diff --git a/gns3server/modules/iou/__init__.py b/gns3server/modules/iou/__init__.py index 3cdddfe7..7b80107a 100644 --- a/gns3server/modules/iou/__init__.py +++ b/gns3server/modules/iou/__init__.py @@ -49,9 +49,10 @@ class IOU(BaseManager): def close_vm(self, vm_id, *args, **kwargs): vm = self.get_vm(vm_id) - i = self._used_application_ids[vm_id] - self._free_application_ids.insert(0, i) - del self._used_application_ids[vm_id] + if vm_id in self._used_application_ids: + i = self._used_application_ids[vm_id] + self._free_application_ids.insert(0, i) + del self._used_application_ids[vm_id] yield from super().close_vm(vm_id, *args, **kwargs) return vm diff --git a/gns3server/modules/iou/iou_vm.py b/gns3server/modules/iou/iou_vm.py index 236c553f..c45126ad 100644 --- a/gns3server/modules/iou/iou_vm.py +++ b/gns3server/modules/iou/iou_vm.py @@ -590,6 +590,7 @@ class IOUVM(BaseVM): self._ioucon_thread = None self._terminate_process_iou() + if self._iou_process.returncode is None: try: yield from gns3server.utils.asyncio.wait_for_process_termination(self._iou_process, timeout=3) diff --git a/tests/modules/iou/test_iou_vm.py b/tests/modules/iou/test_iou_vm.py index 42ddba80..9159f00b 100644 --- a/tests/modules/iou/test_iou_vm.py +++ b/tests/modules/iou/test_iou_vm.py @@ -24,7 +24,7 @@ import socket from tests.utils import asyncio_patch -from unittest.mock import patch, MagicMock +from unittest.mock import patch, MagicMock, PropertyMock from gns3server.modules.iou.iou_vm import IOUVM from gns3server.modules.iou.iou_error import IOUError from gns3server.modules.iou import IOU @@ -97,11 +97,13 @@ def test_vm_invalid_iouyap_path(project, manager, loop): def test_start(loop, vm, monkeypatch): + mock_process = MagicMock() with patch("gns3server.modules.iou.iou_vm.IOUVM._check_requirements", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._check_iou_licence", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_ioucon", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_iouyap", return_value=True): - with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): + with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process): + mock_process.returncode = None loop.run_until_complete(asyncio.async(vm.start())) assert vm.is_running() @@ -111,13 +113,14 @@ def test_start_with_iourc(loop, vm, monkeypatch, tmpdir): fake_file = str(tmpdir / "iourc") with open(fake_file, "w+") as f: f.write("1") - + mock_process = MagicMock() with patch("gns3server.config.Config.get_section_config", return_value={"iourc_path": fake_file, "iouyap_path": vm.iouyap_path}): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._check_requirements", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._check_iou_licence", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_ioucon", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_iouyap", return_value=True): - with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as exec_mock: + with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as exec_mock: + mock_process.returncode = None loop.run_until_complete(asyncio.async(vm.start())) assert vm.is_running() arsgs, kwargs = exec_mock.call_args @@ -152,11 +155,13 @@ def test_stop(loop, vm): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_ioucon", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_iouyap", return_value=True): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): - loop.run_until_complete(asyncio.async(vm.start())) - assert vm.is_running() - loop.run_until_complete(asyncio.async(vm.stop())) - assert vm.is_running() is False - process.terminate.assert_called_with() + with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"): + loop.run_until_complete(asyncio.async(vm.start())) + process.returncode = None + assert vm.is_running() + loop.run_until_complete(asyncio.async(vm.stop())) + assert vm.is_running() is False + process.terminate.assert_called_with() def test_reload(loop, vm, fake_iou_bin): @@ -166,16 +171,18 @@ def test_reload(loop, vm, fake_iou_bin): future = asyncio.Future() future.set_result(True) process.wait.return_value = future + process.returncode = None with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._check_requirements", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_ioucon", return_value=True): with asyncio_patch("gns3server.modules.iou.iou_vm.IOUVM._start_iouyap", return_value=True): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): - loop.run_until_complete(asyncio.async(vm.start())) - assert vm.is_running() - loop.run_until_complete(asyncio.async(vm.reload())) - assert vm.is_running() is True - process.terminate.assert_called_with() + with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"): + loop.run_until_complete(asyncio.async(vm.start())) + assert vm.is_running() + loop.run_until_complete(asyncio.async(vm.reload())) + assert vm.is_running() is True + process.terminate.assert_called_with() def test_close(vm, port_manager, loop): @@ -239,7 +246,7 @@ def test_build_command_initial_config(vm, loop): with open(filepath, "w+") as f: f.write("service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption") - assert loop.run_until_complete(asyncio.async(vm._build_command())) == [vm.path, "-L", "-c", vm.initial_config_file, str(vm.application_id)] + assert loop.run_until_complete(asyncio.async(vm._build_command())) == [vm.path, "-L", "-c", os.path.basename(vm.initial_config_file), str(vm.application_id)] def test_get_initial_config(vm): diff --git a/tests/modules/vpcs/test_vpcs_vm.py b/tests/modules/vpcs/test_vpcs_vm.py index 6b539a89..693da5f8 100644 --- a/tests/modules/vpcs/test_vpcs_vm.py +++ b/tests/modules/vpcs/test_vpcs_vm.py @@ -69,8 +69,11 @@ def test_vm_invalid_vpcs_path(project, manager, loop): def test_start(loop, vm): + process = MagicMock() + process.returncode = None + with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True): - with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): + with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) vm.port_add_nio_binding(0, nio) loop.run_until_complete(asyncio.async(vm.start())) @@ -84,13 +87,16 @@ def test_stop(loop, vm): future = asyncio.Future() future.set_result(True) process.wait.return_value = future + process.returncode = None with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): nio = VPCS.instance().create_nio(vm.vpcs_path, {"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) vm.port_add_nio_binding(0, nio) + loop.run_until_complete(asyncio.async(vm.start())) assert vm.is_running() + loop.run_until_complete(asyncio.async(vm.stop())) assert vm.is_running() is False process.terminate.assert_called_with() @@ -103,6 +109,7 @@ def test_reload(loop, vm): future = asyncio.Future() future.set_result(True) process.wait.return_value = future + process.returncode = None with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True): with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):