| 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Simple functional tests for VNC functionality |
| 4 | # |
| 5 | # Copyright (c) 2018 Red Hat, Inc. |
| 6 | # |
| 7 | # Author: |
| 8 | # Cleber Rosa <crosa@redhat.com> |
| 9 | # |
| 10 | # This work is licensed under the terms of the GNU GPL, version 2 or |
| 11 | # later. See the COPYING file in the top-level directory. |
| 12 | |
| 13 | import socket |
| 14 | |
| 15 | from qemu.machine.machine import VMLaunchFailure |
| 16 | from qemu_test import QemuSystemTest |
| 17 | from qemu_test.ports import Ports |
| 18 | |
| 19 | |
| 20 | VNC_ADDR = '127.0.0.1' |
| 21 | |
| 22 | def check_connect(port: int) -> bool: |
| 23 | with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: |
| 24 | try: |
| 25 | sock.connect((VNC_ADDR, port)) |
| 26 | except ConnectionRefusedError: |
| 27 | return False |
| 28 | |
| 29 | return True |
| 30 | |
| 31 | class Vnc(QemuSystemTest): |
| 32 | |
| 33 | def test_no_vnc_change_password(self): |
| 34 | self.set_machine('none') |
| 35 | self.vm.add_args('-nodefaults', '-S') |
| 36 | self.vm.launch() |
| 37 | |
| 38 | query_vnc_response = self.vm.qmp('query-vnc') |
| 39 | if 'error' in query_vnc_response: |
| 40 | self.assertEqual(query_vnc_response['error']['class'], |
| 41 | 'CommandNotFound') |
| 42 | self.skipTest('VNC support not available') |
| 43 | self.assertFalse(query_vnc_response['return']['enabled']) |
| 44 | |
| 45 | set_password_response = self.vm.qmp('change-vnc-password', |
| 46 | password='new_password') |
| 47 | self.assertIn('error', set_password_response) |
| 48 | self.assertEqual(set_password_response['error']['class'], |
| 49 | 'GenericError') |
| 50 | self.assertEqual(set_password_response['error']['desc'], |
| 51 | 'No VNC display is present'); |
| 52 | |
| 53 | def launch_guarded(self): |
| 54 | try: |
| 55 | self.vm.launch() |
| 56 | except VMLaunchFailure as excp: |
| 57 | if "-vnc: invalid option" in excp.output: |
| 58 | self.skipTest("VNC support not available") |
| 59 | elif "Cipher backend does not support DES algorithm" in excp.output: |
| 60 | self.skipTest("No cryptographic backend available") |
| 61 | else: |
| 62 | self.log.info("unhandled launch failure: %s", excp.output) |
| 63 | raise excp |
| 64 | |
| 65 | def test_change_password_requires_a_password(self): |
| 66 | self.set_machine('none') |
| 67 | self.vm.add_args('-nodefaults', '-S', '-vnc', ':1,to=999') |
| 68 | self.launch_guarded() |
| 69 | self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) |
| 70 | set_password_response = self.vm.qmp('change-vnc-password', |
| 71 | password='new_password') |
| 72 | self.assertIn('error', set_password_response) |
| 73 | self.assertEqual(set_password_response['error']['class'], |
| 74 | 'GenericError') |
| 75 | self.assertEqual(set_password_response['error']['desc'], |
| 76 | 'VNC password authentication is disabled') |
| 77 | |
| 78 | def test_change_password(self): |
| 79 | self.set_machine('none') |
| 80 | self.vm.add_args('-nodefaults', '-S', '-vnc', ':1,to=999,password=on') |
| 81 | self.launch_guarded() |
| 82 | self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) |
| 83 | self.vm.cmd('change-vnc-password', |
| 84 | password='new_password') |
| 85 | |
| 86 | def do_test_change_listen(self, a, b, c): |
| 87 | self.assertFalse(check_connect(a)) |
| 88 | self.assertFalse(check_connect(b)) |
| 89 | self.assertFalse(check_connect(c)) |
| 90 | |
| 91 | self.vm.add_args('-nodefaults', '-S', '-vnc', f'{VNC_ADDR}:{a - 5900}') |
| 92 | self.launch_guarded() |
| 93 | self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(a)) |
| 94 | self.assertTrue(check_connect(a)) |
| 95 | self.assertFalse(check_connect(b)) |
| 96 | self.assertFalse(check_connect(c)) |
| 97 | |
| 98 | self.vm.cmd('display-update', type='vnc', |
| 99 | addresses=[{'type': 'inet', 'host': VNC_ADDR, |
| 100 | 'port': str(b)}, |
| 101 | {'type': 'inet', 'host': VNC_ADDR, |
| 102 | 'port': str(c)}]) |
| 103 | self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(b)) |
| 104 | self.assertFalse(check_connect(a)) |
| 105 | self.assertTrue(check_connect(b)) |
| 106 | self.assertTrue(check_connect(c)) |
| 107 | |
| 108 | def test_change_listen(self): |
| 109 | self.set_machine('none') |
| 110 | with Ports() as ports: |
| 111 | a, b, c = ports.find_free_ports(3) |
| 112 | self.do_test_change_listen(a, b, c) |
| 113 | |
| 114 | |
| 115 | if __name__ == '__main__': |
| 116 | QemuSystemTest.main() |