diff --git a/.travis.yml b/.travis.yml index a8a4eb75..c6870778 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: python python: + - '3.4' - '3.5' + - '3.6' sudo: false cache: pip install: diff --git a/dev-requirements.txt b/dev-requirements.txt index 4cfcf60e..54339617 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1,6 @@ -rrequirements.txt -sphinx==1.5.2 +sphinx==1.5.3 pytest==3.0.6 pep8==1.7.0 pytest-catchlog==1.2.2 diff --git a/gns3server/compute/dynamips/nodes/ethernet_switch.py b/gns3server/compute/dynamips/nodes/ethernet_switch.py index 037a837e..52d7c4ab 100644 --- a/gns3server/compute/dynamips/nodes/ethernet_switch.py +++ b/gns3server/compute/dynamips/nodes/ethernet_switch.py @@ -211,7 +211,8 @@ class EthernetSwitch(Device): nio = self._nios[port_number] if isinstance(nio, NIOUDP): self.manager.port_manager.release_udp_port(nio.lport, self._project) - yield from self._hypervisor.send('ethsw remove_nio "{name}" {nio}'.format(name=self._name, nio=nio)) + if self._hypervisor: + yield from self._hypervisor.send('ethsw remove_nio "{name}" {nio}'.format(name=self._name, nio=nio)) log.info('Ethernet switch "{name}" [{id}]: NIO {nio} removed from port {port}'.format(name=self._name, id=self._id, diff --git a/gns3server/compute/dynamips/nodes/router.py b/gns3server/compute/dynamips/nodes/router.py index 33c01655..4f230d6a 100644 --- a/gns3server/compute/dynamips/nodes/router.py +++ b/gns3server/compute/dynamips/nodes/router.py @@ -24,6 +24,7 @@ import asyncio import time import sys import os +import re import glob import shlex import base64 @@ -1474,7 +1475,7 @@ class Router(BaseNode): try: with open(startup_config_path, "r+", encoding="utf-8", errors="replace") as f: old_config = f.read() - new_config = old_config.replace(self.name, new_name) + new_config = re.sub(r"^hostname .+$", "hostname " + new_name, old_config, flags=re.MULTILINE) f.seek(0) f.write(new_config) except OSError as e: diff --git a/gns3server/compute/iou/iou_vm.py b/gns3server/compute/iou/iou_vm.py index bed1b715..200c0b20 100644 --- a/gns3server/compute/iou/iou_vm.py +++ b/gns3server/compute/iou/iou_vm.py @@ -301,7 +301,7 @@ class IOUVM(BaseNode): if self.startup_config_file: content = self.startup_config_content - content = content.replace(self._name, new_name) + content = re.sub(r"^hostname .+$", "hostname " + new_name, content, flags=re.MULTILINE) self.startup_config_content = content super(IOUVM, IOUVM).name.__set__(self, new_name) @@ -1161,7 +1161,7 @@ class IOUVM(BaseNode): bay=adapter_number, unit=port_number, output_file=output_file, - data_link_type=data_link_type)) + data_link_type=re.sub("^DLT_", "", data_link_type))) @asyncio.coroutine def stop_capture(self, adapter_number, port_number): diff --git a/gns3server/compute/virtualbox/virtualbox_vm.py b/gns3server/compute/virtualbox/virtualbox_vm.py index e1d520dc..77466ec9 100644 --- a/gns3server/compute/virtualbox/virtualbox_vm.py +++ b/gns3server/compute/virtualbox/virtualbox_vm.py @@ -303,6 +303,16 @@ class VirtualBoxVM(BaseNode): if self.acpi_shutdown: # use ACPI to shutdown the VM result = yield from self._control_vm("acpipowerbutton") + trial = 0 + while True: + vm_state = yield from self._get_vm_state() + if vm_state == "poweroff": + break + yield from asyncio.sleep(1) + trial += 1 + if trial >= 120: + yield from self._control_vm("poweroff") + break self.status = "stopped" log.debug("ACPI shutdown result: {}".format(result)) else: diff --git a/gns3server/compute/vpcs/vpcs_vm.py b/gns3server/compute/vpcs/vpcs_vm.py index 97439c7b..7765af74 100644 --- a/gns3server/compute/vpcs/vpcs_vm.py +++ b/gns3server/compute/vpcs/vpcs_vm.py @@ -104,7 +104,7 @@ class VPCSVM(BaseNode): Check if VPCS is available with the correct version. """ - path = self.vpcs_path + path = self._vpcs_path() if not path: raise VPCSError("No path to a VPCS executable has been set") @@ -144,8 +144,7 @@ class VPCSVM(BaseNode): else: return None - @property - def vpcs_path(self): + def _vpcs_path(self): """ Returns the VPCS executable path. @@ -170,6 +169,7 @@ class VPCSVM(BaseNode): if self.script_file: content = self.startup_script content = content.replace(self._name, new_name) + content = re.sub(r"^set pcname .+$", "set pcname " + new_name, content, flags=re.MULTILINE) self.startup_script = content super(VPCSVM, VPCSVM).name.__set__(self, new_name) @@ -215,7 +215,7 @@ class VPCSVM(BaseNode): Checks if the VPCS executable version is >= 0.8b or == 0.6.1. """ try: - output = yield from subprocess_check_output(self.vpcs_path, "-v", cwd=self.working_dir) + output = yield from subprocess_check_output(self._vpcs_path(), "-v", cwd=self.working_dir) match = re.search("Welcome to Virtual PC Simulator, version ([0-9a-z\.]+)", output) if match: version = match.group(1) @@ -223,7 +223,7 @@ class VPCSVM(BaseNode): if self._vpcs_version < parse_version("0.6.1"): raise VPCSError("VPCS executable version must be >= 0.6.1 but not a 0.8") else: - raise VPCSError("Could not determine the VPCS version for {}".format(self.vpcs_path)) + raise VPCSError("Could not determine the VPCS version for {}".format(self._vpcs_path())) except (OSError, subprocess.SubprocessError) as e: raise VPCSError("Error while looking for the VPCS version: {}".format(e)) @@ -268,8 +268,8 @@ class VPCSVM(BaseNode): self.status = "started" except (OSError, subprocess.SubprocessError) as e: vpcs_stdout = self.read_vpcs_stdout() - log.error("Could not start VPCS {}: {}\n{}".format(self.vpcs_path, e, vpcs_stdout)) - raise VPCSError("Could not start VPCS {}: {}\n{}".format(self.vpcs_path, e, vpcs_stdout)) + log.error("Could not start VPCS {}: {}\n{}".format(self._vpcs_path(), e, vpcs_stdout)) + raise VPCSError("Could not start VPCS {}: {}\n{}".format(self._vpcs_path(), e, vpcs_stdout)) def _termination_callback(self, returncode): """ @@ -512,7 +512,7 @@ class VPCSVM(BaseNode): """ - command = [self.vpcs_path] + command = [self._vpcs_path()] command.extend(["-p", str(self._internal_console_port)]) # listen to console port command.extend(["-m", str(self._manager.get_mac_id(self.id))]) # the unique ID is used to set the MAC address offset command.extend(["-i", "1"]) # option to start only one VPC instance diff --git a/gns3server/controller/__init__.py b/gns3server/controller/__init__.py index b6f40303..3368e73e 100644 --- a/gns3server/controller/__init__.py +++ b/gns3server/controller/__init__.py @@ -55,16 +55,21 @@ class Controller: def start(self): log.info("Start controller") self.load_base_files() - yield from self.load() server_config = Config.instance().get_section_config("Server") host = server_config.get("host", "localhost") + # If console_host is 0.0.0.0 client will use the ip they use # to connect to the controller console_host = host if host == "0.0.0.0": host = "127.0.0.1" + + name = socket.gethostname() + if name == "gns3vm": + name = "Main server" + yield from self.add_compute(compute_id="local", - name=socket.gethostname(), + name=name, protocol=server_config.get("protocol", "http"), host=host, console_host=console_host, @@ -72,6 +77,7 @@ class Controller: user=server_config.get("user", ""), password=server_config.get("password", ""), force=True) + yield from self._load_controller_settings() yield from self.load_projects() yield from self.gns3vm.auto_start_vm() yield from self._project_auto_open() @@ -118,7 +124,7 @@ class Controller: json.dump(data, f, indent=4) @asyncio.coroutine - def load(self): + def _load_controller_settings(self): """ Reload the controller configuration from disk """ @@ -279,7 +285,7 @@ class Controller: return None for compute in self._computes.values(): - if name and compute.name == name: + if name and compute.name == name and not force: raise aiohttp.web.HTTPConflict(text='Compute name "{}" already exists'.format(name)) compute = Compute(compute_id=compute_id, controller=self, name=name, **kwargs) diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index 413abba6..85f10575 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -426,7 +426,7 @@ class Compute: except aiohttp.errors.WSServerHandshakeError: self._ws = None break - if response.tp == aiohttp.MsgType.closed or response.tp == aiohttp.MsgType.error: + if response.tp == aiohttp.MsgType.closed or response.tp == aiohttp.MsgType.error or response.data is None: self._connected = False break msg = json.loads(response.data) diff --git a/gns3server/controller/drawing.py b/gns3server/controller/drawing.py index 078d67b0..39a4d158 100644 --- a/gns3server/controller/drawing.py +++ b/gns3server/controller/drawing.py @@ -43,6 +43,7 @@ class Drawing: self._id = str(uuid.uuid4()) else: self._id = drawing_id + self._svg = "" self.svg = svg self._x = x self._y = y diff --git a/gns3server/controller/export_project.py b/gns3server/controller/export_project.py index 25c167e2..1cc93a12 100644 --- a/gns3server/controller/export_project.py +++ b/gns3server/controller/export_project.py @@ -47,6 +47,9 @@ def export_project(project, temporary_dir, include_images=False, keep_compute_id if project.is_running(): raise aiohttp.web.HTTPConflict(text="Running topology could not be exported") + # Make sure we save the project + project.dump() + z = zipstream.ZipFile(allowZip64=True) if not os.path.exists(project._path): diff --git a/gns3server/controller/gns3vm/__init__.py b/gns3server/controller/gns3vm/__init__.py index dec8a8c3..73a759fb 100644 --- a/gns3server/controller/gns3vm/__init__.py +++ b/gns3server/controller/gns3vm/__init__.py @@ -222,8 +222,14 @@ class GNS3VM: """ engine = self._get_engine(engine) vms = [] - for vm in (yield from engine.list()): - vms.append({"vmname": vm["vmname"]}) + try: + for vm in (yield from engine.list()): + vms.append({"vmname": vm["vmname"]}) + except GNS3VMError as e: + # We raise error only if user activated the GNS3 VM + # otherwise you have noise when VMware is not installed + if self.enable: + raise e return vms @asyncio.coroutine @@ -267,6 +273,7 @@ class GNS3VM: engine.vmname = self._settings["vmname"] engine.ram = self._settings["ram"] engine.vpcus = self._settings["vcpus"] + engine.headless = self._settings["headless"] compute = yield from self._controller.add_compute(compute_id="vm", name="GNS3 VM is starting ({})".format(engine.vmname), host=None, @@ -277,6 +284,7 @@ class GNS3VM: except Exception as e: yield from self._controller.delete_compute("vm") log.error("Can't start the GNS3 VM: {}", str(e)) + yield from compute.update(name="GNS3 VM ({})".format(engine.vmname)) raise e yield from compute.update(name="GNS3 VM ({})".format(engine.vmname), protocol=self.protocol, diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index c6788034..07dcb72d 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -221,7 +221,7 @@ class VirtualBoxGNS3VM(BaseGNS3VM): second to a GNS3 endpoint in order to get the list of the interfaces and their IP and after that match it with VirtualBox host only. """ - remaining_try = 240 + remaining_try = 300 while remaining_try > 0: json_data = None session = aiohttp.ClientSession() diff --git a/gns3server/controller/ports/port_factory.py b/gns3server/controller/ports/port_factory.py index e0174564..bc4d509b 100644 --- a/gns3server/controller/ports/port_factory.py +++ b/gns3server/controller/ports/port_factory.py @@ -15,6 +15,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import aiohttp + from .atm_port import ATMPort from .frame_relay_port import FrameRelayPort from .gigabitethernet_port import GigabitEthernetPort @@ -64,11 +66,14 @@ class StandardPortFactory: port_name = first_port_name port = PortFactory(port_name, segment_number, adapter_number, port_number, "ethernet") else: - port_name = port_name_format.format( - interface_number, - segment_number, - adapter=adapter_number, - **cls._generate_replacement(interface_number, segment_number)) + try: + port_name = port_name_format.format( + interface_number, + segment_number, + adapter=adapter_number, + **cls._generate_replacement(interface_number, segment_number)) + except (ValueError, KeyError) as e: + raise aiohttp.web.HTTPConflict(text="Invalid port name format {}: {}".format(port_name_format, str(e))) port = PortFactory(port_name, segment_number, adapter_number, port_number, "ethernet") interface_number += 1 if port_segment_size: diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index 5bf23744..da884f31 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -293,6 +293,8 @@ class Project: name = base_name.format(number, id=number, name="Node") except KeyError as e: raise aiohttp.web.HTTPConflict(text="{" + e.args[0] + "} is not a valid replacement string in the node name") + except ValueError as e: + raise aiohttp.web.HTTPConflict(text="{} is not a valid replacement string in the node name".format(base_name)) if name not in self._allocated_node_names: self._allocated_node_names.add(name) return name diff --git a/gns3server/controller/symbols.py b/gns3server/controller/symbols.py index 389f3ac0..5c473d8b 100644 --- a/gns3server/controller/symbols.py +++ b/gns3server/controller/symbols.py @@ -39,16 +39,17 @@ class Symbols: def list(self): self._symbols_path = {} symbols = [] - for file in os.listdir(get_resource("symbols")): - if file.startswith('.'): - continue - symbol_id = ':/symbols/' + file - symbols.append({ - 'symbol_id': symbol_id, - 'filename': file, - 'builtin': True, - }) - self._symbols_path[symbol_id] = os.path.join(get_resource("symbols"), file) + if get_resource("symbols"): + for file in os.listdir(get_resource("symbols")): + if file.startswith('.'): + continue + symbol_id = ':/symbols/' + file + symbols.append({ + 'symbol_id': symbol_id, + 'filename': file, + 'builtin': True, + }) + self._symbols_path[symbol_id] = os.path.join(get_resource("symbols"), file) directory = self.symbols_path() if directory: for file in os.listdir(directory): diff --git a/gns3server/controller/topology.py b/gns3server/controller/topology.py index e7ba73a0..875aaa52 100644 --- a/gns3server/controller/topology.py +++ b/gns3server/controller/topology.py @@ -363,6 +363,14 @@ def _convert_1_3_later(topo, topo_path): node["symbol"] = ":/symbols/vbox_guest.svg" elif old_node["type"] == "IOUDevice": node["node_type"] = "iou" + node["port_name_format"] = old_node.get("port_name_format", "Ethernet{segment0}/{port0}") + node["port_segment_size"] = int(old_node.get("port_segment_size", "4")) + if node["symbol"] is None: + if "l2" in node["properties"].get("path", ""): + node["symbol"] = ":/symbols/multilayer_switch.svg" + else: + node["symbol"] = ":/symbols/router.svg" + elif old_node["type"] == "Cloud": old_node["ports"] = _create_cloud(node, old_node, ":/symbols/cloud.svg") elif old_node["type"] == "Host": diff --git a/gns3server/crash_report.py b/gns3server/crash_report.py index 7edc2865..7302207b 100644 --- a/gns3server/crash_report.py +++ b/gns3server/crash_report.py @@ -18,6 +18,7 @@ import os import sys import struct +import aiohttp import platform @@ -94,6 +95,7 @@ class CrashReport: "os:win_32": " ".join(platform.win32_ver()), "os:mac": "{} {}".format(platform.mac_ver()[0], platform.mac_ver()[2]), "os:linux": " ".join(platform.linux_distribution()), + "aiohttp:version": aiohttp.__version__, "python:version": "{}.{}.{}".format(sys.version_info[0], sys.version_info[1], sys.version_info[2]), diff --git a/gns3server/utils/picture.py b/gns3server/utils/picture.py index 4424ad9a..0fd740d8 100644 --- a/gns3server/utils/picture.py +++ b/gns3server/utils/picture.py @@ -120,7 +120,8 @@ def _svg_convert_size(size): "pc": 15, "mm": 3.543307, "cm": 35.43307, - "in": 90 + "in": 90, + "px": 1 } if len(size) > 3: if size[-2:] in conversion_table: diff --git a/gns3server/version.py b/gns3server/version.py index b72f512a..68fe29f4 100644 --- a/gns3server/version.py +++ b/gns3server/version.py @@ -32,7 +32,7 @@ if "dev" in __version__: import os import subprocess if os.path.exists(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".git")): - r = subprocess.run(["git", "rev-parse", "--short", "HEAD"], stdout=subprocess.PIPE).stdout.decode().strip("\n") + r = subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).decode().strip("\n") __version__ += "-" + r except Exception as e: print(e) diff --git a/gns3server/web/response.py b/gns3server/web/response.py index c057c6a9..65d85d53 100644 --- a/gns3server/web/response.py +++ b/gns3server/web/response.py @@ -39,6 +39,7 @@ class Response(aiohttp.web.Response): self._route = route self._output_schema = output_schema self._request = request + headers['Connection'] = "close" # Disable keep alive because create trouble with old Qt (5.2, 5.3 and 5.4) headers['X-Route'] = self._route headers['Server'] = "Python/{0[0]}.{0[1]} GNS3/{1}".format(sys.version_info, __version__) super().__init__(headers=headers, **kwargs) diff --git a/requirements.txt b/requirements.txt index 222e4b5a..c5400455 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ jsonschema>=2.4.0 -aiohttp==1.2.0 +aiohttp>=1.3.0,<=1.4.0 aiohttp_cors>=0.4.0 -yarl>=0.9.6 +yarl>=0.9.8 typing>=3.5.3.0 # Otherwise yarl fail with python 3.4 Jinja2>=2.7.3 raven>=5.23.0 diff --git a/tests/compute/iou/test_iou_vm.py b/tests/compute/iou/test_iou_vm.py index 3f00875e..83e65041 100644 --- a/tests/compute/iou/test_iou_vm.py +++ b/tests/compute/iou/test_iou_vm.py @@ -298,6 +298,14 @@ def test_change_name(vm, tmpdir): assert vm.name == "hello" with open(path) as f: assert f.read() == "hostname hello" + # support hostname not sync + vm.name = "alpha" + with open(path, 'w+') as f: + f.write("no service password-encryption\nhostname beta\nno ip icmp rate-limit unreachable") + vm.name = "charlie" + assert vm.name == "charlie" + with open(path) as f: + assert f.read() == "no service password-encryption\nhostname charlie\nno ip icmp rate-limit unreachable" def test_library_check(loop, vm): diff --git a/tests/compute/vpcs/test_vpcs_vm.py b/tests/compute/vpcs/test_vpcs_vm.py index 6eedbd93..b36ac1c9 100644 --- a/tests/compute/vpcs/test_vpcs_vm.py +++ b/tests/compute/vpcs/test_vpcs_vm.py @@ -75,7 +75,7 @@ def test_vm_invalid_vpcs_version(loop, manager, vm): def test_vm_invalid_vpcs_path(vm, manager, loop): - with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.vpcs_path", return_value="/tmp/fake/path/vpcs"): + with patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._vpcs_path", return_value="/tmp/fake/path/vpcs"): with pytest.raises(VPCSError): nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) vm.port_add_nio_binding(0, nio) @@ -97,7 +97,7 @@ def test_start(loop, vm, async_run): nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) async_run(vm.port_add_nio_binding(0, nio)) loop.run_until_complete(asyncio.async(vm.start())) - assert mock_exec.call_args[0] == (vm.vpcs_path, + assert mock_exec.call_args[0] == (vm._vpcs_path(), '-p', str(vm._internal_console_port), '-m', '1', @@ -133,7 +133,7 @@ def test_start_0_6_1(loop, vm, async_run): nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) async_run(vm.port_add_nio_binding(0, nio)) async_run(vm.start()) - assert mock_exec.call_args[0] == (vm.vpcs_path, + assert mock_exec.call_args[0] == (vm._vpcs_path(), '-p', str(vm._internal_console_port), '-m', '1', @@ -243,12 +243,12 @@ def test_update_startup_script(vm): def test_update_startup_script_h(vm): - content = "setname %h\n" + content = "set pcname %h\n" vm.name = "pc1" vm.startup_script = content assert os.path.exists(vm.script_file) with open(vm.script_file) as f: - assert f.read() == "setname pc1\n" + assert f.read() == "set pcname pc1\n" def test_get_startup_script(vm): @@ -275,11 +275,18 @@ def test_change_name(vm, tmpdir): path = os.path.join(vm.working_dir, 'startup.vpc') vm.name = "world" with open(path, 'w+') as f: - f.write("name world") + f.write("set pcname world") vm.name = "hello" assert vm.name == "hello" with open(path) as f: - assert f.read() == "name hello" + assert f.read() == "set pcname hello" + # Support when the name is not sync with config + with open(path, 'w+') as f: + f.write("set pcname alpha") + vm.name = "beta" + assert vm.name == "beta" + with open(path) as f: + assert f.read() == "set pcname beta" def test_close(vm, port_manager, loop): diff --git a/tests/controller/test_controller.py b/tests/controller/test_controller.py index 34a98741..d630aa27 100644 --- a/tests/controller/test_controller.py +++ b/tests/controller/test_controller.py @@ -42,7 +42,7 @@ def test_save(controller, controller_config_path): assert data["gns3vm"] == controller.gns3vm.__json__() -def test_load(controller, controller_config_path, async_run): +def test_load_controller_settings(controller, controller_config_path, async_run): controller.save() with open(controller_config_path) as f: data = json.load(f) @@ -60,7 +60,7 @@ def test_load(controller, controller_config_path, async_run): data["gns3vm"] = {"vmname": "Test VM"} with open(controller_config_path, "w+") as f: json.dump(data, f) - async_run(controller.load()) + async_run(controller._load_controller_settings()) assert controller.settings["IOU"] assert controller.computes["test1"].__json__() == { "compute_id": "test1", @@ -104,7 +104,7 @@ def test_import_computes_1_x(controller, controller_config_path, async_run): with open(os.path.join(config_dir, "gns3_gui.conf"), "w+") as f: json.dump(gns3_gui_conf, f) - async_run(controller.load()) + async_run(controller._load_controller_settings()) for compute in controller.computes.values(): if compute.id != "local": assert len(compute.id) == 36 @@ -146,7 +146,7 @@ def test_import_gns3vm_1_x(controller, controller_config_path, async_run): json.dump(gns3_gui_conf, f) controller.gns3vm.settings["engine"] = None - async_run(controller.load()) + async_run(controller._load_controller_settings()) assert controller.gns3vm.settings["engine"] == "vmware" assert controller.gns3vm.settings["enable"] assert controller.gns3vm.settings["headless"] @@ -202,7 +202,7 @@ def test_import_remote_gns3vm_1_x(controller, controller_config_path, async_run) json.dump(gns3_gui_conf, f) with asyncio_patch("gns3server.controller.compute.Compute.connect"): - async_run(controller.load()) + async_run(controller._load_controller_settings()) assert controller.gns3vm.settings["engine"] == "remote" assert controller.gns3vm.settings["vmname"] == "http://127.0.0.1:3081" diff --git a/tests/controller/test_export_project.py b/tests/controller/test_export_project.py index 2b6b6610..f48df7c8 100644 --- a/tests/controller/test_export_project.py +++ b/tests/controller/test_export_project.py @@ -33,7 +33,9 @@ from gns3server.controller.export_project import export_project, _filter_files @pytest.fixture def project(controller): - return Project(controller=controller, name="Test") + p = Project(controller=controller, name="Test") + p.dump = MagicMock() + return p @pytest.fixture diff --git a/tests/resources/firefox.svg b/tests/resources/firefox.svg new file mode 100644 index 00000000..2d3178f9 --- /dev/null +++ b/tests/resources/firefox.svg @@ -0,0 +1,420 @@ + + + + diff --git a/tests/topologies/1_5_iou/after/1_5_iou.gns3 b/tests/topologies/1_5_iou/after/1_5_iou.gns3 index ba57da26..cc417d25 100644 --- a/tests/topologies/1_5_iou/after/1_5_iou.gns3 +++ b/tests/topologies/1_5_iou/after/1_5_iou.gns3 @@ -30,8 +30,8 @@ "name": "IOU1", "node_id": "aaeb2288-a7d8-42a9-b9d8-c42ab464a390", "node_type": "iou", - "port_name_format": "Ethernet{0}", - "port_segment_size": 0, + "port_name_format": "Ethernet{segment0}/{port0}", + "port_segment_size": 4, "first_port_name": null, "properties": { "ethernet_adapters": 2, diff --git a/tests/utils/test_picture.py b/tests/utils/test_picture.py index d2764c40..a592d500 100644 --- a/tests/utils/test_picture.py +++ b/tests/utils/test_picture.py @@ -39,3 +39,7 @@ def test_get_size(): with open("gns3server/symbols/cloud.svg", "rb") as f: res = get_size(f.read()) assert res == (159, 71, "svg") + # Size with px + with open("tests/resources/firefox.svg", "rb") as f: + res = get_size(f.read()) + assert res == (66, 70, "svg")