# Copyright 2015 Cloudbase Solutions Srl # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import mock from nova import exception from hyperv.nova import constants from hyperv.nova import ioutils from hyperv.nova import namedpipe from hyperv.nova import serialconsolehandler from hyperv.nova import serialproxy from hyperv.nova import utilsfactory from hyperv.tests.unit import test_base class SerialConsoleHandlerTestCase(test_base.HyperVBaseTestCase): @mock.patch.object(utilsfactory, 'get_pathutils') def setUp(self, mock_get_pathutils): super(SerialConsoleHandlerTestCase, self).setUp() self._consolehandler = serialconsolehandler.SerialConsoleHandler( mock.sentinel.instance_name) self._consolehandler._log_path = mock.sentinel.log_path self._consolehandler._pathutils = mock.Mock() self._consolehandler._vmutils = mock.Mock() @mock.patch.object(serialconsolehandler.SerialConsoleHandler, '_setup_handlers') def test_start_handler(self, mock_setup_handlers): mock_workers = [mock.Mock(), mock.Mock()] self._consolehandler._workers = mock_workers self._consolehandler.start() mock_setup_handlers.assert_called_once_with() for worker in mock_workers: worker.start.assert_called_once_with() @mock.patch('nova.console.serial.release_port') def test_stop_handler(self, mock_release_port): mock_serial_proxy = mock.Mock() mock_workers = [mock_serial_proxy, mock.Mock()] self._consolehandler._serial_proxy = mock_serial_proxy self._consolehandler._listen_host = mock.sentinel.host self._consolehandler._listen_port = mock.sentinel.port self._consolehandler._workers = mock_workers self._consolehandler.stop() mock_release_port.assert_called_once_with(mock.sentinel.host, mock.sentinel.port) for worker in mock_workers: worker.stop.assert_called_once_with() @mock.patch.object(serialconsolehandler.SerialConsoleHandler, '_setup_named_pipe_handlers') @mock.patch.object(serialconsolehandler.SerialConsoleHandler, '_setup_serial_proxy_handler') def _test_setup_handlers(self, mock_setup_proxy, mock_setup_pipe_handlers, serial_console_enabled=True): self.flags(enabled=serial_console_enabled, group='serial_console') self._consolehandler._setup_handlers() self.assertEqual(serial_console_enabled, mock_setup_proxy.called) mock_setup_pipe_handlers.assert_called_once_with() def test_setup_handlers(self): self._test_setup_handlers() def test_setup_handlers_console_disabled(self): self._test_setup_handlers(serial_console_enabled=False) @mock.patch.object(serialproxy, 'SerialProxy') @mock.patch('nova.console.serial.acquire_port') @mock.patch.object(serialconsolehandler.threading, 'Event') @mock.patch.object(ioutils, 'IOQueue') def test_setup_serial_proxy_handler(self, mock_io_queue, mock_event, mock_acquire_port, mock_serial_proxy_class): mock_input_queue = mock.sentinel.input_queue mock_output_queue = mock.sentinel.output_queue mock_client_connected = mock_event.return_value mock_io_queue.side_effect = [mock_input_queue, mock_output_queue] mock_serial_proxy = mock_serial_proxy_class.return_value mock_acquire_port.return_value = mock.sentinel.port self.flags(proxyclient_address=mock.sentinel.host, group='serial_console') self._consolehandler._setup_serial_proxy_handler() mock_serial_proxy_class.assert_called_once_with( mock.sentinel.instance_name, mock.sentinel.host, mock.sentinel.port, mock_input_queue, mock_output_queue, mock_client_connected) self.assertIn(mock_serial_proxy, self._consolehandler._workers) @mock.patch.object(serialconsolehandler.SerialConsoleHandler, '_get_named_pipe_handler') @mock.patch.object(serialconsolehandler.SerialConsoleHandler, '_get_vm_serial_port_mapping') def _mock_setup_named_pipe_handlers(self, mock_get_port_mapping, mock_get_pipe_handler, serial_port_mapping=None): mock_get_port_mapping.return_value = serial_port_mapping self._consolehandler._setup_named_pipe_handlers() expected_workers = [mock_get_pipe_handler.return_value for port in serial_port_mapping] self.assertEqual(expected_workers, self._consolehandler._workers) return mock_get_pipe_handler def test_setup_ro_pipe_handler(self): serial_port_mapping = { constants.SERIAL_PORT_TYPE_RW: mock.sentinel.pipe_path } mock_get_handler = self._mock_setup_named_pipe_handlers( serial_port_mapping=serial_port_mapping) mock_get_handler.assert_called_once_with( mock.sentinel.pipe_path, pipe_type=constants.SERIAL_PORT_TYPE_RW, enable_logging=True) def test_setup_pipe_handlers(self): serial_port_mapping = { constants.SERIAL_PORT_TYPE_RO: mock.sentinel.ro_pipe_path, constants.SERIAL_PORT_TYPE_RW: mock.sentinel.rw_pipe_path } mock_get_handler = self._mock_setup_named_pipe_handlers( serial_port_mapping=serial_port_mapping) expected_calls = [mock.call(mock.sentinel.ro_pipe_path, pipe_type=constants.SERIAL_PORT_TYPE_RO, enable_logging=True), mock.call(mock.sentinel.rw_pipe_path, pipe_type=constants.SERIAL_PORT_TYPE_RW, enable_logging=False)] mock_get_handler.assert_has_calls(expected_calls, any_order=True) @mock.patch.object(namedpipe, 'NamedPipeHandler') def _test_get_named_pipe_handler(self, mock_pipe_handler_class, pipe_type=None, enable_logging=False): expected_args = {} if pipe_type == constants.SERIAL_PORT_TYPE_RW: self._consolehandler._input_queue = mock.sentinel.input_queue self._consolehandler._output_queue = mock.sentinel.output_queue self._consolehandler._client_connected = ( mock.sentinel.connect_event) expected_args.update({ 'input_queue': mock.sentinel.input_queue, 'output_queue': mock.sentinel.output_queue, 'connect_event': mock.sentinel.connect_event}) if enable_logging: expected_args['log_file'] = mock.sentinel.log_path ret_val = self._consolehandler._get_named_pipe_handler( mock.sentinel.pipe_path, pipe_type, enable_logging) self.assertEqual(mock_pipe_handler_class.return_value, ret_val) mock_pipe_handler_class.assert_called_once_with( mock.sentinel.pipe_path, **expected_args) def test_get_ro_named_pipe_handler(self): self._test_get_named_pipe_handler( pipe_type=constants.SERIAL_PORT_TYPE_RO, enable_logging=True) def test_get_rw_named_pipe_handler(self): self._test_get_named_pipe_handler( pipe_type=constants.SERIAL_PORT_TYPE_RW, enable_logging=False) def _mock_get_port_connections(self, port_connections): get_port_connections = ( self._consolehandler._vmutils.get_vm_serial_port_connections) get_port_connections.return_value = port_connections def test_get_vm_serial_port_mapping_having_tagged_pipes(self): ro_pipe_path = 'fake_pipe_ro' rw_pipe_path = 'fake_pipe_rw' self._mock_get_port_connections([ro_pipe_path, rw_pipe_path]) ret_val = self._consolehandler._get_vm_serial_port_mapping() expected_mapping = { constants.SERIAL_PORT_TYPE_RO: ro_pipe_path, constants.SERIAL_PORT_TYPE_RW: rw_pipe_path } self.assertEqual(expected_mapping, ret_val) def test_get_vm_serial_port_mapping_untagged_pipe(self): pipe_path = 'fake_pipe_path' self._mock_get_port_connections([pipe_path]) ret_val = self._consolehandler._get_vm_serial_port_mapping() expected_mapping = {constants.SERIAL_PORT_TYPE_RW: pipe_path} self.assertEqual(expected_mapping, ret_val) def test_get_vm_serial_port_mapping_exception(self): self._mock_get_port_connections([]) self.assertRaises(exception.NovaException, self._consolehandler._get_vm_serial_port_mapping) @mock.patch('nova.console.type.ConsoleSerial') def _test_get_serial_console(self, mock_serial_console, console_enabled=True): self.flags(enabled=console_enabled, group='serial_console') if console_enabled: self._consolehandler._listen_host = mock.sentinel.host self._consolehandler._listen_port = mock.sentinel.port ret_val = self._consolehandler.get_serial_console() self.assertEqual(mock_serial_console.return_value, ret_val) mock_serial_console.assert_called_once_with( host=mock.sentinel.host, port=mock.sentinel.port) else: self.assertRaises(exception.ConsoleTypeUnavailable, self._consolehandler.get_serial_console) def test_get_serial_console(self): self._test_get_serial_console() def test_get_serial_console_disabled(self): self._test_get_serial_console(console_enabled=False)