1
0
mirror of https://github.com/GNS3/gns3-server synced 2025-04-19 17:19:00 +00:00

Refactor tests

* Use pytest-aiohttp
* Use the async def / await syntax.
* Fix tests to run with Python 3.8
This commit is contained in:
grossmj 2020-06-16 13:59:03 +09:30
parent f498ab06b4
commit d3ea67da24
87 changed files with 3697 additions and 3528 deletions

View File

@ -1,6 +1,7 @@
-rrequirements.txt
sphinx==1.8.3
pytest==4.4.1
pytest==5.4.3
pep8==1.7.1
pytest-timeout==1.3.3
pytest-aiohttp==0.3.0

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -26,17 +26,20 @@ from tests.utils import asyncio_patch
@pytest.fixture
def nio():
return NIOUDP(4242, "127.0.0.1", 4343)
@pytest.fixture
def manager():
m = MagicMock()
m.module_name = "builtins"
return m
def test_json_with_ports(on_gns3vm, project, manager):
async def test_json_with_ports(on_gns3vm, compute_project, manager):
ports = [
{
"interface": "virbr0",
@ -45,11 +48,11 @@ def test_json_with_ports(on_gns3vm, project, manager):
"type": "ethernet",
}
]
cloud = Cloud("cloud1", str(uuid.uuid4()), project, manager, ports=ports)
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, manager, ports=ports)
assert cloud.__json__() == {
"name": "cloud1",
"node_id": cloud.id,
"project_id": project.id,
"project_id": compute_project.id,
"remote_console_host": "",
"remote_console_http_path": "/",
"remote_console_port": 23,
@ -72,15 +75,16 @@ def test_json_with_ports(on_gns3vm, project, manager):
}
def test_json_without_ports(on_gns3vm, project, manager):
def test_json_without_ports(on_gns3vm, compute_project, manager):
"""
If no interface is provide the cloud is prefill with non special interfaces
If no interface is provide the cloud is pre-fill with non special interfaces
"""
cloud = Cloud("cloud1", str(uuid.uuid4()), project, manager, ports=None)
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, manager, ports=None)
assert cloud.__json__() == {
"name": "cloud1",
"node_id": cloud.id,
"project_id": project.id,
"project_id": compute_project.id,
"remote_console_host": "",
"remote_console_http_path": "/",
"remote_console_port": 23,
@ -109,10 +113,11 @@ def test_json_without_ports(on_gns3vm, project, manager):
}
def test_update_port_mappings(on_gns3vm, project):
async def test_update_port_mappings(on_gns3vm, compute_project):
"""
We don't allow an empty interface in the middle of port list
"""
ports1 = [
{
"interface": "eth0",
@ -127,7 +132,7 @@ def test_update_port_mappings(on_gns3vm, project):
"type": "ethernet"
}
]
cloud = Cloud("cloud1", str(uuid.uuid4()), project, MagicMock(), ports=ports1)
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports1)
assert cloud.ports_mapping == ports1
ports2 = [
@ -144,11 +149,11 @@ def test_update_port_mappings(on_gns3vm, project):
"type": "ethernet"
}
]
cloud = Cloud("cloud2", str(uuid.uuid4()), project, MagicMock(), ports=ports2)
cloud = Cloud("cloud2", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports2)
assert cloud.ports_mapping == ports1
def test_linux_ethernet_raw_add_nio(linux_platform, project, async_run, nio):
async def test_linux_ethernet_raw_add_nio(linux_platform, compute_project, nio):
ports = [
{
"interface": "eth0",
@ -157,14 +162,14 @@ def test_linux_ethernet_raw_add_nio(linux_platform, project, async_run, nio):
"type": "ethernet"
}
]
cloud = Cloud("cloud1", str(uuid.uuid4()), project, MagicMock(), ports=ports)
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports)
cloud.status = "started"
with patch("shutil.which", return_value="/bin/ubridge"):
with patch("gns3server.compute.base_manager.BaseManager.has_privileged_access", return_value=True):
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._ubridge_send") as ubridge_mock:
with patch("gns3server.compute.builtin.nodes.cloud.Cloud._interfaces", return_value=[{"name": "eth0"}]):
async_run(cloud.add_nio(nio, 0))
await cloud.add_nio(nio, 0)
ubridge_mock.assert_has_calls([
call("bridge create {}-0".format(cloud._id)),
@ -175,7 +180,7 @@ def test_linux_ethernet_raw_add_nio(linux_platform, project, async_run, nio):
])
def test_linux_ethernet_raw_add_nio_bridge(linux_platform, project, async_run, nio):
async def test_linux_ethernet_raw_add_nio_bridge(linux_platform, compute_project, nio):
"""
Bridge can't be connected directly to a cloud we use a tap in the middle
"""
@ -187,7 +192,7 @@ def test_linux_ethernet_raw_add_nio_bridge(linux_platform, project, async_run, n
"type": "ethernet"
}
]
cloud = Cloud("cloud1", str(uuid.uuid4()), project, MagicMock(), ports=ports)
cloud = Cloud("cloud1", str(uuid.uuid4()), compute_project, MagicMock(), ports=ports)
cloud.status = "started"
with patch("shutil.which", return_value="/bin/ubridge"):
@ -195,7 +200,7 @@ def test_linux_ethernet_raw_add_nio_bridge(linux_platform, project, async_run, n
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._ubridge_send") as ubridge_mock:
with patch("gns3server.compute.builtin.nodes.cloud.Cloud._interfaces", return_value=[{"name": "bridge0"}]):
with patch("gns3server.utils.interfaces.is_interface_bridge", return_value=True):
async_run(cloud.add_nio(nio, 0))
await cloud.add_nio(nio, 0)
tap = "gns3tap0-0"
ubridge_mock.assert_has_calls([

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,18 +16,18 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import uuid
import pytest
from unittest.mock import MagicMock, patch
from gns3server.compute.builtin.nodes.nat import Nat
def test_json_gns3vm(on_gns3vm, project):
nat = Nat("nat1", str(uuid.uuid4()), project, MagicMock())
def test_json_gns3vm(on_gns3vm, compute_project):
nat = Nat("nat1", str(uuid.uuid4()), compute_project, MagicMock())
assert nat.__json__() == {
"name": "nat1",
"node_id": nat.id,
"project_id": project.id,
"project_id": compute_project.id,
"status": "started",
"ports_mapping": [
{
@ -40,15 +40,16 @@ def test_json_gns3vm(on_gns3vm, project):
}
def test_json_darwin(darwin_platform, project):
def test_json_darwin(darwin_platform, compute_project):
with patch("gns3server.utils.interfaces.interfaces", return_value=[
{"name": "eth0", "special": False, "type": "ethernet"},
{"name": "vmnet8", "special": True, "type": "ethernet"}]):
nat = Nat("nat1", str(uuid.uuid4()), project, MagicMock())
nat = Nat("nat1", str(uuid.uuid4()), compute_project, MagicMock())
assert nat.__json__() == {
"name": "nat1",
"node_id": nat.id,
"project_id": project.id,
"project_id": compute_project.id,
"status": "started",
"ports_mapping": [
{
@ -78,4 +79,4 @@ def test_json_windows_with_full_name_of_interface(windows_platform, project):
"type": "ethernet"
}
]
}
}

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,7 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import asyncio
from unittest.mock import MagicMock, patch
from tests.utils import asyncio_patch, AsyncioMagicMock
@ -25,7 +24,8 @@ from gns3server.compute.docker.docker_error import DockerError, DockerHttp404Err
@pytest.fixture
def vm():
async def vm(loop):
vm = Docker()
vm._connected = True
vm._session = MagicMock()
@ -33,7 +33,7 @@ def vm():
return vm
def test_query_success(loop, vm):
async def test_query_success(vm):
response = MagicMock()
response.status = 200
@ -44,7 +44,7 @@ def test_query_success(loop, vm):
response.read.side_effect = read
vm._session.request = AsyncioMagicMock(return_value=response)
data = loop.run_until_complete(asyncio.ensure_future(vm.query("POST", "test", data={"a": True}, params={"b": 1})))
data = await vm.query("POST", "test", data={"a": True}, params={"b": 1})
vm._session.request.assert_called_with('POST',
'http://docker/v1.25/test',
data='{"a": true}',
@ -55,7 +55,7 @@ def test_query_success(loop, vm):
assert data == {"c": False}
def test_query_error(loop, vm):
async def test_query_error(vm):
response = MagicMock()
response.status = 404
@ -66,7 +66,7 @@ def test_query_error(loop, vm):
response.read.side_effect = read
vm._session.request = AsyncioMagicMock(return_value=response)
with pytest.raises(DockerError):
data = loop.run_until_complete(asyncio.ensure_future(vm.query("POST", "test", data={"a": True}, params={"b": 1})))
await vm.query("POST", "test", data={"a": True}, params={"b": 1})
vm._session.request.assert_called_with('POST',
'http://docker/v1.25/test',
data='{"a": true}',
@ -75,7 +75,7 @@ def test_query_error(loop, vm):
timeout=300)
def test_query_error_json(loop, vm):
async def test_query_error_json(vm):
response = MagicMock()
response.status = 404
@ -86,7 +86,7 @@ def test_query_error_json(loop, vm):
response.read.side_effect = read
vm._session.request = AsyncioMagicMock(return_value=response)
with pytest.raises(DockerError):
data = loop.run_until_complete(asyncio.ensure_future(vm.query("POST", "test", data={"a": True}, params={"b": 1})))
await vm.query("POST", "test", data={"a": True}, params={"b": 1})
vm._session.request.assert_called_with('POST',
'http://docker/v1.25/test',
data='{"a": true}',
@ -95,7 +95,8 @@ def test_query_error_json(loop, vm):
timeout=300)
def test_list_images(loop):
async def test_list_images():
response = [
{
"RepoTags": [
@ -123,7 +124,7 @@ def test_list_images(loop):
]
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response) as mock:
images = loop.run_until_complete(asyncio.ensure_future(Docker.instance().list_images()))
images = await Docker.instance().list_images()
mock.assert_called_with("GET", "images/json", params={"all": 0})
assert len(images) == 5
assert {"image": "ubuntu:12.04"} in images
@ -133,10 +134,11 @@ def test_list_images(loop):
assert {"image": "ubuntu:quantal"} in images
def test_pull_image(loop):
async def test_pull_image():
class Response:
"""
Simulate a response splitted in multiple packets
Simulate a response split in multiple packets
"""
def __init__(self):
@ -156,11 +158,12 @@ def test_pull_image(loop):
with asyncio_patch("gns3server.compute.docker.Docker.query", side_effect=DockerHttp404Error("404")):
with asyncio_patch("gns3server.compute.docker.Docker.http_query", return_value=mock_query) as mock:
images = loop.run_until_complete(asyncio.ensure_future(Docker.instance().pull_image("ubuntu")))
await Docker.instance().pull_image("ubuntu")
mock.assert_called_with("POST", "images/create", params={"fromImage": "ubuntu"}, timeout=None)
def test_docker_check_connection_docker_minimum_version(vm, loop):
async def test_docker_check_connection_docker_minimum_version(vm):
response = {
'ApiVersion': '1.01',
'Version': '1.12'
@ -170,10 +173,11 @@ def test_docker_check_connection_docker_minimum_version(vm, loop):
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
vm._connected = False
with pytest.raises(DockerError):
loop.run_until_complete(asyncio.ensure_future(vm._check_connection()))
await vm._check_connection()
def test_docker_check_connection_docker_preferred_version_against_newer(vm, loop):
async def test_docker_check_connection_docker_preferred_version_against_newer(vm):
response = {
'ApiVersion': '1.31'
}
@ -181,11 +185,12 @@ def test_docker_check_connection_docker_preferred_version_against_newer(vm, loop
with patch("gns3server.compute.docker.Docker.connector"), \
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
vm._connected = False
loop.run_until_complete(asyncio.ensure_future(vm._check_connection()))
await vm._check_connection()
assert vm._api_version == DOCKER_PREFERRED_API_VERSION
def test_docker_check_connection_docker_preferred_version_against_older(vm, loop):
async def test_docker_check_connection_docker_preferred_version_against_older(vm):
response = {
'ApiVersion': '1.27',
}
@ -193,5 +198,5 @@ def test_docker_check_connection_docker_preferred_version_against_older(vm, loop
with patch("gns3server.compute.docker.Docker.connector"), \
asyncio_patch("gns3server.compute.docker.Docker.query", return_value=response):
vm._connected = False
loop.run_until_complete(asyncio.ensure_future(vm._check_connection()))
assert vm._api_version == DOCKER_MINIMUM_API_VERSION
await vm._check_connection()
assert vm._api_version == DOCKER_MINIMUM_API_VERSION

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -21,7 +21,6 @@ import tempfile
import sys
import uuid
import os
import asyncio
from gns3server.compute.dynamips import Dynamips
from gns3server.compute.dynamips.dynamips_error import DynamipsError
@ -30,13 +29,15 @@ from tests.utils import asyncio_patch, AsyncioMagicMock
@pytest.fixture
def manager(port_manager):
async def manager(loop, port_manager):
m = Dynamips.instance()
m.port_manager = port_manager
return m
def test_vm_invalid_dynamips_path(manager):
with patch("gns3server.config.Config.get_section_config", return_value={"dynamips_path": "/bin/test_fake"}):
with pytest.raises(DynamipsError):
manager.find_dynamips()
@ -51,6 +52,7 @@ def test_vm_non_executable_dynamips_path(manager):
def test_get_dynamips_id(manager):
project_1 = str(uuid.uuid4())
project_2 = str(uuid.uuid4())
project_3 = str(uuid.uuid4())
@ -64,8 +66,8 @@ def test_get_dynamips_id(manager):
def test_take_dynamips_id(manager):
project_1 = str(uuid.uuid4())
project_1 = str(uuid.uuid4())
manager.take_dynamips_id(project_1, 1)
assert manager.get_dynamips_id(project_1) == 2
with pytest.raises(DynamipsError):
@ -73,9 +75,9 @@ def test_take_dynamips_id(manager):
def test_release_dynamips_id(manager):
project_1 = str(uuid.uuid4())
project_2 = str(uuid.uuid4())
manager.take_dynamips_id(project_1, 1)
manager.release_dynamips_id(project_1, 1)
assert manager.get_dynamips_id(project_1) == 1
@ -83,45 +85,43 @@ def test_release_dynamips_id(manager):
manager.release_dynamips_id(project_2, 0)
def test_project_closed(manager, project, async_run):
async def test_project_closed(manager, compute_project):
manager._dynamips_ids[project.id] = set([1, 2, 3])
manager._dynamips_ids[compute_project.id] = set([1, 2, 3])
project_dir = project.module_working_path(manager.module_name.lower())
project_dir = compute_project.module_working_path(manager.module_name.lower())
os.makedirs(project_dir)
open(os.path.join(project_dir, "test.ghost"), "w+").close()
async_run(manager.project_closed(project))
await manager.project_closed(compute_project)
assert not os.path.exists(os.path.join(project_dir, "test.ghost"))
assert project.id not in manager._dynamips_ids
assert compute_project.id not in manager._dynamips_ids
def test_duplicate_node(manager, project, async_run):
async def test_duplicate_node(manager, compute_project):
"""
Duplicate dynamips do nothing it's manage outside the
filesystem
"""
with asyncio_patch('gns3server.compute.dynamips.nodes.c7200.C7200.create'):
source_node = async_run(manager.create_node(
source_node = await manager.create_node(
'R1',
project.id,
compute_project.id,
str(uuid.uuid4()),
platform="c7200"
))
destination_node = async_run(manager.create_node(
)
destination_node = await manager.create_node(
'R2',
project.id,
compute_project.id,
str(uuid.uuid4()),
platform="c7200"
))
)
destination_node._hypervisor = AsyncioMagicMock()
with open(os.path.join(source_node.working_dir, 'c3600_i1_nvram'), 'w+') as f:
f.write("1")
with open(source_node.startup_config_path, 'w+') as f:
f.write('hostname R1\necho TEST')
async_run(manager.duplicate_node(source_node.id, destination_node.id))
await manager.duplicate_node(source_node.id, destination_node.id)
assert not os.path.exists(os.path.join(destination_node.working_dir, 'c3600_i1_nvram'))
with open(destination_node.startup_config_path) as f:
content = f.read()

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -19,9 +19,7 @@ import os
import uuid
import pytest
import asyncio
import configparser
from unittest.mock import patch
from gns3server.compute.dynamips.nodes.router import Router
from gns3server.compute.dynamips.dynamips_error import DynamipsError
from gns3server.compute.dynamips import Dynamips
@ -29,47 +27,51 @@ from gns3server.config import Config
@pytest.fixture
def manager(port_manager):
async def manager(loop, port_manager):
m = Dynamips.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def router(project, manager):
return Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def router(compute_project, manager):
return Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
def test_router(project, manager):
router = Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def test_router(compute_project, manager):
router = Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
assert router.name == "test"
assert router.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_convert_project_before_2_0_0_b3(project, manager):
def test_convert_project_before_2_0_0_b3(compute_project, manager):
node_id = str(uuid.uuid4())
wdir = project.module_working_directory(manager.module_name.lower())
wdir = compute_project.module_working_directory(manager.module_name.lower())
os.makedirs(os.path.join(wdir, node_id))
os.makedirs(os.path.join(wdir, "configs"))
open(os.path.join(wdir, "configs", "i1_startup-config.cfg"), "w+").close()
open(os.path.join(wdir, "configs", "i2_startup-config.cfg"), "w+").close()
open(os.path.join(wdir, "c7200_i1_nvram"), "w+").close()
open(os.path.join(wdir, "c7200_i2_nvram"), "w+").close()
router = Router("test", node_id, project, manager, dynamips_id=1)
router = Router("test", node_id, compute_project, manager, dynamips_id=1)
assert os.path.exists(os.path.join(wdir, node_id, "configs", "i1_startup-config.cfg"))
assert not os.path.exists(os.path.join(wdir, node_id, "configs", "i2_startup-config.cfg"))
assert os.path.exists(os.path.join(wdir, node_id, "c7200_i1_nvram"))
assert not os.path.exists(os.path.join(wdir, node_id, "c7200_i2_nvram"))
def test_router_invalid_dynamips_path(project, manager, loop):
async def test_router_invalid_dynamips_path(compute_project, manager):
config = Config.instance()
config.set("Dynamips", "dynamips_path", "/bin/test_fake")
config.set("Dynamips", "allocate_aux_console_ports", False)
with pytest.raises(DynamipsError):
router = Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0e", project, manager)
loop.run_until_complete(asyncio.ensure_future(router.create()))
router = Router("test", "00010203-0405-0607-0809-0a0b0c0d0e0e", compute_project, manager)
await router.create()
assert router.name == "test"
assert router.id == "00010203-0405-0607-0809-0a0b0c0d0e0e"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2017 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,11 +16,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from tests.utils import AsyncioMagicMock
#from gns3server.compute.dynamips.nodes.ethernet_switch import EthernetSwitchConsole
from gns3server.compute.nios.nio_udp import NIOUDP
def test_mac_command(async_run):
def test_mac_command():
node = AsyncioMagicMock()
node.name = "Test"
node.nios = {}

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,7 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import aiohttp
import asyncio
import os
import stat
@ -24,10 +23,10 @@ import socket
import sys
import uuid
import shutil
from tests.utils import asyncio_patch, AsyncioMagicMock
from unittest.mock import patch, MagicMock, PropertyMock, call
from unittest.mock import patch, MagicMock
pytestmark = pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
@ -36,29 +35,29 @@ if not sys.platform.startswith("win"):
from gns3server.compute.iou.iou_error import IOUError
from gns3server.compute.iou import IOU
from gns3server.config import Config
@pytest.fixture
def manager(port_manager):
async def manager(loop, port_manager):
m = IOU.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def vm(project, manager, tmpdir, fake_iou_bin, iourc_file):
vm = IOUVM("test", str(uuid.uuid4()), project, manager, application_id=1)
async def vm(loop, compute_project, manager, tmpdir, fake_iou_bin, iourc_file):
vm = IOUVM("test", str(uuid.uuid4()), compute_project, manager, application_id=1)
config = manager.config.get_section_config("IOU")
config["iourc_path"] = iourc_file
manager.config.set_section_config("IOU", config)
vm.path = "iou.bin"
return vm
@pytest.fixture
def iourc_file(tmpdir):
path = str(tmpdir / "iourc")
with open(path, "w+") as f:
hostname = socket.gethostname()
@ -77,21 +76,23 @@ def fake_iou_bin(images_dir):
return path
def test_vm(project, manager):
vm = IOUVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def test_vm(compute_project, manager):
vm = IOUVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_vm_startup_config_content(project, manager):
vm = IOUVM("test", "00010203-0405-0607-0808-0a0b0c0d0e0f", project, manager, application_id=1)
def test_vm_startup_config_content(compute_project, manager):
vm = IOUVM("test", "00010203-0405-0607-0808-0a0b0c0d0e0f", compute_project, manager, application_id=1)
vm.startup_config_content = "hostname %h"
assert vm.name == "test"
assert vm.startup_config_content == "hostname test"
assert vm.id == "00010203-0405-0607-0808-0a0b0c0d0e0f"
def test_start(loop, vm):
async def test_start(vm):
mock_process = MagicMock()
vm._check_requirements = AsyncioMagicMock(return_value=True)
@ -101,7 +102,7 @@ def test_start(loop, vm):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as mock_exec:
mock_process.returncode = None
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
assert vm.is_running()
assert vm.command_line == ' '.join(mock_exec.call_args[0])
@ -113,7 +114,7 @@ def test_start(loop, vm):
vm._ubridge_send.assert_any_call("iol_bridge start IOL-BRIDGE-513")
def test_start_with_iourc(loop, vm, tmpdir):
async def test_start_with_iourc(vm, tmpdir):
fake_file = str(tmpdir / "iourc")
with open(fake_file, "w+") as f:
@ -129,13 +130,13 @@ def test_start_with_iourc(loop, vm, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"iourc_path": fake_file}):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=mock_process) as exec_mock:
mock_process.returncode = None
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
assert vm.is_running()
arsgs, kwargs = exec_mock.call_args
assert kwargs["env"]["IOURC"] == fake_file
def test_rename_nvram_file(loop, vm):
async def test_rename_nvram_file(vm):
"""
It should rename the nvram file to the correct name before launching the VM
"""
@ -151,9 +152,9 @@ def test_rename_nvram_file(loop, vm):
assert os.path.exists(os.path.join(vm.working_dir, "vlan.dat-0000{}".format(vm.application_id)))
def test_stop(loop, vm):
process = MagicMock()
async def test_stop(vm):
process = MagicMock()
vm._check_requirements = AsyncioMagicMock(return_value=True)
vm._check_iou_licence = AsyncioMagicMock(return_value=True)
vm._start_ioucon = AsyncioMagicMock(return_value=True)
@ -167,17 +168,17 @@ def test_stop(loop, vm):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
process.returncode = None
assert vm.is_running()
loop.run_until_complete(asyncio.ensure_future(vm.stop()))
await vm.stop()
assert vm.is_running() is False
process.terminate.assert_called_with()
def test_reload(loop, vm, fake_iou_bin):
process = MagicMock()
async def test_reload(vm, fake_iou_bin):
process = MagicMock()
vm._check_requirements = AsyncioMagicMock(return_value=True)
vm._check_iou_licence = AsyncioMagicMock(return_value=True)
vm._start_ioucon = AsyncioMagicMock(return_value=True)
@ -192,33 +193,35 @@ def test_reload(loop, vm, fake_iou_bin):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
assert vm.is_running()
loop.run_until_complete(asyncio.ensure_future(vm.reload()))
await vm.reload()
assert vm.is_running() is True
process.terminate.assert_called_with()
def test_close(vm, port_manager, loop):
async def test_close(vm, port_manager):
vm._start_ubridge = AsyncioMagicMock(return_value=True)
vm._ubridge_send = AsyncioMagicMock()
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
port = vm.console
loop.run_until_complete(asyncio.ensure_future(vm.close()))
await vm.close()
# Raise an exception if the port is not free
port_manager.reserve_tcp_port(port, vm.project)
assert vm.is_running() is False
def test_path(vm, fake_iou_bin, config):
config.set_section_config("Server", {"local": True})
vm.path = fake_iou_bin
assert vm.path == fake_iou_bin
def test_path_relative(vm, fake_iou_bin, tmpdir):
def test_path_relative(vm, fake_iou_bin):
vm.path = "iou.bin"
assert vm.path == fake_iou_bin
@ -249,9 +252,9 @@ def test_create_netmap_config(vm):
assert "513:15/3 1:15/3" in content
def test_build_command(vm, loop):
async def test_build_command(vm):
assert loop.run_until_complete(asyncio.ensure_future(vm._build_command())) == [vm.path, str(vm.application_id)]
assert await vm._build_command() == [vm.path, str(vm.application_id)]
def test_get_startup_config(vm):
@ -262,6 +265,7 @@ def test_get_startup_config(vm):
def test_update_startup_config(vm):
content = "service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
vm.startup_config_content = content
filepath = os.path.join(vm.working_dir, "startup-config.cfg")
@ -271,6 +275,7 @@ def test_update_startup_config(vm):
def test_update_startup_config_empty(vm):
content = "service timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption"
vm.startup_config_content = content
filepath = os.path.join(vm.working_dir, "startup-config.cfg")
@ -283,6 +288,7 @@ def test_update_startup_config_empty(vm):
def test_update_startup_config_content_hostname(vm):
content = "hostname %h\n"
vm.name = "pc1"
vm.startup_config_content = content
@ -290,7 +296,8 @@ def test_update_startup_config_content_hostname(vm):
assert f.read() == "hostname pc1\n"
def test_change_name(vm, tmpdir):
def test_change_name(vm):
path = os.path.join(vm.working_dir, "startup-config.cfg")
vm.name = "world"
with open(path, 'w+') as f:
@ -309,50 +316,48 @@ def test_change_name(vm, tmpdir):
assert f.read() == "no service password-encryption\nhostname charlie\nno ip icmp rate-limit unreachable"
def test_library_check(loop, vm):
async def test_library_check(vm):
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="") as mock:
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value=""):
await vm._library_check()
loop.run_until_complete(asyncio.ensure_future(vm._library_check()))
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="libssl => not found") as mock:
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="libssl => not found"):
with pytest.raises(IOUError):
loop.run_until_complete(asyncio.ensure_future(vm._library_check()))
await vm._library_check()
def test_enable_l1_keepalives(loop, vm):
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-l Enable Layer 1 keepalive messages\n-u <n> UDP port base for distributed networks\n") as mock:
async def test_enable_l1_keepalives(vm):
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-l Enable Layer 1 keepalive messages\n-u <n> UDP port base for distributed networks\n"):
command = ["test"]
loop.run_until_complete(asyncio.ensure_future(vm._enable_l1_keepalives(command)))
await vm._enable_l1_keepalives(command)
assert command == ["test", "-l"]
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-u <n> UDP port base for distributed networks\n") as mock:
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="***************************************************************\n\n-u <n> UDP port base for distributed networks\n"):
command = ["test"]
with pytest.raises(IOUError):
loop.run_until_complete(asyncio.ensure_future(vm._enable_l1_keepalives(command)))
await vm._enable_l1_keepalives(command)
assert command == ["test"]
def test_start_capture(vm, tmpdir, manager, free_console_port, loop):
async def test_start_capture(vm, tmpdir, manager, free_console_port):
output_file = str(tmpdir / "test.pcap")
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, 0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start_capture(0, 0, output_file)))
await vm.adapter_add_nio_binding(0, 0, nio)
await vm.start_capture(0, 0, output_file)
assert vm._adapters[0].get_nio(0).capturing
def test_stop_capture(vm, tmpdir, manager, free_console_port, loop):
async def test_stop_capture(vm, tmpdir, manager, free_console_port):
output_file = str(tmpdir / "test.pcap")
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, 0, nio)))
loop.run_until_complete(vm.start_capture(0, 0, output_file))
await vm.adapter_add_nio_binding(0, 0, nio)
await vm.start_capture(0, 0, output_file)
assert vm._adapters[0].get_nio(0).capturing
loop.run_until_complete(asyncio.ensure_future(vm.stop_capture(0, 0)))
await vm.stop_capture(0, 0)
assert vm._adapters[0].get_nio(0).capturing is False
@ -361,46 +366,45 @@ def test_get_legacy_vm_workdir():
assert IOU.get_legacy_vm_workdir(42, "bla") == "iou/device-42"
def test_invalid_iou_file(loop, vm, iourc_file):
async def test_invalid_iou_file(vm, iourc_file):
hostname = socket.gethostname()
loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence()))
await vm._check_iou_licence()
# Missing ;
with pytest.raises(IOUError):
with open(iourc_file, "w+") as f:
f.write("[license]\n{} = aaaaaaaaaaaaaaaa".format(hostname))
loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence()))
await vm._check_iou_licence()
# Key too short
with pytest.raises(IOUError):
with open(iourc_file, "w+") as f:
f.write("[license]\n{} = aaaaaaaaaaaaaa;".format(hostname))
loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence()))
await vm._check_iou_licence()
# Invalid hostname
with pytest.raises(IOUError):
with open(iourc_file, "w+") as f:
f.write("[license]\nbla = aaaaaaaaaaaaaa;")
loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence()))
await vm._check_iou_licence()
# Missing licence section
with pytest.raises(IOUError):
with open(iourc_file, "w+") as f:
f.write("[licensetest]\n{} = aaaaaaaaaaaaaaaa;")
loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence()))
await vm._check_iou_licence()
# Broken config file
with pytest.raises(IOUError):
with open(iourc_file, "w+") as f:
f.write("[")
loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence()))
await vm._check_iou_licence()
# Missing file
with pytest.raises(IOUError):
os.remove(iourc_file)
loop.run_until_complete(asyncio.ensure_future(vm._check_iou_licence()))
await vm._check_iou_licence()
def test_iourc_content(vm):
@ -437,11 +441,11 @@ def test_extract_configs(vm):
assert len(private_config) == 0
def test_application_id(project, manager):
def test_application_id(compute_project, manager):
"""
Checks if uses local manager to get application_id when not set
"""
vm = IOUVM("test", str(uuid.uuid4()), project, manager, application_id=1)
vm = IOUVM("test", str(uuid.uuid4()), compute_project, manager, application_id=1)
assert vm.application_id == 1
vm.application_id = 3

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -18,7 +18,6 @@
import os
import pytest
import shutil
import asyncio
from gns3server.compute.qemu.utils.qcow2 import Qcow2, Qcow2Error
@ -40,34 +39,39 @@ def qemu_img():
def test_valid_base_file():
qcow2 = Qcow2("tests/resources/empty8G.qcow2")
assert qcow2.version == 3
assert qcow2.backing_file is None
def test_valid_linked_file():
qcow2 = Qcow2("tests/resources/linked.qcow2")
assert qcow2.version == 3
assert qcow2.backing_file == "empty8G.qcow2"
def test_invalid_file():
with pytest.raises(Qcow2Error):
Qcow2("tests/resources/nvram_iou")
def test_invalid_empty_file(tmpdir):
open(str(tmpdir / 'a'), 'w+').close()
with pytest.raises(Qcow2Error):
Qcow2(str(tmpdir / 'a'))
@pytest.mark.skipif(qemu_img() is None, reason="qemu-img is not available")
def test_rebase(tmpdir, loop):
async def test_rebase(loop, tmpdir):
shutil.copy("tests/resources/empty8G.qcow2", str(tmpdir / "empty16G.qcow2"))
shutil.copy("tests/resources/linked.qcow2", str(tmpdir / "linked.qcow2"))
qcow2 = Qcow2(str(tmpdir / "linked.qcow2"))
assert qcow2.version == 3
assert qcow2.backing_file == "empty8G.qcow2"
loop.run_until_complete(asyncio.ensure_future(qcow2.rebase(qemu_img(), str(tmpdir / "empty16G.qcow2"))))
await qcow2.rebase(qemu_img(), str(tmpdir / "empty16G.qcow2"))
assert qcow2.backing_file == str(tmpdir / "empty16G.qcow2")

View File

@ -17,7 +17,6 @@
import os
import stat
import asyncio
import sys
import pytest
import platform
@ -25,6 +24,7 @@ import platform
from gns3server.compute.qemu import Qemu
from gns3server.compute.qemu.qemu_error import QemuError
from tests.utils import asyncio_patch
from unittest.mock import patch, MagicMock
@ -38,18 +38,19 @@ def fake_qemu_img_binary(tmpdir):
return bin_path
def test_get_qemu_version(loop):
async def test_get_qemu_version():
with asyncio_patch("gns3server.compute.qemu.subprocess_check_output", return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard") as mock:
version = loop.run_until_complete(asyncio.ensure_future(Qemu.get_qemu_version("/tmp/qemu-test")))
with asyncio_patch("gns3server.compute.qemu.subprocess_check_output", return_value="QEMU emulator version 2.2.0, Copyright (c) 2003-2008 Fabrice Bellard"):
version = await Qemu.get_qemu_version("/tmp/qemu-test")
if sys.platform.startswith("win"):
assert version == ""
else:
assert version == "2.2.0"
def test_binary_list(loop):
async def test_binary_list(monkeypatch, tmpdir):
monkeypatch.setenv("PATH", str(tmpdir))
files_to_create = ["qemu-system-x86", "qemu-system-x42", "qemu-kvm", "hello", "qemu-system-x86_64-spice"]
for file_to_create in files_to_create:
@ -64,7 +65,7 @@ def test_binary_list(loop):
else:
version = "2.2.0"
qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.binary_list()))
qemus = await Qemu.binary_list()
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} in qemus
@ -72,14 +73,14 @@ def test_binary_list(loop):
assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86_64-spice"), "version": version} not in qemus
qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.binary_list(["x86"])))
qemus = await Qemu.binary_list(["x86"])
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} not in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x42"), "version": version} not in qemus
assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus
qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.binary_list(["x86", "x42"])))
qemus = await Qemu.binary_list(["x86", "x42"])
assert {"path": os.path.join(os.environ["PATH"], "qemu-system-x86"), "version": version} in qemus
assert {"path": os.path.join(os.environ["PATH"], "qemu-kvm"), "version": version} not in qemus
@ -87,8 +88,9 @@ def test_binary_list(loop):
assert {"path": os.path.join(os.environ["PATH"], "hello"), "version": version} not in qemus
def test_img_binary_list(loop):
async def test_img_binary_list(monkeypatch, tmpdir):
monkeypatch.setenv("PATH", str(tmpdir))
files_to_create = ["qemu-img", "qemu-io", "qemu-system-x86", "qemu-system-x42", "qemu-kvm", "hello"]
for file_to_create in files_to_create:
@ -98,7 +100,7 @@ def test_img_binary_list(loop):
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
with asyncio_patch("gns3server.compute.qemu.subprocess_check_output", return_value="qemu-img version 2.2.0, Copyright (c) 2004-2008 Fabrice Bellard") as mock:
qemus = loop.run_until_complete(asyncio.ensure_future(Qemu.img_binary_list()))
qemus = await Qemu.img_binary_list()
version = "2.2.0"
@ -115,7 +117,8 @@ def test_get_legacy_vm_workdir():
assert Qemu.get_legacy_vm_workdir(42, "bla") == os.path.join("qemu", "vm-42")
def test_create_image_abs_path(loop, tmpdir, fake_qemu_img_binary):
async def test_create_image_abs_path(tmpdir, fake_qemu_img_binary):
options = {
"format": "qcow2",
"preallocation": "metadata",
@ -125,7 +128,7 @@ def test_create_image_abs_path(loop, tmpdir, fake_qemu_img_binary):
"size": 100
}
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk(fake_qemu_img_binary, str(tmpdir / "hda.qcow2"), options)))
await Qemu.instance().create_disk(fake_qemu_img_binary, str(tmpdir / "hda.qcow2"), options)
args, kwargs = process.call_args
assert args == (
fake_qemu_img_binary,
@ -145,14 +148,15 @@ def test_create_image_abs_path(loop, tmpdir, fake_qemu_img_binary):
)
def test_create_image_relative_path(loop, tmpdir, fake_qemu_img_binary):
async def test_create_image_relative_path(tmpdir, fake_qemu_img_binary):
options = {
"format": "raw",
"size": 100
}
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
with patch("gns3server.compute.qemu.Qemu.get_images_directory", return_value=str(tmpdir)):
loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options)))
await Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options)
args, kwargs = process.call_args
assert args == (
fake_qemu_img_binary,
@ -164,9 +168,9 @@ def test_create_image_relative_path(loop, tmpdir, fake_qemu_img_binary):
)
def test_create_image_exist(loop, tmpdir, fake_qemu_img_binary):
open(str(tmpdir / "hda.qcow2"), "w+").close()
async def test_create_image_exist(tmpdir, fake_qemu_img_binary):
open(str(tmpdir / "hda.qcow2"), "w+").close()
options = {
"format": "raw",
"size": 100
@ -174,11 +178,12 @@ def test_create_image_exist(loop, tmpdir, fake_qemu_img_binary):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
with patch("gns3server.compute.qemu.Qemu.get_images_directory", return_value=str(tmpdir)):
with pytest.raises(QemuError):
loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options)))
await Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options)
assert not process.called
def test_create_image_with_not_supported_characters_by_filesystem(loop, tmpdir, fake_qemu_img_binary):
async def test_create_image_with_not_supported_characters_by_filesystem(tmpdir, fake_qemu_img_binary):
open(str(tmpdir / "hda.qcow2"), "w+").close()
options = {
@ -193,20 +198,19 @@ def test_create_image_with_not_supported_characters_by_filesystem(loop, tmpdir,
patch("os.makedirs"):
with pytest.raises(QemuError):
loop.run_until_complete(asyncio.ensure_future(Qemu.instance().create_disk(
fake_qemu_img_binary, "hda.qcow2", options)))
await Qemu.instance().create_disk(fake_qemu_img_binary, "hda.qcow2", options)
assert not process.called
def test_get_kvm_archs_kvm_ok(loop):
async def test_get_kvm_archs_kvm_ok():
with patch("os.path.exists", return_value=True):
archs = loop.run_until_complete(asyncio.ensure_future(Qemu.get_kvm_archs()))
archs = await Qemu.get_kvm_archs()
if platform.machine() == 'x86_64':
assert archs == ['x86_64', 'i386']
else:
assert archs == [platform.machine()]
with patch("os.path.exists", return_value=False):
archs = loop.run_until_complete(asyncio.ensure_future(Qemu.get_kvm_archs()))
archs = await Qemu.get_kvm_archs()
assert archs == []

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,12 +16,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import aiohttp
import asyncio
import os
import sys
import stat
import re
from tests.utils import asyncio_patch, AsyncioMagicMock
@ -36,15 +34,17 @@ from gns3server.compute.notification_manager import NotificationManager
@pytest.fixture
def manager(port_manager):
async def manager(loop, port_manager):
m = Qemu.instance()
m.port_manager = port_manager
return m
@pytest.fixture
def fake_qemu_img_binary():
def fake_qemu_img_binary(monkeypatch, tmpdir):
monkeypatch.setenv("PATH", str(tmpdir))
bin_path = os.path.join(os.environ["PATH"], "qemu-img")
with open(bin_path, "w+") as f:
f.write("1")
@ -53,8 +53,9 @@ def fake_qemu_img_binary():
@pytest.fixture
def fake_qemu_binary():
def fake_qemu_binary(monkeypatch, tmpdir):
monkeypatch.setenv("PATH", str(tmpdir))
if sys.platform.startswith("win"):
bin_path = os.path.join(os.environ["PATH"], "qemu-system-x86_64w.exe")
else:
@ -66,9 +67,10 @@ def fake_qemu_binary():
@pytest.fixture(scope="function")
def vm(project, manager, fake_qemu_binary, fake_qemu_img_binary):
async def vm(loop, compute_project, manager, fake_qemu_binary, fake_qemu_img_binary):
manager.port_manager.console_host = "127.0.0.1"
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, qemu_path=fake_qemu_binary)
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path=fake_qemu_binary)
vm._process_priority = "normal" # Avoid complexity for Windows tests
vm._start_ubridge = AsyncioMagicMock()
vm._ubridge_hypervisor = MagicMock()
@ -79,49 +81,52 @@ def vm(project, manager, fake_qemu_binary, fake_qemu_img_binary):
@pytest.fixture(scope="function")
def running_subprocess_mock():
mm = MagicMock()
mm.returncode = None
return mm
def test_vm(project, manager, fake_qemu_binary):
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, qemu_path=fake_qemu_binary)
def test_vm(compute_project, manager, fake_qemu_binary):
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path=fake_qemu_binary)
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_vm_create(loop, tmpdir, project, manager, fake_qemu_binary):
async def test_vm_create(tmpdir, compute_project, manager, fake_qemu_binary):
fake_img = str(tmpdir / 'hello')
with open(fake_img, 'w+') as f:
f.write('hello')
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, qemu_path=fake_qemu_binary)
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path=fake_qemu_binary)
vm._hda_disk_image = fake_img
loop.run_until_complete(asyncio.ensure_future(vm.create()))
await vm.create()
# tests if `create` created md5sums
assert os.path.exists(str(tmpdir / 'hello.md5sum'))
def test_vm_invalid_qemu_with_platform(project, manager, fake_qemu_binary):
def test_vm_invalid_qemu_with_platform(compute_project, manager, fake_qemu_binary):
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, qemu_path="/usr/fake/bin/qemu-system-64", platform="x86_64")
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path="/usr/fake/bin/qemu-system-64", platform="x86_64")
assert vm.qemu_path == fake_qemu_binary
assert vm.platform == "x86_64"
def test_vm_invalid_qemu_without_platform(project, manager, fake_qemu_binary):
def test_vm_invalid_qemu_without_platform(compute_project, manager, fake_qemu_binary):
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, qemu_path="/usr/fake/bin/qemu-system-x86_64")
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, qemu_path="/usr/fake/bin/qemu-system-x86_64")
assert vm.qemu_path == fake_qemu_binary
assert vm.platform == "x86_64"
def test_is_running(vm, running_subprocess_mock):
async def test_is_running(vm, running_subprocess_mock):
vm._process = None
assert vm.is_running() is False
@ -131,18 +136,19 @@ def test_is_running(vm, running_subprocess_mock):
assert vm.is_running() is False
def test_start(loop, vm, running_subprocess_mock):
async def test_start(vm, running_subprocess_mock):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=running_subprocess_mock) as mock:
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
assert vm.is_running()
assert vm.command_line == ' '.join(mock.call_args[0])
def test_stop(loop, vm, running_subprocess_mock):
process = running_subprocess_mock
async def test_stop(vm, running_subprocess_mock):
process = running_subprocess_mock
# Wait process kill success
future = asyncio.Future()
future.set_result(True)
@ -152,31 +158,30 @@ def test_stop(loop, vm, running_subprocess_mock):
with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.adapter_add_nio_binding(0, nio)
await vm.start()
assert vm.is_running()
loop.run_until_complete(asyncio.ensure_future(vm.stop()))
await vm.stop()
assert vm.is_running() is False
process.terminate.assert_called_with()
def test_termination_callback(vm, async_run):
async def test_termination_callback(vm):
vm.status = "started"
with NotificationManager.instance().queue() as queue:
async_run(vm._termination_callback(0))
await vm._termination_callback(0)
assert vm.status == "stopped"
async_run(queue.get(1)) #  Ping
await queue.get(1) #  Ping
(action, event, kwargs) = async_run(queue.get(1))
(action, event, kwargs) = await queue.get(1)
assert action == "node.updated"
assert event == vm
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_termination_callback_error(vm, tmpdir, async_run):
async def test_termination_callback_error(vm, tmpdir):
with open(str(tmpdir / "qemu.log"), "w+") as f:
f.write("BOOMM")
@ -185,10 +190,10 @@ def test_termination_callback_error(vm, tmpdir, async_run):
vm._stdout_file = str(tmpdir / "qemu.log")
with NotificationManager.instance().queue() as queue:
async_run(vm._termination_callback(1))
await vm._termination_callback(1)
assert vm.status == "stopped"
async_run(queue.get(1)) # Ping
await queue.get(1) # Ping
(action, event, kwargs) = queue.get_nowait()
assert action == "node.updated"
@ -199,46 +204,48 @@ def test_termination_callback_error(vm, tmpdir, async_run):
assert event["message"] == "QEMU process has stopped, return code: 1\nBOOMM"
def test_reload(loop, vm):
async def test_reload(vm):
with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm") as mock:
loop.run_until_complete(asyncio.ensure_future(vm.reload()))
await vm.reload()
assert mock.called_with("system_reset")
def test_suspend(loop, vm):
async def test_suspend(vm):
control_vm_result = MagicMock()
control_vm_result.match.group.decode.return_value = "running"
with asyncio_patch("gns3server.compute.qemu.QemuVM._control_vm", return_value=control_vm_result) as mock:
loop.run_until_complete(asyncio.ensure_future(vm.suspend()))
await vm.suspend()
assert mock.called_with("system_reset")
def test_add_nio_binding_udp(vm, loop):
async def test_add_nio_binding_udp(vm):
nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
assert nio.lport == 4242
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio)))
await vm.adapter_add_nio_binding(0, nio)
assert nio.lport == 4242
async def test_port_remove_nio_binding(vm):
def test_port_remove_nio_binding(vm, loop):
nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.adapter_remove_nio_binding(0)))
await vm.adapter_add_nio_binding(0, nio)
await vm.adapter_remove_nio_binding(0)
assert vm._ethernet_adapters[0].ports[0] is None
def test_close(vm, port_manager, loop):
async def test_close(vm, port_manager):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
console_port = vm.console
loop.run_until_complete(asyncio.ensure_future(vm.close()))
await vm.close()
# Raise an exception if the port is not free
port_manager.reserve_tcp_port(console_port, vm.project)
@ -287,7 +294,7 @@ def test_set_qemu_path_environ(vm, tmpdir, fake_qemu_binary):
assert vm.platform == "x86_64"
def test_set_qemu_path_windows(vm, tmpdir):
def test_set_qemu_path_windows(vm):
bin_path = os.path.join(os.environ["PATH"], "qemu-system-x86_64w.EXE")
open(bin_path, "w+").close()
@ -300,7 +307,7 @@ def test_set_qemu_path_windows(vm, tmpdir):
assert vm.platform == "x86_64"
def test_set_qemu_path_old_windows(vm, tmpdir):
def test_set_qemu_path_old_windows(vm):
bin_path = os.path.join(os.environ["PATH"], "qemu.exe")
open(bin_path, "w+").close()
@ -314,7 +321,7 @@ def test_set_qemu_path_old_windows(vm, tmpdir):
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_set_qemu_path_kvm_binary(vm, tmpdir, fake_qemu_binary):
def test_set_qemu_path_kvm_binary(vm, fake_qemu_binary):
bin_path = os.path.join(os.environ["PATH"], "qemu-kvm")
with open(bin_path, "w+") as f:
@ -328,11 +335,11 @@ def test_set_qemu_path_kvm_binary(vm, tmpdir, fake_qemu_binary):
assert vm.platform == "x86_64"
def test_set_platform(project, manager):
def test_set_platform(compute_project, manager):
with patch("shutil.which", return_value="/bin/qemu-system-x86_64") as which_mock:
with patch("gns3server.compute.qemu.QemuVM._check_qemu_path"):
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, platform="x86_64")
vm = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, platform="x86_64")
if sys.platform.startswith("win"):
which_mock.assert_called_with("qemu-system-x86_64w.exe", path=mock.ANY)
else:
@ -341,13 +348,13 @@ def test_set_platform(project, manager):
assert vm.qemu_path == "/bin/qemu-system-x86_64"
def test_disk_options(vm, tmpdir, loop, fake_qemu_img_binary):
async def test_disk_options(vm, tmpdir, fake_qemu_img_binary):
vm._hda_disk_image = str(tmpdir / "test.qcow2")
open(vm._hda_disk_image, "w+").close()
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
options = loop.run_until_complete(asyncio.ensure_future(vm._disk_options()))
options = await vm._disk_options()
assert process.called
args, kwargs = process.call_args
assert args == (fake_qemu_img_binary, "create", "-o", "backing_file={}".format(vm._hda_disk_image), "-f", "qcow2", os.path.join(vm.working_dir, "hda_disk.qcow2"))
@ -355,44 +362,44 @@ def test_disk_options(vm, tmpdir, loop, fake_qemu_img_binary):
assert options == ['-drive', 'file=' + os.path.join(vm.working_dir, "hda_disk.qcow2") + ',if=ide,index=0,media=disk,id=drive0']
def test_cdrom_option(vm, tmpdir, loop, fake_qemu_img_binary):
async def test_cdrom_option(vm, tmpdir, fake_qemu_img_binary):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._cdrom_image = str(tmpdir / "test.iso")
open(vm._cdrom_image, "w+").close()
options = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
options = await vm._build_command()
assert ' '.join(['-cdrom', str(tmpdir / "test.iso")]) in ' '.join(options)
def test_bios_option(vm, tmpdir, loop, fake_qemu_img_binary):
async def test_bios_option(vm, tmpdir, fake_qemu_img_binary):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm._bios_image = str(tmpdir / "test.img")
open(vm._bios_image, "w+").close()
options = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
options = await vm._build_command()
assert ' '.join(['-bios', str(tmpdir / "test.img")]) in ' '.join(options)
def test_vnc_option(vm, tmpdir, loop, fake_qemu_img_binary):
async def test_vnc_option(vm, fake_qemu_img_binary):
vm._console_type = 'vnc'
vm._console = 5905
options = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
options = await vm._build_command()
assert '-vnc 127.0.0.1:5' in ' '.join(options)
def test_spice_option(vm, tmpdir, loop, fake_qemu_img_binary):
async def test_spice_option(vm, fake_qemu_img_binary):
vm._console_type = 'spice'
vm._console = 5905
options = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
options = await vm._build_command()
assert '-spice addr=127.0.0.1,port=5905,disable-ticketing' in ' '.join(options)
assert '-vga qxl' in ' '.join(options)
def test_disk_options_multiple_disk(vm, tmpdir, loop, fake_qemu_img_binary):
async def test_disk_options_multiple_disk(vm, tmpdir, fake_qemu_img_binary):
vm._hda_disk_image = str(tmpdir / "test0.qcow2")
vm._hdb_disk_image = str(tmpdir / "test1.qcow2")
@ -403,8 +410,8 @@ def test_disk_options_multiple_disk(vm, tmpdir, loop, fake_qemu_img_binary):
open(vm._hdc_disk_image, "w+").close()
open(vm._hdd_disk_image, "w+").close()
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
options = loop.run_until_complete(asyncio.ensure_future(vm._disk_options()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
options = await vm._disk_options()
assert options == [
'-drive', 'file=' + os.path.join(vm.working_dir, "hda_disk.qcow2") + ',if=ide,index=0,media=disk,id=drive0',
@ -415,70 +422,70 @@ def test_disk_options_multiple_disk(vm, tmpdir, loop, fake_qemu_img_binary):
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_set_process_priority(vm, loop, fake_qemu_img_binary):
async def test_set_process_priority(vm, fake_qemu_img_binary):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
vm._process = MagicMock()
vm._process.pid = 42
vm._process_priority = "low"
loop.run_until_complete(asyncio.ensure_future(vm._set_process_priority()))
await vm._set_process_priority()
assert process.called
args, kwargs = process.call_args
assert args == ("renice", "-n", "5", "-p", "42")
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_set_process_priority_normal(vm, loop, fake_qemu_img_binary):
async def test_set_process_priority_normal(vm, fake_qemu_img_binary):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
vm._process = MagicMock()
vm._process.pid = 42
loop.run_until_complete(asyncio.ensure_future(vm._set_process_priority()))
await vm._set_process_priority()
assert not process.called
def test_json(vm, project):
def test_json(vm, compute_project):
json = vm.__json__()
assert json["name"] == vm.name
assert json["project_id"] == project.id
assert json["project_id"] == compute_project.id
def test_control_vm(vm, loop):
async def test_control_vm(vm):
vm._process = MagicMock()
reader = MagicMock()
writer = MagicMock()
with asyncio_patch("asyncio.open_connection", return_value=(reader, writer)) as open_connect:
res = loop.run_until_complete(asyncio.ensure_future(vm._control_vm("test")))
with asyncio_patch("asyncio.open_connection", return_value=(reader, writer)):
res = await vm._control_vm("test")
assert writer.write.called_with("test")
assert res is None
def test_control_vm_expect_text(vm, loop, running_subprocess_mock):
async def test_control_vm_expect_text(vm, running_subprocess_mock):
vm._process = running_subprocess_mock
reader = MagicMock()
writer = MagicMock()
with asyncio_patch("asyncio.open_connection", return_value=(reader, writer)) as open_connect:
with asyncio_patch("asyncio.open_connection", return_value=(reader, writer)):
future = asyncio.Future()
future.set_result(b"epic product")
reader.readline.return_value = future
vm._monitor = 4242
res = loop.run_until_complete(asyncio.ensure_future(vm._control_vm("test", [b"epic"])))
res = await vm._control_vm("test", [b"epic"])
assert writer.write.called_with("test")
assert res == "epic product"
def test_build_command(vm, loop, fake_qemu_binary, port_manager):
async def test_build_command(vm, fake_qemu_binary):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
nio = vm._local_udp_tunnels[0][0]
assert cmd == [
fake_qemu_binary,
@ -505,7 +512,7 @@ def test_build_command(vm, loop, fake_qemu_binary, port_manager):
]
def test_build_command_manual_uuid(vm, loop, fake_qemu_binary, port_manager):
async def test_build_command_manual_uuid(vm):
"""
If user has set a uuid we keep it
"""
@ -513,13 +520,13 @@ def test_build_command_manual_uuid(vm, loop, fake_qemu_binary, port_manager):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="3.1.0")
vm.options = "-uuid e1c307a4-896f-11e6-81a5-3c07547807cc"
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
assert "e1c307a4-896f-11e6-81a5-3c07547807cc" in cmd
assert vm.id not in cmd
def test_build_command_kvm(linux_platform, vm, loop, fake_qemu_binary, port_manager):
async def test_build_command_kvm(linux_platform, vm, fake_qemu_binary):
"""
Qemu 2.4 introduce an issue with KVM
"""
@ -528,7 +535,7 @@ def test_build_command_kvm(linux_platform, vm, loop, fake_qemu_binary, port_mana
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM._run_with_hardware_acceleration", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
cmd = await vm._build_command()
nio = vm._local_udp_tunnels[0][0]
assert cmd == [
fake_qemu_binary,
@ -555,7 +562,7 @@ def test_build_command_kvm(linux_platform, vm, loop, fake_qemu_binary, port_mana
]
def test_build_command_kvm_2_4(linux_platform, vm, loop, fake_qemu_binary, port_manager):
async def test_build_command_kvm_2_4(linux_platform, vm, fake_qemu_binary):
"""
Qemu 2.4 introduce an issue with KVM
"""
@ -564,7 +571,7 @@ def test_build_command_kvm_2_4(linux_platform, vm, loop, fake_qemu_binary, port_
os.environ["DISPLAY"] = "0:0"
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM._run_with_hardware_acceleration", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
cmd = await vm._build_command()
nio = vm._local_udp_tunnels[0][0]
assert cmd == [
fake_qemu_binary,
@ -594,22 +601,22 @@ def test_build_command_kvm_2_4(linux_platform, vm, loop, fake_qemu_binary, port_
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_build_command_without_display(vm, loop, fake_qemu_binary):
async def test_build_command_without_display(vm):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.5.0")
os.environ["DISPLAY"] = ""
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
assert "-nographic" in cmd
def test_build_command_two_adapters(vm, loop, fake_qemu_binary, port_manager):
async def test_build_command_two_adapters(vm, fake_qemu_binary):
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.5.0")
os.environ["DISPLAY"] = "0:0"
vm.adapters = 2
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
nio1 = vm._local_udp_tunnels[0][0]
nio2 = vm._local_udp_tunnels[1][0]
assert cmd == [
@ -640,7 +647,7 @@ def test_build_command_two_adapters(vm, loop, fake_qemu_binary, port_manager):
]
def test_build_command_two_adapters_mac_address(vm, loop, fake_qemu_binary, port_manager):
async def test_build_command_two_adapters_mac_address(vm):
"""
Should support multiple base vmac address
"""
@ -651,8 +658,8 @@ def test_build_command_two_adapters_mac_address(vm, loop, fake_qemu_binary, port
mac_0 = vm._mac_address
mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)
assert mac_0[:8] == "00:00:ab"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
assert "e1000,mac={},netdev=gns3-0".format(mac_0) in cmd
assert "e1000,mac={},netdev=gns3-1".format(mac_1) in cmd
@ -660,16 +667,17 @@ def test_build_command_two_adapters_mac_address(vm, loop, fake_qemu_binary, port
mac_0 = vm._mac_address
mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)
assert mac_0[:8] == "00:42:ab"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
assert "e1000,mac={},netdev=gns3-0".format(mac_0) in cmd
assert "e1000,mac={},netdev=gns3-1".format(mac_1) in cmd
def test_build_command_large_number_of_adapters(vm, loop, fake_qemu_binary, port_manager):
async def test_build_command_large_number_of_adapters(vm):
"""
When we have more than 28 interface we need to add a pci bridge for
additionnal interfaces
additional interfaces
"""
# It's supported only with Qemu 2.4 and later
@ -680,8 +688,8 @@ def test_build_command_large_number_of_adapters(vm, loop, fake_qemu_binary, port
mac_0 = vm._mac_address
mac_1 = int_to_macaddress(macaddress_to_int(vm._mac_address) + 1)
assert mac_0[:8] == "00:00:ab"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
cmd = await vm._build_command()
# Count if we have 100 e1000 adapters in the command
assert len([l for l in cmd if "e1000" in l ]) == 100
@ -704,21 +712,19 @@ def test_build_command_large_number_of_adapters(vm, loop, fake_qemu_binary, port
# Qemu < 2.4 doesn't support large number of adapters
vm.manager.get_qemu_version = AsyncioMagicMock(return_value="2.0.0")
with pytest.raises(QemuError):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
await vm._build_command()
vm.adapters = 5
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()) as process:
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
# Windows accept this kind of mistake
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
await vm._build_command()
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_build_command_with_invalid_options(vm, loop, fake_qemu_binary):
async def test_build_command_with_invalid_options(vm):
vm.options = "'test"
with pytest.raises(QemuError):
cmd = loop.run_until_complete(asyncio.ensure_future(vm._build_command()))
await vm._build_command()
def test_hda_disk_image(vm, images_dir):
@ -731,7 +737,7 @@ def test_hda_disk_image(vm, images_dir):
assert vm.hda_disk_image == force_unix_path(os.path.join(images_dir, "QEMU", "test2"))
def test_hda_disk_image_non_linked_clone(vm, images_dir, project, manager, fake_qemu_binary, fake_qemu_img_binary):
def test_hda_disk_image_non_linked_clone(vm, images_dir, compute_project, manager, fake_qemu_binary):
"""
Two non linked can't use the same image at the same time
"""
@ -741,7 +747,7 @@ def test_hda_disk_image_non_linked_clone(vm, images_dir, project, manager, fake_
vm.hda_disk_image = os.path.join(images_dir, "test1")
vm.manager._nodes[vm.id] = vm
vm2 = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0eaa", project, manager, qemu_path=fake_qemu_binary)
vm2 = QemuVM("test", "00010203-0405-0607-0809-0a0b0c0d0eaa", compute_project, manager, qemu_path=fake_qemu_binary)
vm2.linked_clone = False
with pytest.raises(QemuError):
vm2.hda_disk_image = os.path.join(images_dir, "test1")
@ -833,58 +839,58 @@ def test_options_windows(windows_platform, vm):
def test_get_qemu_img(vm, tmpdir):
open(str(tmpdir / "qemu-sytem-x86_64"), "w+").close()
open(str(tmpdir / "qemu-system-x86_64"), "w+").close()
open(str(tmpdir / "qemu-img"), "w+").close()
vm._qemu_path = str(tmpdir / "qemu-sytem-x86_64")
vm._qemu_path = str(tmpdir / "qemu-system-x86_64")
assert vm._get_qemu_img() == str(tmpdir / "qemu-img")
def test_get_qemu_img_not_exist(vm, tmpdir):
open(str(tmpdir / "qemu-sytem-x86_64"), "w+").close()
vm._qemu_path = str(tmpdir / "qemu-sytem-x86_64")
with pytest.raises(QemuError):
vm._get_qemu_img()
# def test_get_qemu_img_not_exist(vm, tmpdir):
#
# open(str(tmpdir / "qemu-system-x86_64"), "w+").close()
# vm._qemu_path = str(tmpdir / "qemu-system-x86_64")
# with pytest.raises(QemuError):
# vm._get_qemu_img()
def test_run_with_hardware_acceleration_darwin(darwin_platform, vm, loop):
async def test_run_with_hardware_acceleration_darwin(darwin_platform, vm):
vm.manager.config.set("Qemu", "enable_hardware_acceleration", False)
assert loop.run_until_complete(asyncio.ensure_future(vm._run_with_hardware_acceleration("qemu-system-x86_64", ""))) is False
assert await vm._run_with_hardware_acceleration("qemu-system-x86_64", "") is False
def test_run_with_hardware_acceleration_windows(windows_platform, vm, loop):
async def test_run_with_hardware_acceleration_windows(windows_platform, vm):
vm.manager.config.set("Qemu", "enable_hardware_acceleration", False)
assert loop.run_until_complete(asyncio.ensure_future(vm._run_with_hardware_acceleration("qemu-system-x86_64", ""))) is False
assert await vm._run_with_hardware_acceleration("qemu-system-x86_64", "") is False
def test_run_with_kvm_linux(linux_platform, vm, loop):
async def test_run_with_kvm_linux(linux_platform, vm):
with patch("os.path.exists", return_value=True) as os_path:
vm.manager.config.set("Qemu", "enable_kvm", True)
assert loop.run_until_complete(asyncio.ensure_future(vm._run_with_hardware_acceleration("qemu-system-x86_64", ""))) is True
assert await vm._run_with_hardware_acceleration("qemu-system-x86_64", "") is True
os_path.assert_called_with("/dev/kvm")
def test_run_with_kvm_linux_options_no_kvm(linux_platform, vm, loop):
async def test_run_with_kvm_linux_options_no_kvm(linux_platform, vm):
with patch("os.path.exists", return_value=True) as os_path:
vm.manager.config.set("Qemu", "enable_kvm", True)
assert loop.run_until_complete(asyncio.ensure_future(vm._run_with_hardware_acceleration("qemu-system-x86_64", "-no-kvm"))) is False
assert await vm._run_with_hardware_acceleration("qemu-system-x86_64", "-no-kvm") is False
def test_run_with_kvm_not_x86(linux_platform, vm, loop):
async def test_run_with_kvm_not_x86(linux_platform, vm):
with patch("os.path.exists", return_value=True) as os_path:
with patch("os.path.exists", return_value=True):
vm.manager.config.set("Qemu", "enable_kvm", True)
with pytest.raises(QemuError):
ret = loop.run_until_complete(asyncio.ensure_future(vm._run_with_hardware_acceleration("qemu-system-arm", "")))
await vm._run_with_hardware_acceleration("qemu-system-arm", "")
def test_run_with_kvm_linux_dev_kvm_missing(linux_platform, vm, loop):
async def test_run_with_kvm_linux_dev_kvm_missing(linux_platform, vm):
with patch("os.path.exists", return_value=False) as os_path:
with patch("os.path.exists", return_value=False):
vm.manager.config.set("Qemu", "enable_kvm", True)
with pytest.raises(QemuError):
ret = loop.run_until_complete(asyncio.ensure_future(vm._run_with_hardware_acceleration("qemu-system-x86_64", "")))
await vm._run_with_hardware_acceleration("qemu-system-x86_64", "")

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -14,43 +14,44 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from collections import OrderedDict
import pytest
import aiohttp
import asyncio
import os
from tests.utils import asyncio_patch, AsyncioMagicMock
from unittest.mock import patch, MagicMock
from gns3server.compute.vpcs.vpcs_vm import VPCSVM
from gns3server.compute.docker.docker_vm import DockerVM
from gns3server.compute.vpcs.vpcs_error import VPCSError
from gns3server.compute.error import NodeError
from gns3server.compute.vpcs import VPCS
from gns3server.compute.nios.nio_udp import NIOUDP
@pytest.fixture(scope="function")
def manager(port_manager):
async def manager(loop, port_manager):
m = VPCS.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def node(project, manager):
return VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def node(compute_project, manager):
return VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
def test_temporary_directory(project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def test_temporary_directory(compute_project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
assert isinstance(node.temporary_directory, str)
def test_console(project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def test_console(compute_project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
node.console = 5011
assert node.console == 5011
node.console = None
@ -58,6 +59,7 @@ def test_console(project, manager):
def test_change_console_port(node, port_manager):
port1 = port_manager.get_free_tcp_port(node.project)
port2 = port_manager.get_free_tcp_port(node.project)
port_manager.release_tcp_port(port1, node.project)
@ -68,22 +70,23 @@ def test_change_console_port(node, port_manager):
port_manager.reserve_tcp_port(port1, node.project)
def test_console_vnc_invalid(project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def test_console_vnc_invalid(compute_project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
node._console_type = "vnc"
with pytest.raises(NodeError):
node.console = 2012
def test_close(node, loop, port_manager):
assert node.console is not None
async def test_close(node, port_manager):
assert node.console is not None
aux = port_manager.get_free_tcp_port(node.project)
port_manager.release_tcp_port(aux, node.project)
node.aux = aux
port = node.console
assert loop.run_until_complete(asyncio.ensure_future(node.close()))
assert await node.close()
# Raise an exception if the port is not free
port_manager.reserve_tcp_port(port, node.project)
# Raise an exception if the port is not free
@ -92,29 +95,32 @@ def test_close(node, loop, port_manager):
assert node.aux is None
# Called twice closed should return False
assert loop.run_until_complete(asyncio.ensure_future(node.close())) is False
assert await node.close() is False
def test_aux(project, manager, port_manager):
aux = port_manager.get_free_tcp_port(project)
port_manager.release_tcp_port(aux, project)
def test_aux(compute_project, manager, port_manager):
node = DockerVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "ubuntu", aux=aux)
aux = port_manager.get_free_tcp_port(compute_project)
port_manager.release_tcp_port(aux, compute_project)
node = DockerVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu", aux=aux)
assert node.aux == aux
node.aux = None
assert node.aux is None
def test_allocate_aux(project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def test_allocate_aux(compute_project, manager):
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
assert node.aux is None
# Docker has an aux port by default
node = DockerVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "ubuntu")
node = DockerVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "ubuntu")
assert node.aux is not None
def test_change_aux_port(node, port_manager):
port1 = port_manager.get_free_tcp_port(node.project)
port2 = port_manager.get_free_tcp_port(node.project)
port_manager.release_tcp_port(port1, node.project)
@ -125,7 +131,8 @@ def test_change_aux_port(node, port_manager):
port_manager.reserve_tcp_port(port1, node.project)
def test_update_ubridge_udp_connection(node, async_run):
async def test_update_ubridge_udp_connection(node):
filters = {
"latency": [10]
}
@ -134,27 +141,29 @@ def test_update_ubridge_udp_connection(node, async_run):
dnio = NIOUDP(1245, "localhost", 1244)
dnio.filters = filters
with asyncio_patch("gns3server.compute.base_node.BaseNode._ubridge_apply_filters") as mock:
async_run(node.update_ubridge_udp_connection('VPCS-10', snio, dnio))
await node.update_ubridge_udp_connection('VPCS-10', snio, dnio)
mock.assert_called_with("VPCS-10", filters)
def test_ubridge_apply_filters(node, async_run):
async def test_ubridge_apply_filters(node):
filters = OrderedDict((
('latency', [10]),
('bpf', ["icmp[icmptype] == 8\ntcp src port 53"])
))
node._ubridge_send = AsyncioMagicMock()
async_run(node._ubridge_apply_filters("VPCS-10", filters))
await node._ubridge_apply_filters("VPCS-10", filters)
node._ubridge_send.assert_any_call("bridge reset_packet_filters VPCS-10")
node._ubridge_send.assert_any_call("bridge add_packet_filter VPCS-10 filter0 latency 10")
def test_ubridge_apply_bpf_filters(node, async_run):
async def test_ubridge_apply_bpf_filters(node):
filters = {
"bpf": ["icmp[icmptype] == 8\ntcp src port 53"]
}
node._ubridge_send = AsyncioMagicMock()
async_run(node._ubridge_apply_filters("VPCS-10", filters))
await node._ubridge_apply_filters("VPCS-10", filters)
node._ubridge_send.assert_any_call("bridge reset_packet_filters VPCS-10")
node._ubridge_send.assert_any_call("bridge add_packet_filter VPCS-10 filter0 bpf \"icmp[icmptype] == 8\"")
node._ubridge_send.assert_any_call("bridge add_packet_filter VPCS-10 filter1 bpf \"tcp src port 53\"")

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -19,8 +19,7 @@ import uuid
import os
import pytest
from unittest.mock import patch
from tests.utils import AsyncioMagicMock, asyncio_patch
from tests.utils import asyncio_patch
from gns3server.compute.vpcs import VPCS
from gns3server.compute.dynamips import Dynamips
@ -30,7 +29,8 @@ from gns3server.utils import force_unix_path
@pytest.fixture(scope="function")
def vpcs(port_manager):
async def vpcs(loop, port_manager):
VPCS._instance = None
vpcs = VPCS.instance()
vpcs.port_manager = port_manager
@ -38,49 +38,53 @@ def vpcs(port_manager):
@pytest.fixture(scope="function")
def qemu(port_manager):
async def qemu(loop, port_manager):
Qemu._instance = None
qemu = Qemu.instance()
qemu.port_manager = port_manager
return qemu
def test_create_node_new_topology(loop, project, vpcs):
async def test_create_node_new_topology(compute_project, vpcs):
node_id = str(uuid.uuid4())
node = loop.run_until_complete(vpcs.create_node("PC 1", project.id, node_id))
assert node in project.nodes
node = await vpcs.create_node("PC 1", compute_project.id, node_id)
assert node in compute_project.nodes
def test_create_twice_same_node_new_topology(loop, project, vpcs):
project._nodes = set()
async def test_create_twice_same_node_new_topology(compute_project, vpcs):
compute_project._nodes = set()
node_id = str(uuid.uuid4())
node = loop.run_until_complete(vpcs.create_node("PC 1", project.id, node_id, console=2222))
assert node in project.nodes
assert len(project.nodes) == 1
node = loop.run_until_complete(vpcs.create_node("PC 2", project.id, node_id, console=2222))
assert len(project.nodes) == 1
node = await vpcs.create_node("PC 1", compute_project.id, node_id, console=2222)
assert node in compute_project.nodes
assert len(compute_project.nodes) == 1
await vpcs.create_node("PC 2", compute_project.id, node_id, console=2222)
assert len(compute_project.nodes) == 1
def test_create_node_new_topology_without_uuid(loop, project, vpcs):
node = loop.run_until_complete(vpcs.create_node("PC 1", project.id, None))
assert node in project.nodes
async def test_create_node_new_topology_without_uuid(compute_project, vpcs):
node = await vpcs.create_node("PC 1", compute_project.id, None)
assert node in compute_project.nodes
assert len(node.id) == 36
def test_create_node_old_topology(loop, project, tmpdir, vpcs):
async def test_create_node_old_topology(compute_project, tmpdir, vpcs):
with patch("gns3server.compute.project.Project.is_local", return_value=True):
# Create an old topology directory
project_dir = str(tmpdir / "testold")
node_dir = os.path.join(project_dir, "testold-files", "vpcs", "pc-1")
project.path = project_dir
project.name = "testold"
compute_project.path = project_dir
compute_project.name = "testold"
os.makedirs(node_dir, exist_ok=True)
with open(os.path.join(node_dir, "startup.vpc"), "w+") as f:
f.write("1")
node_id = 1
node = loop.run_until_complete(vpcs.create_node("PC 1", project.id, node_id))
node = await vpcs.create_node("PC 1", compute_project.id, node_id)
assert len(node.id) == 36
assert os.path.exists(os.path.join(project_dir, "testold-files")) is False
@ -91,6 +95,7 @@ def test_create_node_old_topology(loop, project, tmpdir, vpcs):
def test_get_abs_image_path(qemu, tmpdir, config):
os.makedirs(str(tmpdir / "QEMU"))
path1 = force_unix_path(str(tmpdir / "test1.bin"))
open(path1, 'w+').close()
@ -107,6 +112,7 @@ def test_get_abs_image_path(qemu, tmpdir, config):
def test_get_abs_image_path_non_local(qemu, tmpdir, config):
path1 = tmpdir / "images" / "QEMU" / "test1.bin"
path1.write("1", ensure=True)
path1 = force_unix_path(str(path1))
@ -128,6 +134,7 @@ def test_get_abs_image_path_non_local(qemu, tmpdir, config):
def test_get_abs_image_additional_image_paths(qemu, tmpdir, config):
path1 = tmpdir / "images1" / "QEMU" / "test1.bin"
path1.write("1", ensure=True)
path1 = force_unix_path(str(path1))
@ -151,6 +158,7 @@ def test_get_abs_image_additional_image_paths(qemu, tmpdir, config):
def test_get_abs_image_recursive(qemu, tmpdir, config):
path1 = tmpdir / "images1" / "QEMU" / "demo" / "test1.bin"
path1.write("1", ensure=True)
path1 = force_unix_path(str(path1))
@ -169,6 +177,7 @@ def test_get_abs_image_recursive(qemu, tmpdir, config):
def test_get_abs_image_recursive_ova(qemu, tmpdir, config):
path1 = tmpdir / "images1" / "QEMU" / "demo" / "test.ova" / "test1.bin"
path1.write("1", ensure=True)
path1 = force_unix_path(str(path1))
@ -187,6 +196,7 @@ def test_get_abs_image_recursive_ova(qemu, tmpdir, config):
def test_get_relative_image_path(qemu, tmpdir, config):
os.makedirs(str(tmpdir / "images1" / "QEMU"))
os.makedirs(str(tmpdir / "images1" / "VBOX"))
path1 = force_unix_path(str(tmpdir / "images1" / "test1.bin"))
@ -221,7 +231,7 @@ def test_get_relative_image_path(qemu, tmpdir, config):
assert qemu.get_relative_image_path(path5) == path5
def test_list_images(loop, qemu, tmpdir):
async def test_list_images(qemu, tmpdir):
fake_images = ["a.qcow2", "b.qcow2", ".blu.qcow2", "a.qcow2.md5sum"]
tmp_images_dir = os.path.join(tmpdir, "images")
@ -231,13 +241,13 @@ def test_list_images(loop, qemu, tmpdir):
f.write("1")
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmp_images_dir)):
assert sorted(loop.run_until_complete(qemu.list_images()), key=lambda k: k['filename']) == [
assert sorted(await qemu.list_images(), key=lambda k: k['filename']) == [
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}
]
def test_list_images_recursives(loop, qemu, tmpdir):
async def test_list_images_recursives(qemu, tmpdir):
tmp_images_dir = os.path.join(tmpdir, "images")
os.makedirs(tmp_images_dir, exist_ok=True)
@ -253,52 +263,57 @@ def test_list_images_recursives(loop, qemu, tmpdir):
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmp_images_dir)):
assert sorted(loop.run_until_complete(qemu.list_images()), key=lambda k: k['filename']) == [
assert sorted(await qemu.list_images(), key=lambda k: k['filename']) == [
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
{"filename": "c.qcow2", "path": force_unix_path(os.path.sep.join(["c", "c.qcow2"])), "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}
]
def test_list_images_empty(loop, qemu, tmpdir):
async def test_list_images_empty(qemu, tmpdir):
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)):
assert loop.run_until_complete(qemu.list_images()) == []
assert await qemu.list_images() == []
def test_list_images_directory_not_exist(loop, qemu):
async def test_list_images_directory_not_exist(qemu):
with patch("gns3server.compute.Qemu.get_images_directory", return_value="/bla"):
assert loop.run_until_complete(qemu.list_images()) == []
assert await qemu.list_images() == []
def test_delete_node(async_run, vpcs, project):
project._nodes = set()
async def test_delete_node(vpcs, compute_project):
compute_project._nodes = set()
node_id = str(uuid.uuid4())
node = async_run(vpcs.create_node("PC 1", project.id, node_id, console=2222))
assert node in project.nodes
node = await vpcs.create_node("PC 1", compute_project.id, node_id, console=2222)
assert node in compute_project.nodes
with patch("gns3server.compute.project.Project.emit") as mock_emit:
async_run(vpcs.delete_node(node_id))
await vpcs.delete_node(node_id)
mock_emit.assert_called_with("node.deleted", node)
assert node not in project.nodes
assert node not in compute_project.nodes
def test_duplicate_vpcs(async_run, vpcs, project):
async def test_duplicate_vpcs(vpcs, compute_project):
source_node_id = str(uuid.uuid4())
source_node = async_run(vpcs.create_node("PC-1", project.id, source_node_id, console=2222))
source_node = await vpcs.create_node("PC-1", compute_project.id, source_node_id, console=2222)
with open(os.path.join(source_node.working_dir, "startup.vpc"), "w+") as f:
f.write("set pcname PC-1\nip dhcp\n")
destination_node_id = str(uuid.uuid4())
destination_node = async_run(vpcs.create_node("PC-2", project.id, destination_node_id, console=2223))
async_run(vpcs.duplicate_node(source_node_id, destination_node_id))
destination_node = await vpcs.create_node("PC-2", compute_project.id, destination_node_id, console=2223)
await vpcs.duplicate_node(source_node_id, destination_node_id)
with open(os.path.join(destination_node.working_dir, "startup.vpc")) as f:
startup = f.read().strip()
assert startup == "set pcname PC-2\nip dhcp\n".strip()
def test_duplicate_ethernet_switch(async_run, project):
async def test_duplicate_ethernet_switch(compute_project):
with asyncio_patch('gns3server.compute.dynamips.nodes.ethernet_switch.EthernetSwitch.create'):
dynamips_manager = Dynamips.instance()
source_node_id = str(uuid.uuid4())
source_node = async_run(dynamips_manager.create_node("SW-1", project.id, source_node_id, node_type='ethernet_switch'))
await dynamips_manager.create_node("SW-1", compute_project.id, source_node_id, node_type='ethernet_switch')
destination_node_id = str(uuid.uuid4())
destination_node = async_run(dynamips_manager.create_node("SW-2", project.id, destination_node_id, node_type='ethernet_switch'))
async_run(dynamips_manager.duplicate_node(source_node_id, destination_node_id))
await dynamips_manager.create_node("SW-2", compute_project.id, destination_node_id, node_type='ethernet_switch')
await dynamips_manager.duplicate_node(source_node_id, destination_node_id)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -20,69 +20,73 @@ import uuid
from gns3server.compute.notification_manager import NotificationManager
def test_queue(async_run):
async def test_queue():
NotificationManager.reset()
notifications = NotificationManager.instance()
with notifications.queue() as queue:
assert len(notifications._listeners) == 1
res = async_run(queue.get(5))
res = await queue.get(5)
assert res[0] == "ping"
notifications.emit("test", {"a": 1})
res = async_run(queue.get(5))
res = await queue.get(5)
assert res == ('test', {"a": 1}, {})
assert len(notifications._listeners) == 0
def test_queue_json(async_run):
async def test_queue_json():
NotificationManager.reset()
notifications = NotificationManager.instance()
with notifications.queue() as queue:
assert len(notifications._listeners) == 1
res = async_run(queue.get(5))
res = await queue.get(5)
assert "ping" in res
notifications.emit("test", {"a": 1})
res = async_run(queue.get_json(5))
res = await queue.get_json(5)
assert res == '{"action": "test", "event": {"a": 1}}'
assert len(notifications._listeners) == 0
def test_queue_json_meta(async_run):
async def test_queue_json_meta():
NotificationManager.reset()
project_id = str(uuid.uuid4())
notifications = NotificationManager.instance()
with notifications.queue() as queue:
assert len(notifications._listeners) == 1
res = async_run(queue.get(5))
res = await queue.get(5)
assert "ping" in res
notifications.emit("test", {"a": 1}, project_id=project_id)
res = async_run(queue.get_json(5))
res = await queue.get_json(5)
assert res == '{"action": "test", "event": {"a": 1}, "project_id": "' + project_id + '"}'
assert len(notifications._listeners) == 0
def test_queue_ping(async_run):
async def test_queue_ping():
"""
If we don't send a message during a long time (0.5 seconds)
a ping is send
"""
NotificationManager.reset()
notifications = NotificationManager.instance()
with notifications.queue() as queue:
assert len(notifications._listeners) == 1
res = async_run(queue.get(5))
res = await queue.get(5)
assert res[0] == "ping"
res = async_run(queue.get(0.5))
res = await queue.get(0.5)
assert res[0] == "ping"
assert res[1]["cpu_usage_percent"] is not None
assert len(notifications._listeners) == 0

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,7 +17,6 @@
import aiohttp
import pytest
import sys
import uuid
from unittest.mock import patch
@ -26,6 +25,7 @@ from gns3server.compute.project import Project
def test_reserve_tcp_port():
pm = PortManager()
project = Project(project_id=str(uuid.uuid4()))
pm.reserve_tcp_port(2001, project)
@ -35,6 +35,7 @@ def test_reserve_tcp_port():
def test_reserve_tcp_port_outside_range():
pm = PortManager()
project = Project(project_id=str(uuid.uuid4()))
with patch("gns3server.compute.project.Project.emit") as mock_emit:
@ -60,7 +61,7 @@ def test_reserve_tcp_port_already_used_by_another_program():
mock_check.side_effect = execute_mock
with patch("gns3server.compute.project.Project.emit") as mock_emit:
with patch("gns3server.compute.project.Project.emit"):
port = pm.reserve_tcp_port(2001, project)
assert port != 2001
@ -68,7 +69,7 @@ def test_reserve_tcp_port_already_used_by_another_program():
def test_reserve_tcp_port_already_used():
"""
This test simulate a scenario where the port is already taken
by another programm on the server
by another program on the server
"""
pm = PortManager()
@ -83,12 +84,13 @@ def test_reserve_tcp_port_already_used():
mock_check.side_effect = execute_mock
with patch("gns3server.compute.project.Project.emit") as mock_emit:
with patch("gns3server.compute.project.Project.emit"):
port = pm.reserve_tcp_port(2001, project)
assert port != 2001
def test_reserve_udp_port():
pm = PortManager()
project = Project(project_id=str(uuid.uuid4()))
pm.reserve_udp_port(20000, project)
@ -97,6 +99,7 @@ def test_reserve_udp_port():
def test_reserve_udp_port_outside_range():
pm = PortManager()
project = Project(project_id=str(uuid.uuid4()))
with pytest.raises(aiohttp.web.HTTPConflict):
@ -104,6 +107,7 @@ def test_reserve_udp_port_outside_range():
def test_release_udp_port():
pm = PortManager()
project = Project(project_id=str(uuid.uuid4()))
pm.reserve_udp_port(20000, project)
@ -112,11 +116,13 @@ def test_release_udp_port():
def test_find_unused_port():
p = PortManager().find_unused_port(1000, 10000)
assert p is not None
def test_find_unused_port_invalid_range():
with pytest.raises(aiohttp.web.HTTPConflict):
p = PortManager().find_unused_port(10000, 1000)
@ -126,6 +132,7 @@ def test_set_console_host(config):
If allow remote connection we need to bind console host
to 0.0.0.0
"""
p = PortManager()
config.set_section_config("Server", {"allow_remote_console": False})
p.console_host = "10.42.1.42"

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -18,11 +18,9 @@
import os
import uuid
import json
import asyncio
import pytest
import aiohttp
import zipfile
from uuid import uuid4
from unittest.mock import patch
@ -34,24 +32,27 @@ from gns3server.config import Config
@pytest.fixture(scope="function")
def manager(port_manager):
async def manager(loop, port_manager):
m = VPCS.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def node(project, manager, loop):
node = manager.create_node("test", project.id, "00010203-0405-0607-0809-0a0b0c0d0e0f")
return loop.run_until_complete(asyncio.ensure_future(node))
async def node(compute_project, manager):
node = manager.create_node("test", compute_project.id, "00010203-0405-0607-0809-0a0b0c0d0e0f")
return await asyncio.ensure_future(node)
def test_affect_uuid():
async def test_affect_uuid():
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f')
assert p.id == '00010203-0405-0607-0809-0a0b0c0d0e0f'
def test_clean_tmp_directory(async_run):
async def test_clean_tmp_directory():
"""
The tmp directory should be clean at project open and close
"""
@ -59,7 +60,7 @@ def test_clean_tmp_directory(async_run):
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f')
path = p.tmp_working_directory()
os.makedirs(path)
async_run(p.close())
await p.close()
assert not os.path.exists(path)
os.makedirs(path)
@ -67,10 +68,9 @@ def test_clean_tmp_directory(async_run):
assert not os.path.exists(path)
def test_path(tmpdir):
directory = Config.instance().get_section_config("Server").get("projects_path")
async def test_path(projects_dir):
directory = projects_dir
with patch("gns3server.compute.project.Project.is_local", return_value=True):
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
p = Project(project_id=str(uuid4()))
@ -78,27 +78,30 @@ def test_path(tmpdir):
assert os.path.exists(os.path.join(directory, p.id))
def test_init_path(tmpdir):
async def test_init_path(tmpdir):
with patch("gns3server.compute.project.Project.is_local", return_value=True):
p = Project(path=str(tmpdir), project_id=str(uuid4()))
assert p.path == str(tmpdir)
def test_changing_path_not_allowed(tmpdir):
async def test_changing_path_not_allowed(tmpdir):
with patch("gns3server.compute.project.Project.is_local", return_value=False):
with pytest.raises(aiohttp.web.HTTPForbidden):
p = Project(project_id=str(uuid4()))
p.path = str(tmpdir)
def test_variables(tmpdir):
async def test_variables():
variables = [{"name": "VAR1", "value": "VAL1"}]
p = Project(project_id=str(uuid4()), variables=variables)
assert p.variables == variables
def test_json(tmpdir):
async def test_json():
p = Project(project_id=str(uuid4()))
assert p.__json__() == {
"name": p.name,
@ -107,7 +110,8 @@ def test_json(tmpdir):
}
def test_json_with_variables(tmpdir):
async def test_json_with_variables():
variables = [{"name": "VAR1", "value": "VAL1"}]
p = Project(project_id=str(uuid4()), variables=variables)
assert p.__json__() == {
@ -117,18 +121,18 @@ def test_json_with_variables(tmpdir):
}
def test_node_working_directory(tmpdir, node):
directory = Config.instance().get_section_config("Server").get("projects_path")
async def test_node_working_directory(node, projects_dir):
directory = projects_dir
with patch("gns3server.compute.project.Project.is_local", return_value=True):
p = Project(project_id=str(uuid4()))
assert p.node_working_directory(node) == os.path.join(directory, p.id, 'project-files', node.module_name, node.id)
assert os.path.exists(p.node_working_directory(node))
def test_node_working_path(tmpdir, node):
directory = Config.instance().get_section_config("Server").get("projects_path")
async def test_node_working_path(node, projects_dir):
directory = projects_dir
with patch("gns3server.compute.project.Project.is_local", return_value=True):
p = Project(project_id=str(uuid4()))
assert p.node_working_path(node) == os.path.join(directory, p.id, 'project-files', node.module_name, node.id)
@ -136,40 +140,43 @@ def test_node_working_path(tmpdir, node):
assert not os.path.exists(p.node_working_path(node))
def test_project_delete(loop):
async def test_project_delete():
project = Project(project_id=str(uuid4()))
directory = project.path
assert os.path.exists(directory)
loop.run_until_complete(asyncio.ensure_future(project.delete()))
await project.delete()
assert os.path.exists(directory) is False
def test_project_delete_permission_issue(loop):
async def test_project_delete_permission_issue():
project = Project(project_id=str(uuid4()))
directory = project.path
assert os.path.exists(directory)
os.chmod(directory, 0)
with pytest.raises(aiohttp.web.HTTPInternalServerError):
loop.run_until_complete(asyncio.ensure_future(project.delete()))
await asyncio.ensure_future(project.delete())
os.chmod(directory, 700)
def test_project_add_node(manager):
async def test_project_add_node(manager):
project = Project(project_id=str(uuid4()))
node = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
project.add_node(node)
assert len(project.nodes) == 1
def test_project_close(loop, node, project):
async def test_project_close(node, compute_project):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.close") as mock:
loop.run_until_complete(asyncio.ensure_future(project.close()))
await compute_project.close()
assert mock.called
assert node.id not in node.manager._nodes
def test_list_files(tmpdir, loop):
async def test_list_files(tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"projects_path": str(tmpdir)}):
project = Project(project_id=str(uuid4()))
@ -181,7 +188,7 @@ def test_list_files(tmpdir, loop):
with open(os.path.join(path, "test.txt"), "w+") as f:
f.write("test2")
files = loop.run_until_complete(asyncio.ensure_future(project.list_files()))
files = await project.list_files()
assert files == [
{
@ -195,20 +202,21 @@ def test_list_files(tmpdir, loop):
]
def test_emit(async_run):
async def test_emit():
with NotificationManager.instance().queue() as queue:
(action, event, context) = async_run(queue.get(0.5)) #  Ping
await queue.get(0.5) #  Ping
project = Project(project_id=str(uuid4()))
project.emit("test", {})
(action, event, context) = async_run(queue.get(0.5))
(action, event, context) = await queue.get(0.5)
assert action == "test"
assert context["project_id"] == project.id
def test_update_project(loop):
async def test_update_project():
variables = [{"name": "TEST", "value": "VAL"}]
project = Project(project_id=str(uuid.uuid4()))
loop.run_until_complete(asyncio.ensure_future(project.update(variables=variables)))
await project.update(variables=variables)
assert project.variables == variables

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,16 +17,19 @@
import aiohttp
import pytest
from gns3server.compute.project_manager import ProjectManager
def test_create_project():
pm = ProjectManager.instance()
project = pm.create_project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f')
assert project == pm.get_project('00010203-0405-0607-0809-0a0b0c0d0e0f')
def test_project_not_found():
pm = ProjectManager.instance()
with pytest.raises(aiohttp.web.HTTPNotFound):
pm.get_project('00010203-0405-0607-0809-000000000000')

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,10 +17,9 @@
import pytest
import asyncio
import sys
from tests.utils import asyncio_patch, AsyncioMagicMock
from unittest.mock import patch, MagicMock, ANY, PropertyMock
from unittest.mock import patch, MagicMock, ANY
from gns3server.compute.traceng.traceng_vm import TraceNGVM
from gns3server.compute.traceng.traceng_error import TraceNGError
@ -31,14 +30,16 @@ from gns3server.compute.notification_manager import NotificationManager
@pytest.fixture
def manager(port_manager):
m = TraceNG.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def vm(project, manager, ubridge_path):
vm = TraceNGVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
def vm(loop, compute_project, manager, ubridge_path):
vm = TraceNGVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
vm._start_ubridge = AsyncioMagicMock()
vm._ubridge_hypervisor = MagicMock()
vm._ubridge_hypervisor.is_running.return_value = True
@ -46,33 +47,36 @@ def vm(project, manager, ubridge_path):
def test_vm(project, manager):
vm = TraceNGVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_vm_invalid_traceng_path(vm, manager, loop):
async def test_vm_invalid_traceng_path(vm, manager):
with patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._traceng_path", return_value="/tmp/fake/path/traceng"):
with pytest.raises(TraceNGError):
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.port_add_nio_binding(0, nio)
await vm.start()
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e"
def test_start(loop, vm, async_run):
async def test_start(vm):
process = MagicMock()
process.returncode = None
with NotificationManager.instance().queue() as queue:
async_run(queue.get(1)) # Ping
await queue.get(1) # Ping
vm.ip_address = "192.168.1.1"
with patch("sys.platform", return_value="win"):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
loop.run_until_complete(asyncio.ensure_future(vm.start("192.168.1.2")))
await vm.start("192.168.1.2")
assert mock_exec.call_args[0] == (vm._traceng_path(),
'-u',
'-c',
@ -88,14 +92,14 @@ def test_start(loop, vm, async_run):
'192.168.1.2')
assert vm.is_running()
assert vm.command_line == ' '.join(mock_exec.call_args[0])
(action, event, kwargs) = async_run(queue.get(1))
(action, event, kwargs) = await queue.get(1)
assert action == "node.updated"
assert event == vm
def test_stop(loop, vm, async_run):
process = MagicMock()
async def test_stop(vm):
process = MagicMock()
# Wait process kill success
future = asyncio.Future()
future.set_result(True)
@ -108,29 +112,29 @@ def test_stop(loop, vm, async_run):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
nio = TraceNG.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
async_run(vm.port_add_nio_binding(0, nio))
await vm.port_add_nio_binding(0, nio)
vm._ubridge_send = AsyncioMagicMock()
async_run(vm.start("192.168.1.2"))
await vm.start("192.168.1.2")
assert vm.is_running()
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
loop.run_until_complete(asyncio.ensure_future(vm.stop()))
await vm.stop()
assert vm.is_running() is False
process.terminate.assert_called_with()
async_run(queue.get(1)) #  Ping
async_run(queue.get(1)) #  Started
await queue.get(1) #  Ping
await queue.get(1) #  Started
(action, event, kwargs) = async_run(queue.get(1))
(action, event, kwargs) = await queue.get(1)
assert action == "node.updated"
assert event == vm
def test_reload(loop, vm, async_run):
process = MagicMock()
async def test_reload(vm):
process = MagicMock()
# Wait process kill success
future = asyncio.Future()
future.set_result(True)
@ -142,14 +146,14 @@ def test_reload(loop, vm, async_run):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
nio = TraceNG.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
async_run(vm.port_add_nio_binding(0, nio))
await vm.port_add_nio_binding(0, nio)
vm._ubridge_send = AsyncioMagicMock()
async_run(vm.start("192.168.1.2"))
await vm.start("192.168.1.2")
assert vm.is_running()
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
async_run(vm.reload())
await vm.reload()
assert vm.is_running() is True
#if sys.platform.startswith("win"):
@ -158,24 +162,27 @@ def test_reload(loop, vm, async_run):
process.terminate.assert_called_with()
def test_add_nio_binding_udp(vm, async_run):
async def test_add_nio_binding_udp(vm):
nio = TraceNG.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
async_run(vm.port_add_nio_binding(0, nio))
await vm.port_add_nio_binding(0, nio)
assert nio.lport == 4242
def test_port_remove_nio_binding(loop, vm):
async def test_port_remove_nio_binding(vm):
nio = TraceNG.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.port_remove_nio_binding(0)))
await asyncio.ensure_future(vm.port_add_nio_binding(0, nio))
await vm.port_remove_nio_binding(0)
assert vm._ethernet_adapter.ports[0] is None
def test_close(vm, port_manager, loop):
async def test_close(vm):
vm.ip_address = "192.168.1.1"
with patch("sys.platform", return_value="win"):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
loop.run_until_complete(asyncio.ensure_future(vm.start("192.168.1.2")))
loop.run_until_complete(asyncio.ensure_future(vm.close()))
await vm.start("192.168.1.2")
await vm.close()
assert vm.is_running() is False

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -20,8 +20,6 @@ import pytest
import tempfile
import os
import stat
import asyncio
from unittest.mock import patch
@ -31,19 +29,22 @@ from tests.utils import asyncio_patch
@pytest.fixture
def manager(port_manager):
async def manager(loop, port_manager):
m = VirtualBox.instance()
m.port_manager = port_manager
return m
def test_vm_invalid_vboxmanage_path(manager):
with patch("gns3server.config.Config.get_section_config", return_value={"vboxmanage_path": "/bin/test_fake"}):
with pytest.raises(VirtualBoxError):
manager.find_vboxmanage()
def test_vm_non_executable_vboxmanage_path(manager):
tmpfile = tempfile.NamedTemporaryFile()
with patch("gns3server.config.Config.get_section_config", return_value={"vboxmanage_path": tmpfile.name}):
with pytest.raises(VirtualBoxError):
@ -51,27 +52,28 @@ def test_vm_non_executable_vboxmanage_path(manager):
def test_vm_invalid_executable_name_vboxmanage_path(manager, tmpdir):
path = str(tmpdir / "vpcs")
with open(path, "w+") as f:
f.write(path)
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
tmpfile = tempfile.NamedTemporaryFile()
with patch("gns3server.config.Config.get_section_config", return_value={"vboxmanage_path": path}):
with pytest.raises(VirtualBoxError):
manager.find_vboxmanage()
def test_vboxmanage_path(manager, tmpdir):
path = str(tmpdir / "VBoxManage")
with open(path, "w+") as f:
f.write(path)
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
tmpfile = tempfile.NamedTemporaryFile()
with patch("gns3server.config.Config.get_section_config", return_value={"vboxmanage_path": path}):
assert manager.find_vboxmanage() == path
def test_list_vms(manager, loop):
async def test_list_vms(manager):
vm_list = ['"Windows 8.1" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1}',
'"Carriage',
'Return" {27b4d095-ff5f-4ac4-bb9d-5f2c7861c3f3}',
@ -83,7 +85,6 @@ def test_list_vms(manager, loop):
if cmd == "list":
return vm_list
else:
print(args)
if args[0] == "27b4d095-ff5f-4ac4-bb9d-5f2c7861c1f1":
return ["memory=512"]
elif args[0] == "ccd8c50b-c172-457d-99fa-dd69371ede0e":
@ -92,7 +93,7 @@ def test_list_vms(manager, loop):
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute") as mock:
mock.side_effect = execute_mock
vms = loop.run_until_complete(asyncio.ensure_future(manager.list_vms()))
vms = await manager.list_vms()
assert vms == [
{"vmname": "Windows 8.1", "ram": 512},
{"vmname": "Linux Microcore 4.7.1", "ram": 256}

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -26,30 +26,34 @@ from gns3server.compute.virtualbox import VirtualBox
@pytest.fixture
def manager(port_manager):
def manager(loop, port_manager):
m = VirtualBox.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def vm(project, manager):
return VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "test", False)
def vm(compute_project, manager):
return VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "test", False)
def test_vm(project, manager):
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "test", False)
def test_vm(compute_project, manager):
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "test", False)
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
assert vm.vmname == "test"
def test_rename_vmname(project, manager, async_run):
async def test_rename_vmname(compute_project, manager):
"""
Rename a VM is not allowed when using a running linked clone
or if the vm already exists in Vbox
"""
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "test", False)
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "test", False)
vm.manager.list_vms = AsyncioMagicMock(return_value=[{"vmname": "Debian"}])
vm._linked_clone = True
vm._modify_vm = AsyncioMagicMock()
@ -57,42 +61,46 @@ def test_rename_vmname(project, manager, async_run):
# Vm is running
vm._node_status = "started"
with pytest.raises(VirtualBoxError):
async_run(vm.set_vmname("Arch"))
await vm.set_vmname("Arch")
assert not vm._modify_vm.called
vm._node_status = "stopped"
# Name already use
with pytest.raises(VirtualBoxError):
async_run(vm.set_vmname("Debian"))
await vm.set_vmname("Debian")
assert not vm._modify_vm.called
# Work
async_run(vm.set_vmname("Arch"))
await vm.set_vmname("Arch")
assert vm._modify_vm.called
def test_vm_valid_virtualbox_api_version(loop, project, manager):
async def test_vm_valid_virtualbox_api_version(compute_project, manager):
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute", return_value=["API version: 4_3"]):
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "test", False)
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "test", False)
vm._uuid = "00010203-0405-0607-0809-0a0b0c0d0e0f"
loop.run_until_complete(asyncio.ensure_future(vm.create()))
await vm.create()
def test_vm_invalid_virtualbox_api_version(loop, project, manager):
async def test_vm_invalid_virtualbox_api_version(compute_project, manager):
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.execute", return_value=["API version: 4_2"]):
with pytest.raises(VirtualBoxError):
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, "test", False)
loop.run_until_complete(asyncio.ensure_future(vm.create()))
vm = VirtualBoxVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, "test", False)
await vm.create()
def test_vm_adapter_add_nio_binding_adapter_not_exist(loop, vm, manager, free_console_port):
async def test_vm_adapter_add_nio_binding_adapter_not_exist(vm, manager, free_console_port):
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
with pytest.raises(VirtualBoxError):
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(15, nio)))
await vm.adapter_add_nio_binding(15, nio)
def test_json(vm, tmpdir, project):
assert vm.__json__()["node_directory"] is None
project._path = str(tmpdir)
vm._linked_clone = True
@ -100,12 +108,14 @@ def test_json(vm, tmpdir, project):
def test_patch_vm_uuid(vm):
xml = """<?xml version="1.0"?>
<VirtualBox xmlns="http://www.virtualbox.org/" version="1.16-macosx">
<Machine uuid="{f8138a63-e361-49ee-a5a4-ba0559bc00e2}" name="Debian-1" OSType="Debian_64" currentSnapshot="{8bd00b14-4c14-4992-a165-cb09e80fe8e4 }" snapshotFolder="Snapshots" lastStateChange="2016-10-28T12:54:26Z">
</Machine>
</VirtualBox>
"""
os.makedirs(os.path.join(vm.working_dir, vm._vmname), exist_ok=True)
with open(vm._linked_vbox_file(), "w+") as f:
f.write(xml)
@ -117,6 +127,7 @@ def test_patch_vm_uuid(vm):
def test_patch_vm_uuid_with_corrupted_file(vm):
xml = """<?xml version="1.0"?>
<VirtualBox>
"""

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,26 +17,20 @@
import pytest
import tempfile
import os
import stat
import asyncio
from unittest.mock import patch
from gns3server.compute.vmware import VMware
from tests.utils import asyncio_patch
@pytest.fixture
def manager(port_manager):
async def manager(loop, port_manager):
m = VMware.instance()
m.port_manager = port_manager
return m
def test_parse_vmware_file(manager, tmpdir):
def test_parse_vmware_file(tmpdir):
path = str(tmpdir / "test.vmx")
with open(path, "w+") as f:
f.write('displayname = "GNS3 VM"\nguestOS = "ubuntu-64"')

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,57 +17,58 @@
import pytest
import asyncio
from tests.utils import asyncio_patch
from gns3server.compute.vmware.vmware_vm import VMwareVM
from gns3server.compute.vmware.vmware_error import VMwareError
from gns3server.compute.vmware import VMware
@pytest.fixture
def manager(port_manager):
m = VMware.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def vm(project, manager, tmpdir):
async def vm(loop, compute_project, manager, tmpdir):
fake_vmx = str(tmpdir / "test.vmx")
open(fake_vmx, "w+").close()
return VMwareVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, fake_vmx, False)
return VMwareVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager, fake_vmx, False)
def test_vm(project, manager, vm):
def test_vm(vm):
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_json(vm, tmpdir, project):
def test_json(vm, tmpdir, compute_project):
assert vm.__json__()["node_directory"] is not None
project._path = str(tmpdir)
compute_project._path = str(tmpdir)
vm._linked_clone = True
assert vm.__json__()["node_directory"] is not None
def test_start_capture(vm, tmpdir, manager, free_console_port, loop):
async def test_start_capture(vm, tmpdir, manager, free_console_port):
output_file = str(tmpdir / "test.pcap")
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
vm.adapters = 1
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start_capture(0, output_file)))
await vm.adapter_add_nio_binding(0, nio)
await vm.start_capture(0, output_file)
assert vm._ethernet_adapters[0].get_nio(0).capturing
def test_stop_capture(vm, tmpdir, manager, free_console_port, loop):
async def test_stop_capture(vm, tmpdir, manager, free_console_port):
output_file = str(tmpdir / "test.pcap")
nio = manager.create_nio({"type": "nio_udp", "lport": free_console_port, "rport": free_console_port, "rhost": "127.0.0.1"})
vm.adapters = 1
loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio)))
loop.run_until_complete(vm.start_capture(0, output_file))
await vm.adapter_add_nio_binding(0, nio)
await vm.start_capture(0, output_file)
assert vm._ethernet_adapters[0].get_nio(0).capturing
loop.run_until_complete(asyncio.ensure_future(vm.stop_capture(0)))
await asyncio.ensure_future(vm.stop_capture(0))
assert vm._ethernet_adapters[0].get_nio(0).capturing is False

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -25,7 +25,8 @@ from gns3server.compute.vpcs.vpcs_error import VPCSError
from gns3server.compute.project_manager import ProjectManager
def test_get_mac_id(loop, project, port_manager):
async def test_get_mac_id(compute_project, port_manager):
# Cleanup the VPCS object
VPCS._instance = None
vpcs = VPCS.instance()
@ -33,17 +34,18 @@ def test_get_mac_id(loop, project, port_manager):
vm1_id = str(uuid.uuid4())
vm2_id = str(uuid.uuid4())
vm3_id = str(uuid.uuid4())
loop.run_until_complete(vpcs.create_node("PC 1", project.id, vm1_id))
loop.run_until_complete(vpcs.create_node("PC 2", project.id, vm2_id))
await vpcs.create_node("PC 1", compute_project.id, vm1_id)
await vpcs.create_node("PC 2", compute_project.id, vm2_id)
assert vpcs.get_mac_id(vm1_id) == 0
assert vpcs.get_mac_id(vm1_id) == 0
assert vpcs.get_mac_id(vm2_id) == 1
loop.run_until_complete(vpcs.delete_node(vm1_id))
loop.run_until_complete(vpcs.create_node("PC 3", project.id, vm3_id))
await vpcs.delete_node(vm1_id)
await vpcs.create_node("PC 3", compute_project.id, vm3_id)
assert vpcs.get_mac_id(vm3_id) == 0
def test_get_mac_id_multiple_project(loop, port_manager):
async def test_get_mac_id_multiple_project(port_manager):
# Cleanup the VPCS object
VPCS._instance = None
vpcs = VPCS.instance()
@ -53,15 +55,16 @@ def test_get_mac_id_multiple_project(loop, port_manager):
vm3_id = str(uuid.uuid4())
project1 = ProjectManager.instance().create_project(project_id=str(uuid.uuid4()))
project2 = ProjectManager.instance().create_project(project_id=str(uuid.uuid4()))
loop.run_until_complete(vpcs.create_node("PC 1", project1.id, vm1_id))
loop.run_until_complete(vpcs.create_node("PC 2", project1.id, vm2_id))
loop.run_until_complete(vpcs.create_node("PC 2", project2.id, vm3_id))
await vpcs.create_node("PC 1", project1.id, vm1_id)
await vpcs.create_node("PC 2", project1.id, vm2_id)
await vpcs.create_node("PC 2", project2.id, vm3_id)
assert vpcs.get_mac_id(vm1_id) == 0
assert vpcs.get_mac_id(vm2_id) == 1
assert vpcs.get_mac_id(vm3_id) == 0
def test_get_mac_id_no_id_available(loop, project, port_manager):
async def test_get_mac_id_no_id_available(compute_project, port_manager):
# Cleanup the VPCS object
VPCS._instance = None
vpcs = VPCS.instance()
@ -69,5 +72,5 @@ def test_get_mac_id_no_id_available(loop, project, port_manager):
with pytest.raises(VPCSError):
for i in range(0, 256):
node_id = str(uuid.uuid4())
loop.run_until_complete(vpcs.create_node("PC {}".format(i), project.id, node_id))
await vpcs.create_node("PC {}".format(i), compute_project.id, node_id)
assert vpcs.get_mac_id(node_id) == i

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,7 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import aiohttp
import asyncio
import os
import sys
@ -32,15 +31,17 @@ from gns3server.compute.notification_manager import NotificationManager
@pytest.fixture
def manager(port_manager):
async def manager(loop, port_manager):
m = VPCS.instance()
m.port_manager = port_manager
return m
@pytest.fixture(scope="function")
def vm(project, manager, ubridge_path):
vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
async def vm(loop, compute_project, manager, ubridge_path):
vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
vm._vpcs_version = parse_version("0.9")
vm._start_ubridge = AsyncioMagicMock()
vm._ubridge_hypervisor = MagicMock()
@ -48,55 +49,61 @@ def vm(project, manager, ubridge_path):
return vm
def test_vm(project, manager):
vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
async def test_vm(compute_project, manager):
vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", compute_project, manager)
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_vm_check_vpcs_version(loop, vm, manager):
async def test_vm_check_vpcs_version(vm):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.9"):
loop.run_until_complete(asyncio.ensure_future(vm._check_vpcs_version()))
await asyncio.ensure_future(vm._check_vpcs_version())
assert vm._vpcs_version == parse_version("0.9")
def test_vm_check_vpcs_version_0_6_1(loop, vm, manager):
async def test_vm_check_vpcs_version_0_6_1(vm):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.6.1"):
loop.run_until_complete(asyncio.ensure_future(vm._check_vpcs_version()))
await vm._check_vpcs_version()
assert vm._vpcs_version == parse_version("0.6.1")
def test_vm_invalid_vpcs_version(loop, manager, vm):
async def test_vm_invalid_vpcs_version(vm, manager):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.1"):
with pytest.raises(VPCSError):
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm._check_vpcs_version()))
await asyncio.ensure_future(vm.port_add_nio_binding(0, nio))
await asyncio.ensure_future(vm._check_vpcs_version())
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
def test_vm_invalid_vpcs_path(vm, manager, loop):
async def test_vm_invalid_vpcs_path(vm, manager):
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"})
loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await asyncio.ensure_future(vm.port_add_nio_binding(0, nio))
await asyncio.ensure_future(vm.start())
assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e"
def test_start(loop, vm, async_run):
async def test_start(vm):
process = MagicMock()
process.returncode = None
with NotificationManager.instance().queue() as queue:
async_run(queue.get(1)) # Ping
await queue.get(1) # Ping
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
loop.run_until_complete(asyncio.ensure_future(vm.start()))
await vm.start()
assert mock_exec.call_args[0] == (vm._vpcs_path(),
'-p',
str(vm._internal_console_port),
@ -113,16 +120,17 @@ def test_start(loop, vm, async_run):
'127.0.0.1')
assert vm.is_running()
assert vm.command_line == ' '.join(mock_exec.call_args[0])
(action, event, kwargs) = async_run(queue.get(1))
(action, event, kwargs) = await queue.get(1)
assert action == "node.updated"
assert event == vm
def test_start_0_6_1(loop, vm, async_run):
async def test_start_0_6_1(vm):
"""
Version 0.6.1 doesn't have the -R options. It's not require
because GNS3 provide a patch for this.
"""
process = MagicMock()
process.returncode = None
vm._vpcs_version = parse_version("0.6.1")
@ -131,8 +139,8 @@ def test_start_0_6_1(loop, vm, async_run):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process) as mock_exec:
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
async_run(vm.port_add_nio_binding(0, nio))
async_run(vm.start())
await vm.port_add_nio_binding(0, nio)
await vm.start()
assert mock_exec.call_args[0] == (vm._vpcs_path(),
'-p',
str(vm._internal_console_port),
@ -149,9 +157,9 @@ def test_start_0_6_1(loop, vm, async_run):
assert vm.is_running()
def test_stop(loop, vm, async_run):
process = MagicMock()
async def test_stop(vm):
process = MagicMock()
# Wait process kill success
future = asyncio.Future()
future.set_result(True)
@ -163,13 +171,13 @@ def test_stop(loop, vm, async_run):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
async_run(vm.port_add_nio_binding(0, nio))
await vm.port_add_nio_binding(0, nio)
async_run(vm.start())
await vm.start()
assert vm.is_running()
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
loop.run_until_complete(asyncio.ensure_future(vm.stop()))
await asyncio.ensure_future(vm.stop())
assert vm.is_running() is False
if sys.platform.startswith("win"):
@ -177,17 +185,17 @@ def test_stop(loop, vm, async_run):
else:
process.terminate.assert_called_with()
async_run(queue.get(1)) #  Ping
async_run(queue.get(1)) #  Started
await queue.get(1) #  Ping
await queue.get(1) #  Started
(action, event, kwargs) = async_run(queue.get(1))
(action, event, kwargs) = await queue.get(1)
assert action == "node.updated"
assert event == vm
def test_reload(loop, vm, async_run):
process = MagicMock()
async def test_reload(vm):
process = MagicMock()
# Wait process kill success
future = asyncio.Future()
future.set_result(True)
@ -198,13 +206,13 @@ def test_reload(loop, vm, async_run):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process):
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
async_run(vm.port_add_nio_binding(0, nio))
async_run(vm.start())
await vm.port_add_nio_binding(0, nio)
await vm.start()
assert vm.is_running()
vm._ubridge_send = AsyncioMagicMock()
with asyncio_patch("gns3server.utils.asyncio.wait_for_process_termination"):
async_run(vm.reload())
await vm.reload()
assert vm.is_running() is True
if sys.platform.startswith("win"):
@ -213,28 +221,32 @@ def test_reload(loop, vm, async_run):
process.terminate.assert_called_with()
def test_add_nio_binding_udp(vm, async_run):
async def test_add_nio_binding_udp(vm):
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
async_run(vm.port_add_nio_binding(0, nio))
await vm.port_add_nio_binding(0, nio)
assert nio.lport == 4242
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_add_nio_binding_tap(vm, ethernet_device, loop):
async def test_add_nio_binding_tap(vm, ethernet_device):
with patch("gns3server.compute.base_manager.BaseManager.has_privileged_access", return_value=True):
nio = VPCS.instance().create_nio({"type": "nio_tap", "tap_device": ethernet_device})
loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
await asyncio.ensure_future(vm.port_add_nio_binding(0, nio))
assert nio.tap_device == ethernet_device
def test_port_remove_nio_binding(vm, loop):
async def test_port_remove_nio_binding(vm):
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.port_remove_nio_binding(0)))
await asyncio.ensure_future(vm.port_add_nio_binding(0, nio))
await vm.port_remove_nio_binding(0)
assert vm._ethernet_adapter.ports[0] is None
def test_update_startup_script(vm):
content = "echo GNS3 VPCS\nip 192.168.1.2\n"
vm.startup_script = content
filepath = os.path.join(vm.working_dir, 'startup.vpc')
@ -244,6 +256,7 @@ def test_update_startup_script(vm):
def test_update_startup_script_h(vm):
content = "set pcname %h\n"
vm.name = "pc1"
vm.startup_script = content
@ -253,12 +266,14 @@ def test_update_startup_script_h(vm):
def test_update_startup_script_with_escaping_characters_in_name(vm):
vm.startup_script = "set pcname initial-name\n"
vm.name = "test\\"
assert vm.startup_script == "set pcname test{}".format(os.linesep)
def test_get_startup_script(vm):
content = "echo GNS3 VPCS\nip 192.168.1.2"
vm.startup_script = content
assert vm.startup_script == os.linesep.join(["echo GNS3 VPCS", "ip 192.168.1.2"])
@ -278,7 +293,8 @@ def test_get_startup_script_using_default_script(vm):
assert vm.script_file == filepath
def test_change_name(vm, tmpdir):
def test_change_name(vm):
path = os.path.join(vm.working_dir, 'startup.vpc')
vm.name = "world"
with open(path, 'w+') as f:
@ -296,11 +312,11 @@ def test_change_name(vm, tmpdir):
assert f.read() == "set pcname beta"
def test_close(vm, port_manager, loop):
async def test_close(vm):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
loop.run_until_complete(asyncio.ensure_future(vm.start()))
loop.run_until_complete(asyncio.ensure_future(vm.close()))
await asyncio.ensure_future(vm.start())
await asyncio.ensure_future(vm.close())
assert vm.is_running() is False

View File

@ -1,204 +1,46 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2015 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import gc
import pytest
import socket
import asyncio
import tempfile
import weakref
import shutil
import os
import sys
import aiohttp
import weakref
from aiohttp import web
from unittest.mock import patch
from unittest.mock import MagicMock, patch
from pathlib import Path
from gns3server.web.route import Route
from gns3server.controller import Controller
from gns3server.config import Config
from gns3server.compute import MODULES
from gns3server.compute.port_manager import PortManager
from gns3server.compute.project_manager import ProjectManager
# this import will register all handlers
from gns3server.handlers import *
from .handlers.api.base import Query
sys._called_from_test = True
sys.original_platform = sys.platform
# Prevent execution of external binaries
os.environ["PATH"] = tempfile.mkdtemp()
from gns3server.config import Config
from gns3server.web.route import Route
# TODO: get rid of *
from gns3server.handlers import *
from gns3server.compute import MODULES
from gns3server.compute.port_manager import PortManager
from gns3server.compute.project_manager import ProjectManager
from gns3server.controller import Controller
from tests.handlers.api.base import Query
@pytest.fixture(scope='function')
async def http_client(aiohttp_client):
@pytest.yield_fixture
def restore_original_path():
"""
Temporary restore a standard path environnement. This allow
to run external binaries.
"""
os.environ["PATH"] = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
yield
os.environ["PATH"] = tempfile.mkdtemp()
@pytest.yield_fixture(scope="session")
def loop(request):
"""Return an event loop and destroy it at the end of test"""
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop) # Replace main loop to avoid conflict between tests
yield loop
#loop.close()
asyncio.set_event_loop(None)
def _get_unused_port():
""" Return an unused port on localhost. In rare occasion it can return
an already used port (race condition)"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 0))
addr, port = s.getsockname()
s.close()
return port
@pytest.fixture
async def client(aiohttp_client):
"""
Return an helper allowing you to call the server without any prefix
"""
app = web.Application()
app['websockets'] = weakref.WeakSet()
for method, route, handler in Route.get_routes():
app.router.add_route(method, route, handler)
return await aiohttp_client(app)
@pytest.yield_fixture
def http_server(request, loop, port_manager, monkeypatch, controller):
"""A GNS3 server"""
app = web.Application()
for method, route, handler in Route.get_routes():
app.router.add_route(method, route, handler)
# Keep a list of active websocket connections
app['websockets'] = weakref.WeakSet()
host = "127.0.0.1"
# We try multiple time. Because on Travis test can fail when because the port is taken by someone else
for i in range(0, 5):
port = _get_unused_port()
try:
runner = web.AppRunner(app)
loop.run_until_complete(runner.setup())
site = web.TCPSite(runner, host, port)
loop.run_until_complete(site.start())
except OSError:
pass
else:
break
yield (host, port)
# close websocket connections
for ws in set(app['websockets']):
loop.run_until_complete(ws.close(code=aiohttp.WSCloseCode.GOING_AWAY, message='Server shutdown'))
loop.run_until_complete(controller.stop())
for module in MODULES:
instance = module.instance()
monkeypatch.setattr('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.close', lambda self: True)
loop.run_until_complete(instance.unload())
loop.run_until_complete(runner.cleanup())
@pytest.fixture
def http_root(loop, http_server):
"""
Return an helper allowing you to call the server without any prefix
"""
host, port = http_server
return Query(loop, host=host, port=port)
@pytest.fixture
def http_controller(loop, http_server):
"""
Return an helper allowing you to call the server API without any prefix
"""
host, port = http_server
return Query(loop, host=host, port=port, api_version=2)
@pytest.fixture
def http_compute(loop, http_server):
"""
Return an helper allowing you to call the hypervisor API via HTTP
"""
host, port = http_server
return Query(loop, host=host, port=port, prefix="/compute", api_version=2)
@pytest.fixture(scope="function")
def project(tmpdir):
"""A GNS3 lab"""
p = ProjectManager.instance().create_project(project_id="a1e920ca-338a-4e9f-b363-aa607b09dd80")
return p
@pytest.fixture(scope="function")
def port_manager():
"""An instance of port manager"""
PortManager._instance = None
p = PortManager.instance()
p.console_host = "127.0.0.1"
return p
@pytest.fixture(scope="function")
def free_console_port(request, port_manager, project):
"""Get a free TCP port"""
# In case of already use ports we will raise an exception
port = port_manager.get_free_tcp_port(project)
# We release the port immediately in order to allow
# the test do whatever the test want
port_manager.release_tcp_port(port, project)
return port
@pytest.fixture
def ethernet_device():
import psutil
return sorted(psutil.net_if_addrs().keys())[0]
@pytest.fixture
def controller_config_path(tmpdir):
return str(tmpdir / "config" / "gns3_controller.conf")
@pytest.fixture
def controller(tmpdir, controller_config_path):
Controller._instance = None
controller = Controller.instance()
os.makedirs(os.path.dirname(controller_config_path), exist_ok=True)
@ -208,17 +50,184 @@ def controller(tmpdir, controller_config_path):
return controller
@pytest.fixture
def compute(controller):
compute = MagicMock()
compute.id = "example.com"
controller._computes = {"example.com": compute}
return compute
@pytest.fixture
async def project(loop, tmpdir, controller):
return await controller.add_project(name="Test")
@pytest.fixture
def compute_project(tmpdir):
return ProjectManager.instance().create_project(project_id="a1e920ca-338a-4e9f-b363-aa607b09dd80")
@pytest.fixture
def compute_api(http_client):
"""
Return an helper allowing you to call the hypervisor API via HTTP
"""
return Query(http_client, prefix="/compute", api_version=2)
@pytest.fixture
def controller_api(http_client, controller):
"""
Return an helper allowing you to call the server API without any prefix
"""
return Query(http_client, api_version=2)
@pytest.fixture
def config():
config = Config.instance()
config.clear()
return config
@pytest.yield_fixture(autouse=True)
def run_around_tests(monkeypatch, port_manager, controller, config):
@pytest.fixture
def images_dir(config):
"""
This setup a temporay project file environnement around tests
Get the location of images
"""
path = config.get_section_config("Server").get("images_path")
os.makedirs(path, exist_ok=True)
os.makedirs(os.path.join(path, "QEMU"))
os.makedirs(os.path.join(path, "IOU"))
return path
@pytest.fixture
def symbols_dir(config):
"""
Get the location of symbols
"""
path = config.get_section_config("Server").get("symbols_path")
os.makedirs(path, exist_ok=True)
print(path)
return path
@pytest.fixture
def projects_dir(config):
"""
Get the location of images
"""
path = config.get_section_config("Server").get("projects_path")
os.makedirs(path, exist_ok=True)
return path
@pytest.fixture(scope="function")
def port_manager():
"""An instance of port manager"""
PortManager._instance = None
p = PortManager.instance()
p.console_host = "127.0.0.1"
return p
@pytest.fixture(scope="function")
def free_console_port(port_manager, compute_project):
"""Get a free TCP port"""
# In case of already use ports we will raise an exception
port = port_manager.get_free_tcp_port(compute_project)
# We release the port immediately in order to allow
# the test do whatever the test want
port_manager.release_tcp_port(port, compute_project)
return port
@pytest.fixture
def darwin_platform():
"""
Change sys.plaform to Darwin
"""
old_platform = sys.platform
sys.platform = "darwin10.10"
yield
sys.plaform = old_platform
@pytest.fixture
def windows_platform():
"""
Change sys.platform to Windows
"""
old_platform = sys.platform
sys.platform = "win10"
yield
sys.plaform = old_platform
@pytest.fixture
def linux_platform():
"""
Change sys.platform to Linux
"""
old_platform = sys.platform
sys.platform = "linuxdebian"
yield
sys.plaform = old_platform
@pytest.fixture
def on_gns3vm(linux_platform):
"""
Mock the hostname to emulate the GNS3 VM
"""
with patch("gns3server.utils.interfaces.interfaces", return_value=[
{"name": "eth0", "special": False, "type": "ethernet"},
{"name": "eth1", "special": False, "type": "ethernet"},
{"name": "virbr0", "special": True, "type": "ethernet"}]):
with patch("socket.gethostname", return_value="gns3vm"):
yield
@pytest.fixture
def ethernet_device():
import psutil
return sorted(psutil.net_if_addrs().keys())[0]
@pytest.fixture
def ubridge_path(config):
"""
Get the location of a fake ubridge
"""
path = config.get_section_config("Server").get("ubridge_path")
os.makedirs(os.path.dirname(path), exist_ok=True)
open(path, 'w+').close()
return path
@pytest.fixture(autouse=True)
def run_around_tests(monkeypatch, config, port_manager):#port_manager, controller, config):
"""
This setup a temporary project file environment around tests
"""
tmppath = tempfile.mkdtemp()
@ -255,101 +264,3 @@ def run_around_tests(monkeypatch, port_manager, controller, config):
shutil.rmtree(tmppath)
except BaseException:
pass
@pytest.fixture
def images_dir(config):
"""
Get the location of images
"""
path = config.get_section_config("Server").get("images_path")
os.makedirs(path, exist_ok=True)
os.makedirs(os.path.join(path, "QEMU"))
os.makedirs(os.path.join(path, "IOU"))
return path
@pytest.fixture
def symbols_dir(config):
"""
Get the location of symbols
"""
path = config.get_section_config("Server").get("symbols_path")
os.makedirs(path, exist_ok=True)
print(path)
return path
@pytest.fixture
def projects_dir(config):
"""
Get the location of images
"""
path = config.get_section_config("Server").get("projects_path")
os.makedirs(path, exist_ok=True)
return path
@pytest.fixture
def ubridge_path(config):
"""
Get the location of a fake ubridge
"""
path = config.get_section_config("Server").get("ubridge_path")
os.makedirs(os.path.dirname(path), exist_ok=True)
open(path, 'w+').close()
return path
@pytest.yield_fixture
def darwin_platform():
"""
Change sys.plaform to Darwin
"""
old_platform = sys.platform
sys.platform = "darwin10.10"
yield
sys.plaform = old_platform
@pytest.yield_fixture
def windows_platform():
"""
Change sys.platform to Windows
"""
old_platform = sys.platform
sys.platform = "win10"
yield
sys.plaform = old_platform
@pytest.yield_fixture
def linux_platform():
"""
Change sys.platform to Linux
"""
old_platform = sys.platform
sys.platform = "linuxdebian"
yield
sys.plaform = old_platform
@pytest.fixture
def async_run(loop):
"""
Shortcut for running in asyncio loop
"""
return lambda x: loop.run_until_complete(asyncio.ensure_future(x))
@pytest.yield_fixture
def on_gns3vm(linux_platform):
"""
Mock the hostname to emulate the GNS3 VM
"""
with patch("gns3server.utils.interfaces.interfaces", return_value=[
{"name": "eth0", "special": False, "type": "ethernet"},
{"name": "eth1", "special": False, "type": "ethernet"},
{"name": "virbr0", "special": True, "type": "ethernet"}]):
with patch("socket.gethostname", return_value="gns3vm"):
yield

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -23,25 +23,30 @@ from gns3server.controller.gns3vm.gns3_vm_error import GNS3VMError
@pytest.fixture
def gns3vm(controller):
return RemoteGNS3VM(controller)
def test_list(async_run, gns3vm, controller):
async_run(controller.add_compute("r1", name="R1", host="r1.local", connect=False))
res = async_run(gns3vm.list())
async def test_list(gns3vm, controller):
await controller.add_compute("r1", name="R1", host="r1.local", connect=False)
res = await gns3vm.list()
assert res == [{"vmname": "R1"}]
def test_start(async_run, gns3vm, controller):
async_run(controller.add_compute("r1", name="R1",
protocol="https",
host="r1.local",
port=8484,
user="hello",
password="world",
connect=False))
async def test_start(gns3vm, controller):
await controller.add_compute("r1",
name="R1",
protocol="https",
host="r1.local",
port=8484,
user="hello",
password="world",
connect=False)
gns3vm.vmname = "R1"
res = async_run(gns3vm.start())
await gns3vm.start()
assert gns3vm.running
assert gns3vm.protocol == "https"
assert gns3vm.ip_address == "r1.local"
@ -50,14 +55,17 @@ def test_start(async_run, gns3vm, controller):
assert gns3vm.password == "world"
def test_start_invalid_vm(async_run, gns3vm, controller):
async_run(controller.add_compute("r1", name="R1",
protocol="https",
host="r1.local",
port=8484,
user="hello",
password="world"))
async def test_start_invalid_vm(loop, gns3vm, controller):
await controller.add_compute("r1",
name="R1",
protocol="https",
host="r1.local",
port=8484,
user="hello",
password="world")
gns3vm.vmname = "R2"
with pytest.raises(GNS3VMError):
res = async_run(gns3vm.start())
await gns3vm.start()
assert not gns3vm.running

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,19 +16,24 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
from tests.utils import asyncio_patch
import asyncio
from tests.utils import asyncio_patch, AsyncioMagicMock
from unittest.mock import patch
from gns3server.controller.gns3vm.virtualbox_gns3_vm import VirtualBoxGNS3VM
@pytest.fixture
def gns3vm(controller):
async def gns3vm(loop, controller):
vm = VirtualBoxGNS3VM(controller)
vm.vmname = "GNS3 VM"
return vm
def test_look_for_interface(gns3vm, async_run):
async def test_look_for_interface(gns3vm):
showvminfo = """
nic1="hostonly"
nictype1="82540EM"
@ -50,10 +55,13 @@ GuestMemoryBalloon=0
"""
with asyncio_patch("gns3server.controller.gns3vm.virtualbox_gns3_vm.VirtualBoxGNS3VM._execute", return_value=showvminfo) as mock:
res = async_run(gns3vm._look_for_interface("nat"))
res = await gns3vm._look_for_interface("nat")
mock.assert_called_with('showvminfo', ['GNS3 VM', '--machinereadable'])
assert res == 2
with asyncio_patch("gns3server.controller.gns3vm.virtualbox_gns3_vm.VirtualBoxGNS3VM._execute", return_value=showvminfo) as mock:
res = async_run(gns3vm._look_for_interface("dummy"))
assert res == -1
# with asyncio_patch("gns3server.controller.gns3vm.virtualbox_gns3_vm.VirtualBoxGNS3VM._execute") as mock:
# mock.side_effect = execute_mock
# res = await gns3vm._look_for_interface("dummy")
# assert mock.called
# assert res == -1

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2017 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,41 +17,42 @@
import pytest
from tests.utils import asyncio_patch
from gns3server.controller.gns3vm.vmware_gns3_vm import VMwareGNS3VM
@pytest.fixture
def gns3vm(controller):
vm = VMwareGNS3VM(controller)
vm.vmname = "GNS3 VM"
return vm
@pytest.fixture
def tmx_path(tmpdir):
return str(tmpdir / "vmware.tmx")
def vmx_path(tmpdir):
return str(tmpdir / "vmwware_vm.vmx")
def test_set_extra_options(gns3vm, async_run, tmx_path):
gns3vm._vmx_path = tmx_path
async def test_set_extra_options(loop, gns3vm, vmx_path, windows_platform):
gns3vm._vmx_path = vmx_path
# when there is not an entry, we modify it
with open(tmx_path, 'w') as f:
with open(vmx_path, 'w') as f:
f.write("")
async_run(gns3vm._set_extra_options())
await gns3vm._set_extra_options()
with open(tmx_path, 'r') as f:
with open(vmx_path, 'r') as f:
assert f.read() == 'vhv.enable = "TRUE"\n'
# when there is an entry, we don't modify it
with open(tmx_path, 'w') as f:
with open(vmx_path, 'w') as f:
f.write('vhv.enable = "FALSE"\n')
async_run(gns3vm._set_extra_options())
await gns3vm._set_extra_options()
with open(tmx_path, 'r') as f:
with open(vmx_path, 'r') as f:
assert f.read() == 'vhv.enable = "FALSE"\n'

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -15,32 +15,31 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import json
import pytest
import socket
import aiohttp
import asyncio
from unittest.mock import patch, MagicMock
from gns3server.controller.project import Project
from gns3server.controller.compute import Compute, ComputeError, ComputeConflict
from gns3server.version import __version__
from gns3server.controller.compute import Compute, ComputeConflict
from tests.utils import asyncio_patch, AsyncioMagicMock
@pytest.fixture
def compute(controller):
compute = Compute("my_compute_id", protocol="https", host="example.com", port=84, controller=controller)
compute._connected = True
return compute
def test_init(compute):
assert compute.id == "my_compute_id"
def test_getUrl(controller):
compute = Compute("my_compute_id", protocol="https", host="localhost", port=84, controller=controller)
assert compute._getUrl("/test") == "https://localhost:84/v2/compute/test"
# IPV6 localhost
@ -56,6 +55,7 @@ def test_getUrl(controller):
def test_get_url(controller):
compute = Compute("my_compute_id", protocol="https", host="localhost", port=84, controller=controller)
with patch('gns3server.controller.compute.Compute._getUrl', return_value="returned") as getURL:
assert compute.get_url("/test") == 'returned'
@ -63,11 +63,13 @@ def test_get_url(controller):
def test_host_ip(controller):
compute = Compute("my_compute_id", protocol="https", host="localhost", port=84, controller=controller)
assert compute.host_ip == "127.0.0.1"
def test_name():
c = Compute("my_compute_id", protocol="https", host="example.com", port=84, controller=MagicMock(), name=None)
assert c.name == "https://example.com:84"
c = Compute("world", protocol="https", host="example.com", port=84, controller=MagicMock(), name="hello")
@ -76,137 +78,150 @@ def test_name():
assert c.name == "https://azertyuiopq...@example.com:84"
def test_compute_httpQuery(compute, async_run):
async def test_compute_httpQuery(compute):
response = MagicMock()
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
response.status = 200
async_run(compute.post("/projects", {"a": "b"}))
async_run(compute.close())
await compute.post("/projects", {"a": "b"})
await compute.close()
mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data=b'{"a": "b"}', headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
assert compute._auth is None
def test_compute_httpQueryAuth(compute, async_run):
async def test_compute_httpQueryAuth(compute):
response = MagicMock()
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
response.status = 200
compute.user = "root"
compute.password = "toor"
async_run(compute.post("/projects", {"a": "b"}))
async_run(compute.close())
await compute.post("/projects", {"a": "b"})
await compute.close()
mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data=b'{"a": "b"}', headers={'content-type': 'application/json'}, auth=compute._auth, chunked=None, timeout=20)
assert compute._auth.login == "root"
assert compute._auth.password == "toor"
def test_compute_httpQueryNotConnected(compute, controller, async_run):
controller._notification = MagicMock()
compute._connected = False
response = AsyncioMagicMock()
response.read = AsyncioMagicMock(return_value=json.dumps({"version": __version__}).encode())
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.post("/projects", {"a": "b"}))
mock.assert_any_call("GET", "https://example.com:84/v2/compute/capabilities", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=None, timeout=20)
mock.assert_any_call("POST", "https://example.com:84/v2/compute/projects", data=b'{"a": "b"}', headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
#assert compute._connected
assert compute._capabilities["version"] == __version__
controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__())
async_run(compute.close())
def test_compute_httpQueryNotConnectedGNS3vmNotRunning(compute, controller, async_run):
"""
We are not connected to the remote and it's a GNS3 VM. So we need to start it
"""
controller._notification = MagicMock()
controller.gns3vm = AsyncioMagicMock()
controller.gns3vm.running = False
compute._id = "vm"
compute._connected = False
response = AsyncioMagicMock()
response.read = AsyncioMagicMock(return_value=json.dumps({"version": __version__}).encode())
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.post("/projects", {"a": "b"}))
mock.assert_any_call("GET", "https://example.com:84/v2/compute/capabilities", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=None, timeout=20)
mock.assert_any_call("POST", "https://example.com:84/v2/compute/projects", data=b'{"a": "b"}', headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
assert controller.gns3vm.start.called
#assert compute._connected
assert compute._capabilities["version"] == __version__
controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__())
async_run(compute.close())
# async def test_compute_httpQueryNotConnected(compute, controller):
#
# controller._notification = MagicMock()
# compute._connected = False
# response = AsyncioMagicMock()
# response.read = AsyncioMagicMock(return_value=json.dumps({"version": __version__}).encode())
# response.status = 200
# with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
# await compute.post("/projects", {"a": "b"})
# mock.assert_any_call("GET", "https://example.com:84/v2/compute/capabilities", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=None, timeout=20)
# mock.assert_any_call("POST", "https://example.com:84/v2/compute/projects", data=b'{"a": "b"}', headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
# #assert compute._connected
# assert compute._capabilities["version"] == __version__
# controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__())
# await compute.close()
def test_compute_httpQueryNotConnectedInvalidVersion(compute, async_run):
# async def test_compute_httpQueryNotConnectedGNS3vmNotRunning(compute, controller):
# """
# We are not connected to the remote and it's a GNS3 VM. So we need to start it
# """
#
# controller._notification = MagicMock()
# controller.gns3vm = AsyncioMagicMock()
# controller.gns3vm.running = False
#
# compute._id = "vm"
# compute._connected = False
# response = AsyncioMagicMock()
# response.read = AsyncioMagicMock(return_value=json.dumps({"version": __version__}).encode())
# response.status = 200
# with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
# await compute.post("/projects", {"a": "b"})
# mock.assert_any_call("GET", "https://example.com:84/v2/compute/capabilities", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=None, timeout=20)
# mock.assert_any_call("POST", "https://example.com:84/v2/compute/projects", data=b'{"a": "b"}', headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
#
# assert controller.gns3vm.start.called
# #assert compute._connected
# assert compute._capabilities["version"] == __version__
# controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__())
# await compute.close()
async def test_compute_httpQueryNotConnectedInvalidVersion(compute):
compute._connected = False
response = AsyncioMagicMock()
response.read = AsyncioMagicMock(return_value=json.dumps({"version": "1.42.4"}).encode())
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(compute.post("/projects", {"a": "b"}))
await compute.post("/projects", {"a": "b"})
mock.assert_any_call("GET", "https://example.com:84/v2/compute/capabilities", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=None, timeout=20)
async_run(compute.close())
await compute.close()
async def test_compute_httpQueryNotConnectedNonGNS3Server(compute):
def test_compute_httpQueryNotConnectedNonGNS3Server(compute, async_run):
compute._connected = False
response = AsyncioMagicMock()
response.read = AsyncioMagicMock(return_value=b'Blocked by super antivirus')
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(compute.post("/projects", {"a": "b"}))
await compute.post("/projects", {"a": "b"})
mock.assert_any_call("GET", "https://example.com:84/v2/compute/capabilities", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=None, timeout=20)
async_run(compute.close())
await compute.close()
async def test_compute_httpQueryNotConnectedNonGNS3Server2(compute):
def test_compute_httpQueryNotConnectedNonGNS3Server2(compute, async_run):
compute._connected = False
response = AsyncioMagicMock()
response.read = AsyncioMagicMock(return_value=b'{}')
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(compute.post("/projects", {"a": "b"}))
await compute.post("/projects", {"a": "b"})
mock.assert_any_call("GET", "https://example.com:84/v2/compute/capabilities", headers={'content-type': 'application/json'}, data=None, auth=None, chunked=None, timeout=20)
def test_compute_httpQueryError(compute, async_run):
async def test_compute_httpQueryError(compute):
response = MagicMock()
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
response.status = 404
with pytest.raises(aiohttp.web.HTTPNotFound):
async_run(compute.post("/projects", {"a": "b"}))
async_run(compute.close())
await compute.post("/projects", {"a": "b"})
assert mock.called
await compute.close()
def test_compute_httpQueryConflictError(compute, async_run):
async def test_compute_httpQueryConflictError(compute):
response = MagicMock()
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
response.status = 409
response.read = AsyncioMagicMock(return_value=b'{"message": "Test"}')
with pytest.raises(ComputeConflict):
async_run(compute.post("/projects", {"a": "b"}))
async_run(compute.close())
await compute.post("/projects", {"a": "b"})
assert mock.called
await compute.close()
async def test_compute_httpQuery_project(compute):
def test_compute_httpQuery_project(compute, async_run):
response = MagicMock()
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
response.status = 200
project = Project(name="Test")
async_run(compute.post("/projects", project))
await compute.post("/projects", project)
mock.assert_called_with("POST", "https://example.com:84/v2/compute/projects", data=json.dumps(project.__json__()), headers={'content-type': 'application/json'}, auth=None, chunked=None, timeout=20)
async_run(compute.close())
await compute.close()
# FIXME: https://github.com/aio-libs/aiohttp/issues/2525
# def test_connectNotification(compute, async_run):
# ws_mock = AsyncioMagicMock()
# async def test_connectNotification(compute):
#
# ws_mock = AsyncioMagicMock()
# call = 0
#
# async def receive():
@ -226,12 +241,12 @@ def test_compute_httpQuery_project(compute, async_run):
# compute._http_session = AsyncioMagicMock(return_value=ws_mock)
# compute._http_session.ws_connect = AsyncioMagicMock(return_value=ws_mock)
# ws_mock.receive = receive
# async_run(compute._connect_notification())
# await compute._connect_notification()
#
# compute._controller.notification.dispatch.assert_called_with('test', {'a': 1}, compute_id=compute.id)
# assert compute._connected is False
#
#
# def test_connectNotificationPing(compute, async_run):
# """
# When we receive a ping from a compute we update
@ -265,8 +280,8 @@ def test_compute_httpQuery_project(compute, async_run):
# assert args[1]["memory_usage_percent"] == 80.7
# assert args[1]["cpu_usage_percent"] == 35.7
async def test_json(compute):
def test_json(compute):
compute.user = "test"
assert compute.__json__() == {
"compute_id": "my_compute_id",
@ -293,28 +308,31 @@ def test_json(compute):
}
def test_downloadFile(project, async_run, compute):
async def test_downloadFile(project, compute):
response = MagicMock()
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.download_file(project, "test/titi"))
await compute.download_file(project, "test/titi")
mock.assert_called_with("GET", "https://example.com:84/v2/compute/projects/{}/files/test/titi".format(project.id), auth=None)
async_run(compute.close())
await compute.close()
def test_close(compute, async_run):
async def test_close(compute):
assert compute.connected is True
async_run(compute.close())
await compute.close()
assert compute.connected is False
def test_update(compute, controller, async_run):
async def test_update(compute, controller):
compute._controller._notification = MagicMock()
compute._controller.save = MagicMock()
compute.name = "Test"
compute.host = "example.org"
compute._connected = True
async_run(compute.update(name="Test 2"))
await compute.update(name="Test 2")
assert compute.name == "Test 2"
assert compute.host == "example.org"
controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__())
@ -322,34 +340,42 @@ def test_update(compute, controller, async_run):
assert compute._controller.save.called
def test_forward_get(compute, async_run):
async def test_forward_get(compute):
response = MagicMock()
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.forward("GET", "qemu", "images"))
await compute.forward("GET", "qemu", "images")
mock.assert_called_with("GET", "https://example.com:84/v2/compute/qemu/images", auth=None, data=None, headers={'content-type': 'application/json'}, chunked=None, timeout=None)
async_run(compute.close())
await compute.close()
async def test_forward_404(compute):
def test_forward_404(compute, async_run):
response = MagicMock()
response.status = 404
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
async_run(compute.forward("GET", "qemu", "images"))
async_run(compute.close())
await compute.forward("GET", "qemu", "images")
assert mock.called
await compute.close()
async def test_forward_post(compute):
def test_forward_post(compute, async_run):
response = MagicMock()
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.forward("POST", "qemu", "img", data={"id": 42}))
await compute.forward("POST", "qemu", "img", data={"id": 42})
mock.assert_called_with("POST", "https://example.com:84/v2/compute/qemu/img", auth=None, data=b'{"id": 42}', headers={'content-type': 'application/json'}, chunked=None, timeout=None)
async_run(compute.close())
await compute.close()
def test_images(compute, async_run, images_dir):
async def test_images(compute):
"""
Will return image on compute
"""
response = MagicMock()
response.status = 200
response.read = AsyncioMagicMock(return_value=json.dumps([{
@ -358,26 +384,29 @@ def test_images(compute, async_run, images_dir):
"md5sum": "d41d8cd98f00b204e9800998ecf8427e",
"filesize": 0}]).encode())
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
images = async_run(compute.images("qemu"))
images = await compute.images("qemu")
mock.assert_called_with("GET", "https://example.com:84/v2/compute/qemu/images", auth=None, data=None, headers={'content-type': 'application/json'}, chunked=None, timeout=None)
async_run(compute.close())
await compute.close()
assert images == [
{"filename": "linux.qcow2", "path": "linux.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}
]
def test_list_files(project, async_run, compute):
async def test_list_files(project, compute):
res = [{"path": "test"}]
response = AsyncioMagicMock()
response.read = AsyncioMagicMock(return_value=json.dumps(res).encode())
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
assert async_run(compute.list_files(project)) == res
assert await compute.list_files(project) == res
mock.assert_any_call("GET", "https://example.com:84/v2/compute/projects/{}/files".format(project.id), auth=None, chunked=None, data=None, headers={'content-type': 'application/json'}, timeout=None)
async_run(compute.close())
await compute.close()
async def test_interfaces(compute):
def test_interfaces(project, async_run, compute):
res = [
{
"id": "vmnet99",
@ -392,11 +421,13 @@ def test_interfaces(project, async_run, compute):
response.read = AsyncioMagicMock(return_value=json.dumps(res).encode())
response.status = 200
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
assert async_run(compute.interfaces()) == res
assert await compute.interfaces() == res
mock.assert_any_call("GET", "https://example.com:84/v2/compute/network/interfaces", auth=None, chunked=None, data=None, headers={'content-type': 'application/json'}, timeout=20)
async_run(compute.close())
await compute.close()
async def test_get_ip_on_same_subnet(controller):
def test_get_ip_on_same_subnet(controller, async_run):
compute1 = Compute("compute1", host="192.168.1.1", controller=controller)
compute1._interfaces_cache = [
{
@ -429,7 +460,7 @@ def test_get_ip_on_same_subnet(controller, async_run):
"netmask": "255.255.255.0"
}
]
assert async_run(compute1.get_ip_on_same_subnet(compute2)) == ("192.168.1.1", "192.168.1.2")
assert await compute1.get_ip_on_same_subnet(compute2) == ("192.168.1.1", "192.168.1.2")
# Case 2 compute2 host is on a different network but a common interface is available
compute2 = Compute("compute2", host="127.0.0.1", controller=controller)
@ -447,7 +478,7 @@ def test_get_ip_on_same_subnet(controller, async_run):
"netmask": "255.255.255.0"
}
]
assert async_run(compute1.get_ip_on_same_subnet(compute2)) == ("192.168.1.1", "192.168.1.2")
assert await compute1.get_ip_on_same_subnet(compute2) == ("192.168.1.1", "192.168.1.2")
#No common interface
compute2 = Compute("compute2", host="127.0.0.1", controller=controller)
@ -458,7 +489,7 @@ def test_get_ip_on_same_subnet(controller, async_run):
}
]
with pytest.raises(ValueError):
async_run(compute1.get_ip_on_same_subnet(compute2))
await compute1.get_ip_on_same_subnet(compute2)
# Ignore 169.254 network because it's for Windows special purpose
compute2 = Compute("compute2", host="192.168.1.2", controller=controller)
@ -483,4 +514,4 @@ def test_get_ip_on_same_subnet(controller, async_run):
"netmask": "255.255.0.0"
},
]
assert async_run(compute1.get_ip_on_same_subnet(compute2)) == ('192.168.2.1', '192.168.1.2')
assert await compute1.get_ip_on_same_subnet(compute2) == ('192.168.2.1', '192.168.1.2')

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -29,6 +29,7 @@ from gns3server.version import __version__
def test_save(controller, controller_config_path):
controller.save()
assert os.path.exists(controller_config_path)
with open(controller_config_path) as f:
@ -39,7 +40,8 @@ def test_save(controller, controller_config_path):
assert data["gns3vm"] == controller.gns3vm.__json__()
def test_load_controller_settings(controller, controller_config_path, async_run):
def test_load_controller_settings(controller, controller_config_path):
controller.save()
with open(controller_config_path) as f:
data = json.load(f)
@ -60,7 +62,8 @@ def test_load_controller_settings(controller, controller_config_path, async_run)
assert controller.gns3vm.settings["vmname"] == "Test VM"
def test_load_controller_settings_with_no_computes_section(controller, controller_config_path, async_run):
def test_load_controller_settings_with_no_computes_section(controller, controller_config_path):
controller.save()
with open(controller_config_path) as f:
data = json.load(f)
@ -70,11 +73,12 @@ def test_load_controller_settings_with_no_computes_section(controller, controlle
assert len(controller._load_controller_settings()) == 0
def test_import_computes_1_x(controller, controller_config_path, async_run):
def test_import_computes_1_x(controller, controller_config_path):
"""
At first start the server should import the
computes from the gns3_gui 1.X
"""
gns3_gui_conf = {
"Servers": {
"remote_servers": [
@ -106,43 +110,46 @@ def test_import_computes_1_x(controller, controller_config_path, async_run):
assert compute.password is None
def test_load_projects(controller, projects_dir, async_run):
controller.save()
async def test_load_projects(controller, projects_dir):
controller.save()
os.makedirs(os.path.join(projects_dir, "project1"))
with open(os.path.join(projects_dir, "project1", "project1.gns3"), "w+") as f:
f.write("")
with asyncio_patch("gns3server.controller.Controller.load_project") as mock_load_project:
async_run(controller.load_projects())
await controller.load_projects()
mock_load_project.assert_called_with(os.path.join(projects_dir, "project1", "project1.gns3"), load=False)
def test_add_compute(controller, controller_config_path, async_run):
async def test_add_compute(controller):
controller._notification = MagicMock()
c = async_run(controller.add_compute(compute_id="test1", connect=False))
c = await controller.add_compute(compute_id="test1", connect=False)
controller._notification.controller_emit.assert_called_with("compute.created", c.__json__())
assert len(controller.computes) == 1
async_run(controller.add_compute(compute_id="test1", connect=False))
await controller.add_compute(compute_id="test1", connect=False)
controller._notification.controller_emit.assert_called_with("compute.updated", c.__json__())
assert len(controller.computes) == 1
async_run(controller.add_compute(compute_id="test2", connect=False))
await controller.add_compute(compute_id="test2", connect=False)
assert len(controller.computes) == 2
def test_addDuplicateCompute(controller, controller_config_path, async_run):
async def test_addDuplicateCompute(controller):
controller._notification = MagicMock()
c = async_run(controller.add_compute(compute_id="test1", name="Test", connect=False))
c = await controller.add_compute(compute_id="test1", name="Test", connect=False)
assert len(controller.computes) == 1
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(controller.add_compute(compute_id="test2", name="Test", connect=False))
await controller.add_compute(compute_id="test2", name="Test", connect=False)
def test_deleteCompute(controller, controller_config_path, async_run):
c = async_run(controller.add_compute(compute_id="test1", connect=False))
async def test_deleteCompute(controller, controller_config_path):
c = await controller.add_compute(compute_id="test1", connect=False)
assert len(controller.computes) == 1
controller._notification = MagicMock()
c._connected = True
async_run(controller.delete_compute("test1"))
await controller.delete_compute("test1")
assert len(controller.computes) == 0
controller._notification.controller_emit.assert_called_with("compute.deleted", c.__json__())
with open(controller_config_path) as f:
@ -151,25 +158,26 @@ def test_deleteCompute(controller, controller_config_path, async_run):
assert c.connected is False
def test_deleteComputeProjectOpened(controller, controller_config_path, async_run):
async def test_deleteComputeProjectOpened(controller, controller_config_path):
"""
When you delete a compute the project using it are close
"""
c = async_run(controller.add_compute(compute_id="test1", connect=False))
c = await controller.add_compute(compute_id="test1", connect=False)
c.post = AsyncioMagicMock()
assert len(controller.computes) == 1
project1 = async_run(controller.add_project(name="Test1"))
async_run(project1.open())
project1 = await controller.add_project(name="Test1")
await project1.open()
# We simulate that the project use this compute
project1._project_created_on_compute.add(c)
project2 = async_run(controller.add_project(name="Test2"))
async_run(project2.open())
project2 = await controller.add_project(name="Test2")
await project2.open()
controller._notification = MagicMock()
c._connected = True
async_run(controller.delete_compute("test1"))
await controller.delete_compute("test1")
assert len(controller.computes) == 0
controller._notification.controller_emit.assert_called_with("compute.deleted", c.__json__())
with open(controller_config_path) as f:
@ -182,8 +190,9 @@ def test_deleteComputeProjectOpened(controller, controller_config_path, async_ru
assert project2.status == "opened"
def test_addComputeConfigFile(controller, controller_config_path, async_run):
async_run(controller.add_compute(compute_id="test1", name="Test", connect=False))
async def test_addComputeConfigFile(controller, controller_config_path):
await controller.add_compute(compute_id="test1", name="Test", connect=False)
assert len(controller.computes) == 1
with open(controller_config_path) as f:
data = json.load(f)
@ -200,170 +209,180 @@ def test_addComputeConfigFile(controller, controller_config_path, async_run):
]
def test_getCompute(controller, async_run):
compute = async_run(controller.add_compute(compute_id="test1", connect=False))
async def test_getCompute(controller):
compute = await controller.add_compute(compute_id="test1", connect=False)
assert controller.get_compute("test1") == compute
with pytest.raises(aiohttp.web.HTTPNotFound):
assert controller.get_compute("dsdssd")
def test_has_compute(controller, async_run):
compute = async_run(controller.add_compute(compute_id="test1", connect=False))
async def test_has_compute(controller):
await controller.add_compute(compute_id="test1", connect=False)
assert controller.has_compute("test1")
assert not controller.has_compute("test2")
def test_add_project(controller, async_run):
async def test_add_project(controller):
uuid1 = str(uuid.uuid4())
uuid2 = str(uuid.uuid4())
async_run(controller.add_project(project_id=uuid1, name="Test"))
await controller.add_project(project_id=uuid1, name="Test")
assert len(controller.projects) == 1
async_run(controller.add_project(project_id=uuid1, name="Test"))
await controller.add_project(project_id=uuid1, name="Test")
assert len(controller.projects) == 1
async_run(controller.add_project(project_id=uuid2, name="Test 2"))
await controller.add_project(project_id=uuid2, name="Test 2")
assert len(controller.projects) == 2
def test_addDuplicateProject(controller, async_run):
async def test_addDuplicateProject(controller):
uuid1 = str(uuid.uuid4())
uuid2 = str(uuid.uuid4())
async_run(controller.add_project(project_id=uuid1, name="Test"))
await controller.add_project(project_id=uuid1, name="Test")
assert len(controller.projects) == 1
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(controller.add_project(project_id=uuid2, name="Test"))
await controller.add_project(project_id=uuid2, name="Test")
def test_remove_project(controller, async_run):
async def test_remove_project(controller):
uuid1 = str(uuid.uuid4())
project1 = async_run(controller.add_project(project_id=uuid1, name="Test"))
project1 = await controller.add_project(project_id=uuid1, name="Test")
assert len(controller.projects) == 1
controller.remove_project(project1)
assert len(controller.projects) == 0
def test_addProject_with_compute(controller, async_run):
uuid1 = str(uuid.uuid4())
async def test_addProject_with_compute(controller):
uuid1 = str(uuid.uuid4())
compute = Compute("test1", controller=MagicMock())
compute.post = MagicMock()
controller._computes = {"test1": compute}
project1 = async_run(controller.add_project(project_id=uuid1, name="Test"))
await controller.add_project(project_id=uuid1, name="Test")
def test_getProject(controller, async_run):
async def test_getProject(controller):
uuid1 = str(uuid.uuid4())
project = async_run(controller.add_project(project_id=uuid1, name="Test"))
project = await controller.add_project(project_id=uuid1, name="Test")
assert controller.get_project(uuid1) == project
with pytest.raises(aiohttp.web.HTTPNotFound):
assert controller.get_project("dsdssd")
def test_start(controller, async_run):
async def test_start(controller):
controller.gns3vm.settings = {
"enable": False,
"engine": "vmware",
"vmname": "GNS3 VM"
}
with asyncio_patch("gns3server.controller.compute.Compute.connect") as mock:
async_run(controller.start())
await controller.start()
assert mock.called
assert len(controller.computes) == 1 # Local compute is created
assert controller.computes["local"].name == socket.gethostname()
def test_start_vm(controller, async_run):
async def test_start_vm(controller):
"""
Start the controller with a GNS3 VM
"""
controller.gns3vm.settings = {
"enable": True,
"engine": "vmware",
"vmname": "GNS3 VM"
}
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.start") as mock:
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network") as mock_check_network:
with asyncio_patch("gns3server.controller.compute.Compute.connect") as mock_connect:
async_run(controller.start())
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network"):
with asyncio_patch("gns3server.controller.compute.Compute.connect"):
await controller.start()
assert mock.called
assert "local" in controller.computes
assert "vm" in controller.computes
assert len(controller.computes) == 2 # Local compute and vm are created
def test_stop(controller, async_run):
c = async_run(controller.add_compute(compute_id="test1", connect=False))
async def test_stop(controller):
c = await controller.add_compute(compute_id="test1", connect=False)
c._connected = True
async_run(controller.stop())
await controller.stop()
assert c.connected is False
def test_stop_vm(controller, async_run):
async def test_stop_vm(controller):
"""
Stop GNS3 VM if configured
"""
controller.gns3vm.settings = {
"enable": True,
"engine": "vmware",
"when_exit": "stop",
"vmname": "GNS3 VM"
}
controller.gns3vm.current_engine().running = True
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.stop") as mock:
async_run(controller.stop())
await controller.stop()
assert mock.called
def test_suspend_vm(controller, async_run):
async def test_suspend_vm(controller):
"""
Suspend GNS3 VM if configured
"""
controller.gns3vm.settings = {
"enable": True,
"engine": "vmware",
"when_exit": "suspend",
"vmname": "GNS3 VM"
}
controller.gns3vm.current_engine().running = True
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.suspend") as mock:
async_run(controller.stop())
await controller.stop()
assert mock.called
def test_keep_vm(controller, async_run):
async def test_keep_vm(controller):
"""
Keep GNS3 VM if configured
"""
controller.gns3vm.settings = {
"enable": True,
"engine": "vmware",
"when_exit": "keep",
"vmname": "GNS3 VM"
}
controller.gns3vm.current_engine().running = True
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.suspend") as mock:
async_run(controller.stop())
await controller.stop()
assert not mock.called
def test_get_free_project_name(controller, async_run):
async def test_get_free_project_name(controller):
async_run(controller.add_project(project_id=str(uuid.uuid4()), name="Test"))
await controller.add_project(project_id=str(uuid.uuid4()), name="Test")
assert controller.get_free_project_name("Test") == "Test-1"
async_run(controller.add_project(project_id=str(uuid.uuid4()), name="Test-1"))
await controller.add_project(project_id=str(uuid.uuid4()), name="Test-1")
assert controller.get_free_project_name("Test") == "Test-2"
assert controller.get_free_project_name("Hello") == "Hello"
def test_load_base_files(controller, config, tmpdir):
config.set_section_config("Server", {"configs_path": str(tmpdir)})
async def test_load_base_files(controller, config, tmpdir):
config.set_section_config("Server", {"configs_path": str(tmpdir)})
with open(str(tmpdir / 'iou_l2_base_startup-config.txt'), 'w+') as f:
f.write('test')
@ -375,7 +394,8 @@ def test_load_base_files(controller, config, tmpdir):
assert f.read() == 'test'
def test_appliances(controller, async_run, tmpdir):
def test_appliances(controller, tmpdir):
my_appliance = {
"name": "My Appliance",
"status": "stable"
@ -406,6 +426,7 @@ def test_appliances(controller, async_run, tmpdir):
def test_load_templates(controller):
controller._settings = {}
controller.template_manager.load_templates()
@ -430,10 +451,11 @@ def test_load_templates(controller):
assert cloud_uuid == template.id
def test_autoidlepc(controller, async_run):
async def test_autoidlepc(controller):
controller._computes["local"] = AsyncioMagicMock()
node_mock = AsyncioMagicMock()
with asyncio_patch("gns3server.controller.Project.add_node", return_value=node_mock):
async_run(controller.autoidlepc("local", "c7200", "test.bin", 512))
await controller.autoidlepc("local", "c7200", "test.bin", 512)
assert node_mock.dynamips_auto_idlepc.called
assert len(controller.projects) == 0

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -22,33 +22,30 @@ import os
from tests.utils import AsyncioMagicMock
from gns3server.controller.drawing import Drawing
from gns3server.controller.project import Project
@pytest.fixture
def project(controller, async_run):
return async_run(controller.add_project(name="Test"))
@pytest.fixture
def drawing(project):
return Drawing(project, None, svg="<svg></svg>")
def test_init_without_uuid(project):
drawing = Drawing(project, None, svg="<svg></svg>")
assert drawing.id is not None
def test_init_with_uuid(project):
id = str(uuid.uuid4())
drawing = Drawing(project, id, svg="<svg></svg>")
assert drawing.id == id
def test_json(project):
i = Drawing(project, None, svg="<svg></svg>")
assert i.__json__() == {
"drawing_id": i.id,
@ -71,11 +68,12 @@ def test_json(project):
}
def test_update(drawing, project, async_run, controller):
async def test_update(drawing, project, controller):
controller._notification = AsyncioMagicMock()
project.dump = MagicMock()
async_run(drawing.update(x=42, svg="<svg><rect></rect></svg>"))
await drawing.update(x=42, svg="<svg><rect></rect></svg>")
assert drawing.x == 42
args, kwargs = controller._notification.project_emit.call_args
assert args[0] == "drawing.updated"
@ -83,7 +81,7 @@ def test_update(drawing, project, async_run, controller):
assert args[1]["x"] == 42
assert args[1]["svg"] == "<svg><rect></rect></svg>"
async_run(drawing.update(x=12, svg="<svg><rect></rect></svg>"))
await drawing.update(x=12, svg="<svg><rect></rect></svg>")
assert drawing.x == 12
args, kwargs = controller._notification.project_emit.call_args
assert args[0] == "drawing.updated"
@ -99,6 +97,7 @@ def test_image_base64(project):
"""
If image are embed as base 64 we need to dump them on disk
"""
svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" height=\"128\" width=\"128\">\n<image height=\"128\" width=\"128\" xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAN2AAADdgF91YLMAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAHm5JREFUeJztnXl8FGXSx7/VIYAKKCoe4IEIq6ALuQnI4YXXKihulCSACIIsu4qKNyqXByqK67EeiMtyJGrwXnfABSu/L3I31aclPub3oBIQ/YD2zdUBZ+T37l7Dt0OAKoIYcUf07mBhpkieonJe+FcAUOgeX8dL/4ysTCSmTiwwsx1FPLJfuas89mXsByu/N/BR43E09+xMafDrYFI6wmzINu7QreFo1kD4EQIW/m8ICm1iAdBXWp0wuusiJp+Q7ilok3VE02RR+MoWPTYMXTYNlarAx6c6iQU7X/RbQ4DZA2m1F44CnrdYjDPG8ZcLBe/1kzz2Z9ybfUZQALAS\" />\n</svg>"
drawing = Drawing(project, None, svg=svg)
@ -112,6 +111,7 @@ def test_image_svg(project):
"""
Large SVG are dump on disk
"""
svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" height=\"128\" width=\"128\">\n"
for i in range(0, 1000):

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -33,14 +33,16 @@ from gns3server.utils.asyncio import aiozipstream
@pytest.fixture
def project(controller):
async def project(loop, controller):
p = Project(controller=controller, name="test")
p.dump = MagicMock()
return p
@pytest.fixture
def node(controller, project, async_run):
async def node(controller, project):
compute = MagicMock()
compute.id = "local"
@ -48,7 +50,7 @@ def node(controller, project, async_run):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node = async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
return node
@ -60,6 +62,7 @@ async def write_file(path, z):
def test_exportable_files():
assert _is_exportable("hello/world")
assert not _is_exportable("project-files/tmp")
assert not _is_exportable("project-files/test_log.txt")
@ -69,7 +72,8 @@ def test_exportable_files():
assert not _is_exportable("test/project-files/snapshots/test.gns3p")
def test_export(tmpdir, project, async_run):
async def test_export(tmpdir, project):
path = project.path
os.makedirs(os.path.join(path, "vm-1", "dynamips"))
@ -113,8 +117,8 @@ def test_export(tmpdir, project, async_run):
with aiozipstream.ZipFile() as z:
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
async_run(export_project(z, project, str(tmpdir), include_images=False))
async_run(write_file(str(tmpdir / 'zipfile.zip'), z))
await export_project(z, project, str(tmpdir), include_images=False)
await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
with myzip.open("vm-1/dynamips/test") as myfile:
@ -134,7 +138,7 @@ def test_export(tmpdir, project, async_run):
assert topo["computes"] == []
def test_export_vm(tmpdir, project, async_run):
async def test_export_vm(tmpdir, project):
"""
If data is on a remote server export it locally before
sending it in the archive.
@ -147,7 +151,7 @@ def test_export_vm(tmpdir, project, async_run):
# Fake file that will be download from the vm
mock_response = AsyncioMagicMock()
mock_response.content = AsyncioBytesIO()
async_run(mock_response.content.write(b"HELLO"))
await mock_response.content.write(b"HELLO")
mock_response.content.seek(0)
compute.download_file = AsyncioMagicMock(return_value=mock_response)
@ -161,9 +165,9 @@ def test_export_vm(tmpdir, project, async_run):
f.write("{}")
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir)))
await export_project(z, project, str(tmpdir))
assert compute.list_files.called
async_run(write_file(str(tmpdir / 'zipfile.zip'), z))
await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
with myzip.open("vm-1/dynamips/test") as myfile:
@ -171,7 +175,7 @@ def test_export_vm(tmpdir, project, async_run):
assert content == b"HELLO"
def test_export_disallow_running(tmpdir, project, node, async_run):
async def test_export_disallow_running(tmpdir, project, node):
"""
Disallow export when a node is running
"""
@ -194,10 +198,10 @@ def test_export_disallow_running(tmpdir, project, node, async_run):
node._status = "started"
with pytest.raises(aiohttp.web.HTTPConflict):
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir)))
await export_project(z, project, str(tmpdir))
def test_export_disallow_some_type(tmpdir, project, async_run):
async def test_export_disallow_some_type(tmpdir, project):
"""
Disallow export for some node type
"""
@ -219,9 +223,9 @@ def test_export_disallow_some_type(tmpdir, project, async_run):
with pytest.raises(aiohttp.web.HTTPConflict):
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir)))
await export_project(z, project, str(tmpdir))
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir), allow_all_nodes=True))
await export_project(z, project, str(tmpdir), allow_all_nodes=True)
# VirtualBox is always disallowed
topology = {
@ -240,10 +244,10 @@ def test_export_disallow_some_type(tmpdir, project, async_run):
json.dump(topology, f)
with pytest.raises(aiohttp.web.HTTPConflict):
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir), allow_all_nodes=True))
await export_project(z, project, str(tmpdir), allow_all_nodes=True)
def test_export_fix_path(tmpdir, project, async_run):
async def test_export_fix_path(tmpdir, project):
"""
Fix absolute image path, except for Docker
"""
@ -273,8 +277,8 @@ def test_export_fix_path(tmpdir, project, async_run):
json.dump(topology, f)
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir)))
async_run(write_file(str(tmpdir / 'zipfile.zip'), z))
await export_project(z, project, str(tmpdir))
await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
with myzip.open("project.gns3") as myfile:
@ -284,7 +288,7 @@ def test_export_fix_path(tmpdir, project, async_run):
assert topology["topology"]["nodes"][1]["properties"]["image"] == "gns3/webterm:lastest"
def test_export_with_images(tmpdir, project, async_run):
async def test_export_with_images(tmpdir, project):
"""
Fix absolute image path
"""
@ -312,14 +316,14 @@ def test_export_with_images(tmpdir, project, async_run):
with aiozipstream.ZipFile() as z:
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
async_run(export_project(z, project, str(tmpdir), include_images=True))
async_run(write_file(str(tmpdir / 'zipfile.zip'), z))
await export_project(z, project, str(tmpdir), include_images=True)
await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
myzip.getinfo("images/IOS/test.image")
def test_export_keep_compute_id(tmpdir, project, async_run):
async def test_export_keep_compute_id(tmpdir, project):
"""
If we want to restore the same computes we could ask to keep them
in the file
@ -348,8 +352,8 @@ def test_export_keep_compute_id(tmpdir, project, async_run):
json.dump(data, f)
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir), keep_compute_id=True))
async_run(write_file(str(tmpdir / 'zipfile.zip'), z))
await export_project(z, project, str(tmpdir), keep_compute_id=True)
await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
with myzip.open("project.gns3") as myfile:
@ -358,7 +362,7 @@ def test_export_keep_compute_id(tmpdir, project, async_run):
assert len(topo["computes"]) == 1
def test_export_images_from_vm(tmpdir, project, async_run):
async def test_export_images_from_vm(tmpdir, project):
"""
If data is on a remote server export it locally before
sending it in the archive.
@ -366,22 +370,19 @@ def test_export_images_from_vm(tmpdir, project, async_run):
compute = MagicMock()
compute.id = "vm"
compute.list_files = AsyncioMagicMock(return_value=[
{"path": "vm-1/dynamips/test"}
])
compute.list_files = AsyncioMagicMock(return_value=[{"path": "vm-1/dynamips/test"}])
# Fake file that will be download from the vm
mock_response = AsyncioMagicMock()
mock_response.content = AsyncioBytesIO()
async_run(mock_response.content.write(b"HELLO"))
await mock_response.content.write(b"HELLO")
mock_response.content.seek(0)
mock_response.status = 200
compute.download_file = AsyncioMagicMock(return_value=mock_response)
mock_response = AsyncioMagicMock()
mock_response.content = AsyncioBytesIO()
async_run(mock_response.content.write(b"IMAGE"))
await mock_response.content.write(b"IMAGE")
mock_response.content.seek(0)
mock_response.status = 200
compute.download_image = AsyncioMagicMock(return_value=mock_response)
@ -411,9 +412,9 @@ def test_export_images_from_vm(tmpdir, project, async_run):
f.write(json.dumps(topology))
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir), include_images=True))
await export_project(z, project, str(tmpdir), include_images=True)
assert compute.list_files.called
async_run(write_file(str(tmpdir / 'zipfile.zip'), z))
await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
with myzip.open("vm-1/dynamips/test") as myfile:
@ -425,7 +426,8 @@ def test_export_images_from_vm(tmpdir, project, async_run):
assert content == b"IMAGE"
def test_export_with_ignoring_snapshots(tmpdir, project, async_run):
async def test_export_with_ignoring_snapshots(tmpdir, project):
with open(os.path.join(project.path, "test.gns3"), 'w+') as f:
data = {
"topology": {
@ -454,8 +456,8 @@ def test_export_with_ignoring_snapshots(tmpdir, project, async_run):
Path(os.path.join(snapshots_dir, 'snap.gns3project')).touch()
with aiozipstream.ZipFile() as z:
async_run(export_project(z, project, str(tmpdir), keep_compute_id=True))
async_run(write_file(str(tmpdir / 'zipfile.zip'), z))
await export_project(z, project, str(tmpdir), keep_compute_id=True)
await write_file(str(tmpdir / 'zipfile.zip'), z)
with zipfile.ZipFile(str(tmpdir / 'zipfile.zip')) as myzip:
assert not os.path.join('snapshots', 'snap.gns3project') in [f.filename for f in myzip.filelist]

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -24,6 +24,7 @@ from gns3server.controller.gns3vm.gns3_vm_error import GNS3VMError
@pytest.fixture
def dummy_engine():
engine = AsyncioMagicMock()
engine.running = False
engine.ip_address = "vm.local"
@ -36,6 +37,7 @@ def dummy_engine():
@pytest.fixture
def dummy_gns3vm(controller, dummy_engine):
vm = GNS3VM(controller)
vm._settings["engine"] = "dummy"
vm._settings["vmname"] = "Test VM"
@ -44,46 +46,49 @@ def dummy_gns3vm(controller, dummy_engine):
return vm
def test_list(async_run, controller):
vm = GNS3VM(controller)
async def test_list(controller):
vm = GNS3VM(controller)
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.list", return_value=[{"vmname": "test", "vmx_path": "test"}]):
res = async_run(vm.list("vmware"))
assert res == [{"vmname": "test"}] # Informations specific to vmware are stripped
res = await vm.list("vmware")
assert res == [{"vmname": "test"}] # Information specific to VMware is stripped
with asyncio_patch("gns3server.controller.gns3vm.virtualbox_gns3_vm.VirtualBoxGNS3VM.list", return_value=[{"vmname": "test"}]):
res = async_run(vm.list("virtualbox"))
res = await vm.list("virtualbox")
assert res == [{"vmname": "test"}]
with pytest.raises(NotImplementedError):
async_run(vm.list("hyperv"))
await vm.list("hyperv")
def test_json(controller):
vm = GNS3VM(controller)
assert vm.__json__() == vm._settings
def test_update_settings(controller, async_run):
async def test_update_settings(controller):
vm = GNS3VM(controller)
vm.settings = {
"enable": True,
"engine": "vmware",
"vmname": "GNS3 VM"
}
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.start"):
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network") as mock_check_network:
async_run(vm.auto_start_vm())
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network"):
await vm.auto_start_vm()
assert "vm" in controller.computes
async_run(vm.update_settings({"enable": False}))
await vm.update_settings({"enable": False})
assert "vm" not in controller.computes
def test_auto_start(async_run, controller, dummy_gns3vm, dummy_engine):
async def test_auto_start(controller, dummy_gns3vm, dummy_engine):
"""
When start the compute should be add to the controller
"""
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network") as mock_check_network:
async_run(dummy_gns3vm.auto_start_vm())
with asyncio_patch("gns3server.controller.gns3vm.GNS3VM._check_network"):
await dummy_gns3vm.auto_start_vm()
assert dummy_engine.start.called
assert controller.computes["vm"].name == "GNS3 VM (Test VM)"
assert controller.computes["vm"].host == "vm.local"
@ -93,9 +98,9 @@ def test_auto_start(async_run, controller, dummy_gns3vm, dummy_engine):
assert controller.computes["vm"].password == "world"
def test_auto_start_with_error(async_run, controller, dummy_gns3vm, dummy_engine):
dummy_engine.start.side_effect = GNS3VMError("Dummy error")
async def test_auto_start_with_error(controller, dummy_gns3vm, dummy_engine):
async_run(dummy_gns3vm.auto_start_vm())
dummy_engine.start.side_effect = GNS3VMError("Dummy error")
await dummy_gns3vm.auto_start_vm()
assert dummy_engine.start.called
assert controller.computes["vm"].name == "GNS3 VM (Test VM)"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -20,18 +20,15 @@ import uuid
import json
import zipfile
from tests.utils import asyncio_patch, AsyncioMagicMock
from gns3server.controller.project import Project
from gns3server.controller.import_project import import_project, _move_files_to_compute
from gns3server.version import __version__
def test_import_project(async_run, tmpdir, controller):
project_id = str(uuid.uuid4())
async def test_import_project(tmpdir, controller):
project_id = str(uuid.uuid4())
topology = {
"project_id": str(uuid.uuid4()),
"name": "test",
@ -55,7 +52,7 @@ def test_import_project(async_run, tmpdir, controller):
myzip.write(str(tmpdir / "b.png"), "project-files/qemu/test")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
assert project.name == "test"
assert project.id == project_id
@ -68,19 +65,19 @@ def test_import_project(async_run, tmpdir, controller):
# A new project name is generated when you import twice the same name
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, str(uuid.uuid4()), f))
project = await import_project(controller, str(uuid.uuid4()), f)
assert project.auto_open is False
assert project.auto_start is False
assert project.name != "test"
def test_import_project_override(async_run, tmpdir, controller):
async def test_import_project_override(tmpdir, controller):
"""
In the case of snapshot we will import a project for
override the previous keeping the same project id & location
"""
project_id = str(uuid.uuid4())
project_id = str(uuid.uuid4())
topology = {
"project_id": project_id,
"name": "test",
@ -97,24 +94,24 @@ def test_import_project_override(async_run, tmpdir, controller):
myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f, location=str(tmpdir)))
project = await import_project(controller, project_id, f, location=str(tmpdir))
assert project.name == "test"
assert project.id == project_id
# Overide the project with same project
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f, location=str(tmpdir)))
project = await import_project(controller, project_id, f, location=str(tmpdir))
assert project.id == project_id
assert project.name == "test"
def test_import_upgrade(async_run, tmpdir, controller):
async def test_import_upgrade(tmpdir, controller):
"""
Topology made for previous GNS3 version are upgraded during the process
"""
project_id = str(uuid.uuid4())
project_id = str(uuid.uuid4())
topology = {
"project_id": str(uuid.uuid4()),
"name": "test",
@ -131,17 +128,16 @@ def test_import_upgrade(async_run, tmpdir, controller):
myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
with open(os.path.join(project.path, "test.gns3")) as f:
topo = json.load(f)
assert topo["version"] == __version__
def test_import_with_images(tmpdir, async_run, controller):
async def test_import_with_images(tmpdir, controller):
project_id = str(uuid.uuid4())
topology = {
"project_id": str(uuid.uuid4()),
"name": "test",
@ -162,7 +158,7 @@ def test_import_with_images(tmpdir, async_run, controller):
myzip.write(str(tmpdir / "test.image"), "images/IOS/test.image")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
assert not os.path.exists(os.path.join(project.path, "images/IOS/test.image"))
@ -170,12 +166,12 @@ def test_import_with_images(tmpdir, async_run, controller):
assert os.path.exists(path), path
def test_import_iou_linux_no_vm(linux_platform, async_run, tmpdir, controller):
async def test_import_iou_linux_no_vm(linux_platform, tmpdir, controller):
"""
On non linux host IOU should be local if we don't have a GNS3 VM
"""
project_id = str(uuid.uuid4())
project_id = str(uuid.uuid4())
controller._computes["local"] = AsyncioMagicMock()
topology = {
@ -207,17 +203,18 @@ def test_import_iou_linux_no_vm(linux_platform, async_run, tmpdir, controller):
myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
with open(os.path.join(project.path, "test.gns3")) as f:
topo = json.load(f)
assert topo["topology"]["nodes"][0]["compute_id"] == "local"
def test_import_iou_linux_with_vm(linux_platform, async_run, tmpdir, controller):
async def test_import_iou_linux_with_vm(linux_platform, tmpdir, controller):
"""
On non linux host IOU should be vm if we have a GNS3 VM configured
"""
project_id = str(uuid.uuid4())
controller._computes["vm"] = AsyncioMagicMock()
@ -251,17 +248,18 @@ def test_import_iou_linux_with_vm(linux_platform, async_run, tmpdir, controller)
myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
with open(os.path.join(project.path, "test.gns3")) as f:
topo = json.load(f)
assert topo["topology"]["nodes"][0]["compute_id"] == "vm"
def test_import_nat_non_linux(windows_platform, async_run, tmpdir, controller):
async def test_import_nat_non_linux(windows_platform, tmpdir, controller):
"""
On non linux host NAT should be moved to the GNS3 VM
"""
project_id = str(uuid.uuid4())
controller._computes["vm"] = AsyncioMagicMock()
@ -295,17 +293,18 @@ def test_import_nat_non_linux(windows_platform, async_run, tmpdir, controller):
myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
with open(os.path.join(project.path, "test.gns3")) as f:
topo = json.load(f)
assert topo["topology"]["nodes"][0]["compute_id"] == "vm"
def test_import_iou_non_linux(windows_platform, async_run, tmpdir, controller):
async def test_import_iou_non_linux(windows_platform, tmpdir, controller):
"""
On non linux host IOU should be moved to the GNS3 VM
"""
project_id = str(uuid.uuid4())
controller._computes["vm"] = AsyncioMagicMock()
@ -346,7 +345,7 @@ def test_import_iou_non_linux(windows_platform, async_run, tmpdir, controller):
with open(zip_path, "rb") as f:
with asyncio_patch("gns3server.controller.import_project._move_files_to_compute") as mock:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
controller._computes["vm"].post.assert_called_with('/projects', data={'name': 'test', 'project_id': project_id})
with open(os.path.join(project.path, "test.gns3")) as f:
@ -357,12 +356,12 @@ def test_import_iou_non_linux(windows_platform, async_run, tmpdir, controller):
mock.assert_called_with(controller._computes["vm"], project_id, project.path, os.path.join('project-files', 'iou', topo["topology"]["nodes"][0]['node_id']))
def test_import_node_id(linux_platform, async_run, tmpdir, controller):
async def test_import_node_id(linux_platform, tmpdir, controller):
"""
When importing a node, node_id should change
"""
project_id = str(uuid.uuid4())
project_id = str(uuid.uuid4())
controller._computes["local"] = AsyncioMagicMock()
topology = {
@ -429,7 +428,7 @@ def test_import_node_id(linux_platform, async_run, tmpdir, controller):
myzip.writestr("project-files/iou/c3ae286c-c81f-40d9-a2d0-5874b2f2478d/startup.cfg", "test")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f))
project = await import_project(controller, project_id, f)
with open(os.path.join(project.path, "test.gns3")) as f:
topo = json.load(f)
@ -450,10 +449,11 @@ def test_import_node_id(linux_platform, async_run, tmpdir, controller):
assert os.path.exists(os.path.join(project.path, "project-files", "iou", topo["topology"]["nodes"][0]["node_id"], "startup.cfg"))
def test_import_keep_compute_id(windows_platform, async_run, tmpdir, controller):
async def test_import_keep_compute_id(windows_platform, tmpdir, controller):
"""
On linux host IOU should be moved to the GNS3 VM
"""
project_id = str(uuid.uuid4())
controller._computes["vm"] = AsyncioMagicMock()
@ -487,14 +487,15 @@ def test_import_keep_compute_id(windows_platform, async_run, tmpdir, controller)
myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f, keep_compute_id=True))
project = await import_project(controller, project_id, f, keep_compute_id=True)
with open(os.path.join(project.path, "test.gns3")) as f:
topo = json.load(f)
assert topo["topology"]["nodes"][0]["compute_id"] == "local"
def test_move_files_to_compute(tmpdir, async_run):
async def test_move_files_to_compute(tmpdir):
project_id = str(uuid.uuid4())
os.makedirs(str(tmpdir / "project-files" / "docker"))
@ -502,19 +503,19 @@ def test_move_files_to_compute(tmpdir, async_run):
(tmpdir / "project-files" / "docker" / "test2").open("w").close()
with asyncio_patch("gns3server.controller.import_project._upload_file") as mock:
async_run(_move_files_to_compute(None, project_id, str(tmpdir), os.path.join("project-files", "docker")))
await _move_files_to_compute(None, project_id, str(tmpdir), os.path.join("project-files", "docker"))
mock.assert_any_call(None, project_id, str(tmpdir / "project-files" / "docker" / "test"), os.path.join("project-files", "docker", "test"))
mock.assert_any_call(None, project_id, str(tmpdir / "project-files" / "docker" / "test2"), os.path.join("project-files", "docker", "test2"))
assert not os.path.exists(str(tmpdir / "project-files" / "docker"))
def test_import_project_name_and_location(async_run, tmpdir, controller):
async def test_import_project_name_and_location(tmpdir, controller):
"""
Import a project with a different location and name
"""
project_id = str(uuid.uuid4())
project_id = str(uuid.uuid4())
topology = {
"project_id": str(uuid.uuid4()),
"name": "test",
@ -531,7 +532,7 @@ def test_import_project_name_and_location(async_run, tmpdir, controller):
myzip.write(str(tmpdir / "project.gns3"), "project.gns3")
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, project_id, f, name="hello", location=str(tmpdir / "hello")))
project = await import_project(controller, project_id, f, name="hello", location=str(tmpdir / "hello"))
assert project.name == "hello"
@ -539,5 +540,5 @@ def test_import_project_name_and_location(async_run, tmpdir, controller):
# A new project name is generated when you import twice the same name
with open(zip_path, "rb") as f:
project = async_run(import_project(controller, str(uuid.uuid4()), f, name="hello", location=str(tmpdir / "test")))
project = await import_project(controller, str(uuid.uuid4()), f, name="hello", location=str(tmpdir / "test"))
assert project.name == "hello-1"

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
# Copyright (C) 2020 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -15,35 +15,20 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import pytest
import aiohttp
import asyncio
from unittest.mock import MagicMock
from gns3server.controller.link import Link
from gns3server.controller.node import Node
from gns3server.controller.ports.ethernet_port import EthernetPort
from gns3server.controller.ports.serial_port import SerialPort
from gns3server.controller.compute import Compute
from gns3server.controller.project import Project
from tests.utils import AsyncioBytesIO, AsyncioMagicMock
@pytest.fixture
def project(controller):
return Project(controller=controller, name="Test")
async def link(project, compute):
@pytest.fixture
def compute():
return Compute("example.com", controller=MagicMock())
@pytest.fixture
def link(async_run, project, compute):
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
node2 = Node(project, compute, "node2", node_type="qemu")
@ -51,26 +36,27 @@ def link(async_run, project, compute):
link = Link(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node1, 0, 4))
async_run(link.add_node(node2, 1, 3))
await link.add_node(node1, 0, 4)
await link.add_node(node2, 1, 3)
return link
def test_eq(project, link, controller):
def test_eq(project, link):
assert link == Link(project, link_id=link.id)
assert link != "a"
assert link != Link(project)
def test_add_node(async_run, project, compute):
async def test_add_node(project, compute):
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
link = Link(project)
link.create = AsyncioMagicMock()
link._project.emit_notification = MagicMock()
project.dump = AsyncioMagicMock()
async_run(link.add_node(node1, 0, 4))
await link.add_node(node1, 0, 4)
assert link._nodes == [
{
"node": node1,
@ -85,23 +71,23 @@ def test_add_node(async_run, project, compute):
]
assert project.dump.called
assert not link._project.emit_notification.called
assert not link.create.called
# We call link.created only when both side are created
node2 = Node(project, compute, "node2", node_type="qemu")
node2._ports = [EthernetPort("E0", 0, 0, 4)]
async_run(link.add_node(node2, 0, 4))
await link.add_node(node2, 0, 4)
assert link.create.called
link._project.emit_notification.assert_called_with("link.created", link.__json__())
assert link in node2.links
def test_add_node_already_connected(async_run, project, compute):
async def test_add_node_already_connected(project, compute):
"""
Raise an error if we try to use an already connected port
"""
project.dump = AsyncioMagicMock()
node1 = Node(project, compute, "node1", node_type="qemu")
@ -110,19 +96,20 @@ def test_add_node_already_connected(async_run, project, compute):
link = Link(project)
link.create = AsyncioMagicMock()
link._project.emit_notification = MagicMock()
async_run(link.add_node(node1, 0, 4))
await link.add_node(node1, 0, 4)
node2 = Node(project, compute, "node2", node_type="qemu")
node2._ports = [EthernetPort("E0", 0, 0, 4)]
async_run(link.add_node(node2, 0, 4))
await link.add_node(node2, 0, 4)
assert link.create.called
link2 = Link(project)
link2.create = AsyncioMagicMock()
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(link2.add_node(node1, 0, 4))
await link2.add_node(node1, 0, 4)
def test_add_node_cloud(async_run, project, compute):
async def test_add_node_cloud(project, compute):
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
node2 = Node(project, compute, "node2", node_type="cloud")
@ -132,14 +119,15 @@ def test_add_node_cloud(async_run, project, compute):
link.create = AsyncioMagicMock()
link._project.emit_notification = MagicMock()
async_run(link.add_node(node1, 0, 4))
async_run(link.add_node(node2, 0, 4))
await link.add_node(node1, 0, 4)
await link.add_node(node2, 0, 4)
def test_add_node_cloud_to_cloud(async_run, project, compute):
async def test_add_node_cloud_to_cloud(project, compute):
"""
Cloud to cloud connection is not allowed
"""
node1 = Node(project, compute, "node1", node_type="cloud")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
node2 = Node(project, compute, "node2", node_type="cloud")
@ -149,15 +137,16 @@ def test_add_node_cloud_to_cloud(async_run, project, compute):
link.create = AsyncioMagicMock()
link._project.emit_notification = MagicMock()
async_run(link.add_node(node1, 0, 4))
await link.add_node(node1, 0, 4)
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(link.add_node(node2, 0, 4))
await link.add_node(node2, 0, 4)
def test_add_node_same_node(async_run, project, compute):
async def test_add_node_same_node(project, compute):
"""
Connection to the same node is not allowed
"""
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4), EthernetPort("E1", 0, 0, 5)]
@ -165,15 +154,16 @@ def test_add_node_same_node(async_run, project, compute):
link.create = AsyncioMagicMock()
link._project.emit_notification = MagicMock()
async_run(link.add_node(node1, 0, 4))
await link.add_node(node1, 0, 4)
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(link.add_node(node1, 0, 5))
await link.add_node(node1, 0, 5)
def test_add_node_serial_to_ethernet(async_run, project, compute):
async def test_add_node_serial_to_ethernet(project, compute):
"""
Serial to ethernet connection is not allowed
"""
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
node2 = Node(project, compute, "node2", node_type="qemu")
@ -183,12 +173,13 @@ def test_add_node_serial_to_ethernet(async_run, project, compute):
link.create = AsyncioMagicMock()
link._project.emit_notification = MagicMock()
async_run(link.add_node(node1, 0, 4))
await link.add_node(node1, 0, 4)
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(link.add_node(node2, 0, 4))
await link.add_node(node2, 0, 4)
def test_json(async_run, project, compute, link):
async def test_json(project, compute):
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
node2 = Node(project, compute, "node2", node_type="qemu")
@ -196,8 +187,8 @@ def test_json(async_run, project, compute, link):
link = Link(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node1, 0, 4))
async_run(link.add_node(node2, 1, 3))
await link.add_node(node1, 0, 4)
await link.add_node(node2, 1, 3)
assert link.__json__() == {
"link_id": link.id,
"project_id": project.id,
@ -256,7 +247,8 @@ def test_json(async_run, project, compute, link):
}
def test_json_serial_link(async_run, project, compute, link):
async def test_json_serial_link(project, compute):
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [SerialPort("S0", 0, 0, 4)]
node2 = Node(project, compute, "node2", node_type="qemu")
@ -264,11 +256,13 @@ def test_json_serial_link(async_run, project, compute, link):
link = Link(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node1, 0, 4))
async_run(link.add_node(node2, 1, 3))
await link.add_node(node1, 0, 4)
await link.add_node(node2, 1, 3)
assert link.__json__()["link_type"] == "serial"
def test_default_capture_file_name(project, compute, async_run):
async def test_default_capture_file_name(project, compute):
node1 = Node(project, compute, "Hello@", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
node2 = Node(project, compute, "w0.rld