Refactor tests

* Use pytest-aiohttp
* Use the async def / await syntax.
* Fix tests to run with Python 3.8
pull/1781/head
grossmj 4 years ago
parent f498ab06b4
commit d3ea67da24

@ -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

@ -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([

@ -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"
}
]
}
}

@ -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()
async def test_docker_check_connection_docker_preferred_version_against_newer(vm):
def test_docker_check_connection_docker_preferred_version_against_newer(vm, loop):
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

@ -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()

@ -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"

@ -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 = {}

@ -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 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):
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value="") as mock:
async def test_library_check(vm):
loop.run_until_complete(asyncio.ensure_future(vm._library_check()))
with asyncio_patch("gns3server.utils.asyncio.subprocess_check_output", return_value=""):
await 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

@ -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")

@ -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 == []

@ -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", "")

@ -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 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\"")

@ -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
async def test_create_twice_same_node_new_topology(compute_project, vpcs):
def test_create_twice_same_node_new_topology(loop, project, vpcs):
project._nodes = set()
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() == []
async def test_delete_node(vpcs, compute_project):
def test_delete_node(async_run, vpcs, project):
project._nodes = set()
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)

@ -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

@ -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"

@ -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)
async def test_affect_uuid():
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

@ -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')

@ -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

@ -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}

@ -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(compute_project, manager):
def test_vm(project, manager):
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)
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()
async def test_vm_invalid_virtualbox_api_version(compute_project, manager):
def test_vm_invalid_virtualbox_api_version(loop, 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>
"""

@ -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"')

@ -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", compute_project, manager, fake_vmx, False)
return VMwareVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager, fake_vmx, False)
def test_vm(vm):
def test_vm(project, manager, 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

@ -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

@ -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

@ -1,267 +1,108 @@
# -*- 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
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.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
from gns3server.controller import Controller
from tests.handlers.api.base import Query
# this import will register all handlers
from gns3server.handlers import *
from .handlers.api.base import Query
@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
sys._called_from_test = True
sys.original_platform = sys.platform
@pytest.fixture
async def client(aiohttp_client):
"""
Return an helper allowing you to call the server without any prefix
"""
@pytest.fixture(scope='function')
async def http_client(aiohttp_client):
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()
@pytest.fixture
def controller_config_path(tmpdir):
host = "127.0.0.1"
return str(tmpdir / "config" / "gns3_controller.conf")
# 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
@pytest.fixture
def controller(tmpdir, controller_config_path):
yield (host, port)
Controller._instance = None
controller = Controller.instance()
os.makedirs(os.path.dirname(controller_config_path), exist_ok=True)
Path(controller_config_path).touch()
controller._config_file = controller_config_path
controller._config_loaded = True
return controller
# 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())
@pytest.fixture
def compute(controller):
loop.run_until_complete(runner.cleanup())
compute = MagicMock()
compute.id = "example.com"
controller._computes = {"example.com": compute}
return compute
@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)
async def project(loop, tmpdir, controller):
return await controller.add_project(name="Test")
@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)
def compute_project(tmpdir):
return ProjectManager.instance().create_project(project_id="a1e920ca-338a-4e9f-b363-aa607b09dd80")
@pytest.fixture
def http_compute(loop, http_server):
def compute_api(http_client):
"""
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
return Query(http_client, prefix="/compute", api_version=2)
@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")
def controller_api(http_client, controller):
"""
Return an helper allowing you to call the server API without any prefix
"""
@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)
Path(controller_config_path).touch()
controller._config_file = controller_config_path
controller._config_loaded = True
return controller
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):
"""
This setup a temporay project file environnement around tests
"""
tmppath = tempfile.mkdtemp()
for module in MODULES:
module._instance = None
os.makedirs(os.path.join(tmppath, 'projects'))
config.set("Server", "projects_path", os.path.join(tmppath, 'projects'))
config.set("Server", "symbols_path", os.path.join(tmppath, 'symbols'))
config.set("Server", "images_path", os.path.join(tmppath, 'images'))
config.set("Server", "appliances_path", os.path.join(tmppath, 'appliances'))
config.set("Server", "ubridge_path", os.path.join(tmppath, 'bin', 'ubridge'))
config.set("Server", "auth", False)
# Prevent executions of the VM if we forgot to mock something
config.set("VirtualBox", "vboxmanage_path", tmppath)
config.set("VPCS", "vpcs_path", tmppath)
config.set("VMware", "vmrun_path", tmppath)
config.set("Dynamips", "dynamips_path", tmppath)
# Force turn off KVM because it's not available on CI
config.set("Qemu", "enable_kvm", False)
monkeypatch.setattr("gns3server.utils.path.get_default_project_directory", lambda *args: os.path.join(tmppath, 'projects'))
# Force sys.platform to the original value. Because it seem not be restore correctly at each tests
sys.platform = sys.original_platform
yield
# An helper should not raise Exception
try:
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"))
@ -274,6 +115,7 @@ 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)
@ -285,49 +127,64 @@ 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.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.yield_fixture
@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.yield_fixture
@pytest.fixture
def windows_platform():
"""
Change sys.platform to Windows
"""
old_platform = sys.platform
sys.platform = "win10"
yield
sys.plaform = old_platform
@pytest.yield_fixture
@pytest.fixture
def linux_platform():
"""
Change sys.platform to Linux
"""
old_platform = sys.platform
sys.platform = "linuxdebian"
yield
@ -335,21 +192,75 @@ def linux_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
@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()
for module in MODULES:
module._instance = None
os.makedirs(os.path.join(tmppath, 'projects'))
config.set("Server", "projects_path", os.path.join(tmppath, 'projects'))
config.set("Server", "symbols_path", os.path.join(tmppath, 'symbols'))
config.set("Server", "images_path", os.path.join(tmppath, 'images'))
config.set("Server", "appliances_path", os.path.join(tmppath, 'appliances'))
config.set("Server", "ubridge_path", os.path.join(tmppath, 'bin', 'ubridge'))
config.set("Server", "auth", False)
# Prevent executions of the VM if we forgot to mock something
config.set("VirtualBox", "vboxmanage_path", tmppath)
config.set("VPCS", "vpcs_path", tmppath)
config.set("VMware", "vmrun_path", tmppath)
config.set("Dynamips", "dynamips_path", tmppath)
# Force turn off KVM because it's not available on CI
config.set("Qemu", "enable_kvm", False)
monkeypatch.setattr("gns3server.utils.path.get_default_project_directory", lambda *args: os.path.join(tmppath, 'projects'))
# Force sys.platform to the original value. Because it seem not be restore correctly at each tests
sys.platform = sys.original_platform
yield
# An helper should not raise Exception
try:
shutil.rmtree(tmppath)
except BaseException:
pass

@ -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

@ -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

@ -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")
async def test_set_extra_options(loop, gns3vm, vmx_path, windows_platform):
def test_set_extra_options(gns3vm, async_run, tmx_path):
gns3vm._vmx_path = tmx_path
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'

@ -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)
# 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()
# 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()
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_httpQueryNotConnectedInvalidVersion(compute):
def test_compute_httpQueryNotConnectedInvalidVersion(compute, async_run):
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()
async def test_close(compute):
def test_close(compute, async_run):
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')

@ -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):
uuid1 = str(uuid.uuid4())
async def test_remove_project(controller):
project1 = async_run(controller.add_project(project_id=uuid1, name="Test"))
uuid1 = str(uuid.uuid4())
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}
await controller.add_project(project_id=uuid1, name="Test")
project1 = async_run(controller.add_project(project_id=uuid1, name="Test"))
async def test_getProject(controller):
def test_getProject(controller, async_run):
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

@ -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):

@ -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]

@ -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)"

@ -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"

@ -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)
async def test_add_node_cloud(project, compute):
def test_add_node_cloud(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="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)
async def test_json(project, compute):
def test_json(async_run, project, compute, link):
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", node_type="qemu")
@ -276,33 +270,35 @@ def test_default_capture_file_name(project, compute, async_run):
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.default_capture_file_name() == "Hello_0-4_to_w0rld_1-3.pcap"
def test_start_capture(link, async_run, tmpdir):
async def test_start_capture(link):
async def fake_reader():
return AsyncioBytesIO()
link.read_pcap_from_source = fake_reader
link._project.emit_notification = MagicMock()
async_run(link.start_capture(capture_file_name="test.pcap"))
await link.start_capture(capture_file_name="test.pcap")
assert link._capturing
assert link._capture_file_name == "test.pcap"
link._project.emit_notification.assert_called_with("link.updated", link.__json__())
def test_stop_capture(link, async_run, tmpdir):
async def test_stop_capture(link):
link._capturing = True
link._project.emit_notification = MagicMock()
async_run(link.stop_capture())
await link.stop_capture()
assert link._capturing is False
link._project.emit_notification.assert_called_with("link.updated", link.__json__())
def test_delete(async_run, project, compute):
async def test_delete(project, compute):
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
@ -310,19 +306,18 @@ def test_delete(async_run, project, compute):
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)
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 in node2.links
async_run(link.delete())
await link.delete()
assert link not in node2.links
def test_update_filters(async_run, project, compute):
async def test_update_filters(project, compute):
node1 = Node(project, compute, "node1", node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
@ -330,20 +325,20 @@ def test_update_filters(async_run, project, compute):
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)
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)
link.update = AsyncioMagicMock()
assert link._created
async_run(link.update_filters({
await link.update_filters({
"packet_loss": [10],
"delay": [50, 10],
"frequency_drop": [0],
"bpf": [" \n "]
}))
})
assert link.filters == {
"packet_loss": [10],
"delay": [50, 10]
@ -351,7 +346,8 @@ def test_update_filters(async_run, project, compute):
assert link.update.called
def test_available_filters(async_run, project, compute):
async def test_available_filters(project, compute):
node1 = Node(project, compute, "node1", node_type="ethernet_switch")
node1._ports = [EthernetPort("E0", 0, 0, 4)]
@ -360,10 +356,10 @@ def test_available_filters(async_run, project, compute):
assert link.available_filters() == []
# Ethernet switch is not supported should return 0 filters
async_run(link.add_node(node1, 0, 4))
await link.add_node(node1, 0, 4)
assert link.available_filters() == []
node2 = Node(project, compute, "node2", node_type="vpcs")
node2._ports = [EthernetPort("E0", 0, 0, 4)]
async_run(link.add_node(node2, 0, 4))
await link.add_node(node2, 0, 4)
assert len(link.available_filters()) > 0

@ -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,15 +16,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import shutil
import aiohttp
import pytest
import uuid
import asyncio
import copy
import os
from unittest.mock import MagicMock, ANY
from unittest.mock import MagicMock, ANY
from tests.utils import AsyncioMagicMock
from gns3server.controller.node import Node
@ -33,18 +29,15 @@ from gns3server.controller.project import Project
@pytest.fixture
def compute():
s = AsyncioMagicMock()
s.id = "http://test.com:42"
return s
@pytest.fixture
def project(controller):
return Project(str(uuid.uuid4()), controller=controller)
@pytest.fixture
def node(compute, project):
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="vpcs",
@ -57,6 +50,7 @@ def test_name(compute, project):
"""
If node use a name template generate names
"""
node = Node(project, compute, "PC",
node_id=str(uuid.uuid4()),
node_type="vpcs",
@ -76,16 +70,13 @@ def test_name(compute, project):
properties={"startup_script": "echo test"})
assert node.name == "PC2"
# If we change the name to a name already used we patch the name to a free
node.name == "PC1"
assert node.name == "PC2"
def test_vmname(compute, project):
"""
Additionnal properties should be add to the properties
field
"""
node = Node(project, compute, "PC",
node_id=str(uuid.uuid4()),
node_type="virtualbox",
@ -111,6 +102,7 @@ def test_empty_properties(compute, project):
def test_eq(compute, project, node, controller):
assert node == Node(project, compute, "demo1", node_id=node.id, node_type="qemu")
assert node != "a"
assert node != Node(project, compute, "demo2", node_id=str(uuid.uuid4()), node_type="qemu")
@ -118,6 +110,7 @@ def test_eq(compute, project, node, controller):
def test_json(node, compute):
assert node.__json__() == {
"compute_id": str(compute.id),
"project_id": node.project.id,
@ -156,6 +149,7 @@ def test_json(node, compute):
}
]
}
assert node.__json__(topology_dump=True) == {
"compute_id": str(compute.id),
"node_id": node.id,
@ -188,14 +182,14 @@ def test_init_without_uuid(project, compute):
assert node.id is not None
def test_create(node, compute, project, async_run):
node._console = 2048
async def test_create(node, compute):
node._console = 2048
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
assert async_run(node.create()) is True
assert await node.create() is True
data = {
"console": 2048,
"console_type": "vnc",
@ -208,9 +202,9 @@ def test_create(node, compute, project, async_run):
assert node._properties == {"startup_script": "echo test"}
def test_create_image_missing(node, compute, project, async_run):
node._console = 2048
async def test_create_image_missing(node, compute):
node._console = 2048
node.__calls = 0
async def resp(*args, **kwargs):
@ -226,13 +220,13 @@ def test_create_image_missing(node, compute, project, async_run):
compute.post = AsyncioMagicMock(side_effect=resp)
node._upload_missing_image = AsyncioMagicMock(return_value=True)
assert async_run(node.create()) is True
node._upload_missing_image.called is True
assert await node.create() is True
#assert node._upload_missing_image.called is True
def test_create_base_script(node, config, compute, tmpdir, async_run):
config.set_section_config("Server", {"configs_path": str(tmpdir)})
async def test_create_base_script(node, config, compute, tmpdir):
config.set_section_config("Server", {"configs_path": str(tmpdir)})
with open(str(tmpdir / 'test.txt'), 'w+') as f:
f.write('hostname test')
@ -243,7 +237,7 @@ def test_create_base_script(node, config, compute, tmpdir, async_run):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
assert async_run(node.create()) is True
assert await node.create() is True
data = {
"console": 2048,
"console_type": "vnc",
@ -251,10 +245,11 @@ def test_create_base_script(node, config, compute, tmpdir, async_run):
"startup_script": "hostname test",
"name": "demo"
}
compute.post.assert_called_with("/projects/{}/vpcs/nodes".format(node.project.id), data=data, timeout=1200)
def test_symbol(node, symbols_dir, controller):
def test_symbol(node, symbols_dir):
"""
Change symbol should change the node size
"""
@ -304,14 +299,15 @@ def test_label_with_default_label_font(node):
assert node.label["style"] == None #"font-family: TypeWriter;font-size: 10;font-weight: bold;fill: #ff0000;fill-opacity: 1.0;"
def test_update(node, compute, project, async_run, controller):
async def test_update(node, compute, project, controller):
response = MagicMock()
response.json = {"console": 2048}
compute.put = AsyncioMagicMock(return_value=response)
controller._notification = AsyncioMagicMock()
project.dump = MagicMock()
async_run(node.update(x=42, console=2048, console_type="vnc", properties={"startup_script": "echo test"}, name="demo"))
await node.update(x=42, console=2048, console_type="vnc", properties={"startup_script": "echo test"}, name="demo")
data = {
"console": 2048,
"console_type": "vnc",
@ -326,7 +322,7 @@ def test_update(node, compute, project, async_run, controller):
assert project.dump.called
def test_update_properties(node, compute, project, async_run, controller):
async def test_update_properties(node, compute, controller):
"""
properties will be updated by the answer from compute
"""
@ -335,7 +331,7 @@ def test_update_properties(node, compute, project, async_run, controller):
compute.put = AsyncioMagicMock(return_value=response)
controller._notification = AsyncioMagicMock()
async_run(node.update(x=42, console=2048, console_type="vnc", properties={"startup_script": "hello world"}, name="demo"))
await node.update(x=42, console=2048, console_type="vnc", properties={"startup_script": "hello world"}, name="demo")
data = {
"console": 2048,
"console_type": "vnc",
@ -354,26 +350,27 @@ def test_update_properties(node, compute, project, async_run, controller):
#controller._notification.emit.assert_called_with("node.updated", node_notif)
def test_update_only_controller(node, controller, compute, async_run):
async def test_update_only_controller(node, compute):
"""
When updating property used only on controller we don't need to
call the compute
"""
compute.put = AsyncioMagicMock()
node._project.emit_notification = AsyncioMagicMock()
async_run(node.update(x=42))
await node.update(x=42)
assert not compute.put.called
assert node.x == 42
node._project.emit_notification.assert_called_with("node.updated", node.__json__())
# If nothing change a second notif should not be send
# If nothing change a second notif should not be sent
node._project.emit_notification = AsyncioMagicMock()
async_run(node.update(x=42))
await node.update(x=42)
assert not node._project.emit_notification.called
def test_update_no_changes(node, compute, project, async_run):
async def test_update_no_changes(node, compute):
"""
We don't call the compute node if all compute properties has not changed
"""
@ -381,24 +378,25 @@ def test_update_no_changes(node, compute, project, async_run):
response.json = {"console": 2048}
compute.put = AsyncioMagicMock(return_value=response)
async_run(node.update(console=2048, x=42))
await node.update(console=2048, x=42)
assert compute.put.called
compute.put = AsyncioMagicMock()
async_run(node.update(console=2048, x=43))
await node.update(console=2048, x=43)
assert not compute.put.called
assert node.x == 43
def test_start(node, compute, project, async_run):
async def test_start(node, compute):
compute.post = AsyncioMagicMock()
async_run(node.start())
await node.start()
compute.post.assert_called_with("/projects/{}/vpcs/nodes/{}/start".format(node.project.id, node.id), timeout=240)
def test_start_iou(compute, project, async_run, controller):
async def test_start_iou(compute, project, controller):
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="iou")
@ -409,44 +407,42 @@ def test_start_iou(compute, project, async_run, controller):
# async_run(node.start())
controller._iou_license_settings = {"license_check": True, "iourc_content": "aa"}
async_run(node.start())
await node.start()
compute.post.assert_called_with("/projects/{}/iou/nodes/{}/start".format(node.project.id, node.id), timeout=240, data={"license_check": True, "iourc_content": "aa"})
def test_stop(node, compute, project, async_run):
async def test_stop(node, compute):
compute.post = AsyncioMagicMock()
async_run(node.stop())
await node.stop()
compute.post.assert_called_with("/projects/{}/vpcs/nodes/{}/stop".format(node.project.id, node.id), timeout=240, dont_connect=True)
def test_suspend(node, compute, project, async_run):
async def test_suspend(node, compute):
compute.post = AsyncioMagicMock()
async_run(node.suspend())
await node.suspend()
compute.post.assert_called_with("/projects/{}/vpcs/nodes/{}/suspend".format(node.project.id, node.id), timeout=240)
def test_reload(node, compute, project, async_run):
async def test_reload(node, compute):
compute.post = AsyncioMagicMock()
async_run(node.reload())
await node.reload()
compute.post.assert_called_with("/projects/{}/vpcs/nodes/{}/reload".format(node.project.id, node.id), timeout=240)
def test_create_without_console(node, compute, project, async_run):
async def test_create_without_console(node, compute):
"""
None properties should be send. Because it can mean the emulator doesn"t support it
None properties should be send. Because it can mean the emulator doesn't support it
"""
response = MagicMock()
response.json = {"console": 2048, "test_value": "success"}
compute.post = AsyncioMagicMock(return_value=response)
async_run(node.create())
await node.create()
data = {
"console_type": "vnc",
"node_id": node.id,
@ -458,49 +454,53 @@ def test_create_without_console(node, compute, project, async_run):
assert node._properties == {"test_value": "success", "startup_script": "echo test"}
def test_delete(node, compute, async_run):
async_run(node.destroy())
async def test_delete(node, compute):
await node.destroy()
compute.delete.assert_called_with("/projects/{}/vpcs/nodes/{}".format(node.project.id, node.id))
def test_post(node, compute, async_run):
async_run(node.post("/test", {"a": "b"}))
async def test_post(node, compute):
await node.post("/test", {"a": "b"})
compute.post.assert_called_with("/projects/{}/vpcs/nodes/{}/test".format(node.project.id, node.id), data={"a": "b"})
def test_delete(node, compute, async_run):
async_run(node.delete("/test"))
async def test_delete(node, compute):
await node.delete("/test")
compute.delete.assert_called_with("/projects/{}/vpcs/nodes/{}/test".format(node.project.id, node.id))
def test_dynamips_idle_pc(node, async_run, compute):
async def test_dynamips_idle_pc(node, compute):
node._node_type = "dynamips"
response = MagicMock()
response.json = {"idlepc": "0x60606f54"}
compute.get = AsyncioMagicMock(return_value=response)
async_run(node.dynamips_auto_idlepc())
await node.dynamips_auto_idlepc()
compute.get.assert_called_with("/projects/{}/dynamips/nodes/{}/auto_idlepc".format(node.project.id, node.id), timeout=240)
def test_dynamips_idlepc_proposals(node, async_run, compute):
async def test_dynamips_idlepc_proposals(node, compute):
node._node_type = "dynamips"
response = MagicMock()
response.json = ["0x60606f54", "0x30ff6f37"]
compute.get = AsyncioMagicMock(return_value=response)
async_run(node.dynamips_idlepc_proposals())
await node.dynamips_idlepc_proposals()
compute.get.assert_called_with("/projects/{}/dynamips/nodes/{}/idlepc_proposals".format(node.project.id, node.id), timeout=240)
def test_upload_missing_image(compute, controller, async_run, images_dir):
async def test_upload_missing_image(compute, controller, images_dir):
project = Project(str(uuid.uuid4()), controller=controller)
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="qemu",
properties={"hda_disk_image": "linux.img"})
open(os.path.join(images_dir, "linux.img"), 'w+').close()
assert async_run(node._upload_missing_image("qemu", "linux.img")) is True
assert await node._upload_missing_image("qemu", "linux.img") is True
compute.post.assert_called_with("/qemu/images/linux.img", data=ANY, timeout=None)
@ -509,6 +509,7 @@ def test_update_label(node):
The text in label need to be always the
node name
"""
node.name = "Test"
assert node.label["text"] == "Test"
node.label = {"text": "Wrong", "x": 12}
@ -517,6 +518,7 @@ def test_update_label(node):
def test_get_port(node):
node._node_type = "qemu"
node._properties["adapters"] = 2
node._list_ports()
@ -529,12 +531,13 @@ def test_get_port(node):
assert port is None
def test_parse_node_response(node, async_run):
async def test_parse_node_response(node):
"""
When a node is updated we notify the links connected to it
"""
link = MagicMock()
link.node_updated = AsyncioMagicMock()
node.add_link(link)
async_run(node.parse_node_response({"status": "started"}))
await node.parse_node_response({"status": "started"})
assert link.node_updated.called

@ -21,7 +21,6 @@ import uuid
from tests.utils import AsyncioMagicMock
from gns3server.controller.node import Node
from gns3server.controller.project import Project
from gns3server.controller.ports.ethernet_port import EthernetPort
@ -31,12 +30,6 @@ def compute():
s.id = "http://test.com:42"
return s
@pytest.fixture
def project(controller):
return Project(str(uuid.uuid4()), controller=controller)
@pytest.fixture
def node(compute, project):
node = Node(project, compute, "demo",
@ -51,6 +44,7 @@ def test_list_ports(node):
"""
List port by default
"""
assert node.__json__()["ports"] == [
{
"name": "Ethernet0",
@ -67,6 +61,7 @@ def test_list_ports_vpcs(node):
"""
List port by default
"""
node._node_type = "vpcs"
assert node.__json__()["ports"] == [
{
@ -84,6 +79,7 @@ def test_list_ports_docker(node):
"""
List port by default
"""
node._node_type = "docker"
node._properties["adapters"] = 2
assert node.__json__()["ports"] == [
@ -110,6 +106,7 @@ def test_list_ports_port_name_format(node):
"""
Support port name format
"""
node._first_port_name = None
node._port_name_format = "eth{}"
node._list_ports()
@ -139,6 +136,7 @@ def test_list_ports_adapters(node):
"""
List port using adapters properties
"""
node.properties["adapters"] = 2
assert node.__json__()["ports"] == [
{
@ -164,6 +162,7 @@ def test_list_ports_adapters_cloud(project, compute):
"""
List port using adapters properties
"""
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="cloud")
@ -192,6 +191,7 @@ def test_list_ports_ethernet_hub(project, compute):
"""
List port for atm switch
"""
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="ethernet_hub")
@ -230,6 +230,7 @@ def test_list_ports_atm_switch(project, compute):
"""
List port for atm switch
"""
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="atm_switch")
@ -261,6 +262,7 @@ def test_list_ports_frame_relay_switch(project, compute):
"""
List port for frame relay switch
"""
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="frame_relay_switch")
@ -309,6 +311,7 @@ def test_list_ports_iou(compute, project):
"""
IOU has a special behavior 4 port by adapters
"""
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="iou")
@ -514,6 +517,7 @@ def test_list_ports_dynamips(project, compute):
"""
List port for dynamips
"""
node = Node(project, compute, "demo",
node_id=str(uuid.uuid4()),
node_type="dynamips")
@ -595,6 +599,7 @@ def test_list_ports_dynamips(project, compute):
def test_short_name():
# If no customization of port name format return the default short name
assert EthernetPort("Ethernet0", 0, 0, 0).short_name == "e0"
assert EthernetPort("Ethernet0", 0, 0, 0, short_name="mgmt").short_name == "mgmt"

@ -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,81 +18,78 @@
import pytest
from unittest.mock import MagicMock
from gns3server.controller.notification import Notification
from gns3server.controller import Controller
from tests.utils import AsyncioMagicMock
@pytest.fixture
def project(async_run):
return async_run(Controller.instance().add_project(name="Test"))
async def node(project):
@pytest.fixture
def node(project, async_run):
compute = MagicMock()
compute.id = "remote1"
compute.host = "example.org"
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
return await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
return async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
def test_emit_to_all(async_run, controller, project):
async def test_emit_to_all(controller, project):
"""
Send an event to all if we don't have a project id in the event
"""
notif = controller.notification
with notif.project_queue(project.id) as queue:
assert len(notif._project_listeners[project.id]) == 1
async_run(queue.get(0.1)) # ping
await queue.get(0.1) # ping
notif.project_emit('test', {})
msg = async_run(queue.get(5))
msg = await queue.get(5)
assert msg == ('test', {}, {})
assert len(notif._project_listeners[project.id]) == 0
def test_emit_to_project(async_run, controller, project):
async def test_emit_to_project(controller, project):
"""
Send an event to a project listeners
"""
notif = controller.notification
with notif.project_queue(project.id) as queue:
assert len(notif._project_listeners[project.id]) == 1
async_run(queue.get(0.1)) # ping
await queue.get(0.1) # ping
# This event has not listener
notif.project_emit('ignore', {"project_id": 42})
notif.project_emit('test', {"project_id": project.id})
msg = async_run(queue.get(5))
msg = await queue.get(5)
assert msg == ('test', {"project_id": project.id}, {})
assert len(notif._project_listeners[project.id]) == 0
def test_dispatch(async_run, controller, project):
async def test_dispatch(controller, project):
notif = controller.notification
with notif.project_queue(project.id) as queue:
assert len(notif._project_listeners[project.id]) == 1
async_run(queue.get(0.1)) # ping
async_run(notif.dispatch("test", {}, project_id=project.id, compute_id=1))
msg = async_run(queue.get(5))
await queue.get(0.1) # ping
await notif.dispatch("test", {}, project_id=project.id, compute_id=1)
msg = await queue.get(5)
assert msg == ('test', {}, {})
def test_dispatch_ping(async_run, controller, project):
async def test_dispatch_ping(controller, project):
notif = controller.notification
with notif.project_queue(project.id) as queue:
assert len(notif._project_listeners[project.id]) == 1
async_run(queue.get(0.1)) # ping
async_run(notif.dispatch("ping", {}, project_id=project.id, compute_id=12))
msg = async_run(queue.get(5))
await queue.get(0.1) # ping
await notif.dispatch("ping", {}, project_id=project.id, compute_id=12)
msg = await queue.get(5)
assert msg == ('ping', {'compute_id': 12}, {})
def test_dispatch_node_updated(async_run, controller, node, project):
async def test_dispatch_node_updated(controller, node, project):
"""
When we receive a node.updated notification from compute
we need to update the client
@ -101,25 +98,26 @@ def test_dispatch_node_updated(async_run, controller, node, project):
notif = controller.notification
with notif.project_queue(project.id) as queue:
assert len(notif._project_listeners[project.id]) == 1
async_run(queue.get(0.1)) # ping
async_run(notif.dispatch("node.updated", {
await queue.get(0.1) # ping
await notif.dispatch("node.updated", {
"node_id": node.id,
"project_id": project.id,
"name": "hello",
"startup_config": "ip 192"
},
project_id=project.id,
compute_id=1))
compute_id=1)
assert node.name == "hello"
action, event, _ = async_run(queue.get(5))
action, event, _ = await queue.get(5)
assert action == "node.updated"
assert event["name"] == "hello"
assert event["properties"]["startup_config"] == "ip 192"
def test_various_notification(controller, node):
notif = controller.notification
notif.project_emit("log.info", {"message": "Image uploaded"})
notif.project_emit("log.warning", {"message": "Warning ASA 8 is not officialy supported by GNS3"})
notif.project_emit("log.warning", {"message": "Warning ASA 8 is not officially supported by GNS3"})
notif.project_emit("log.error", {"message": "Permission denied on /tmp"})
notif.project_emit("node.updated", node.__json__())

@ -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
@ -34,33 +34,29 @@ from gns3server.config import Config
@pytest.fixture
def project(controller):
return Project(controller=controller, name="Test")
async def node(controller, project):
@pytest.fixture
def node(controller, project, async_run):
compute = MagicMock()
compute.id = "local"
response = MagicMock()
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
def test_affect_uuid():
async def test_affect_uuid():
p = Project(name="Test")
assert len(p.id) == 36
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test 2")
assert p.id == '00010203-0405-0607-0809-0a0b0c0d0e0f'
def test_json(tmpdir):
async def test_json():
p = Project(name="Test")
assert p.__json__() == {
"name": "Test",
"project_id": p.id,
@ -84,34 +80,31 @@ def test_json(tmpdir):
}
def test_update(controller, async_run):
async def test_update(controller):
project = Project(controller=controller, name="Hello")
project.emit_notification = MagicMock()
assert project.name == "Hello"
async_run(project.update(name="World"))
await project.update(name="World")
assert project.name == "World"
project.emit_notification.assert_any_call("project.updated", project.__json__())
def test_update_on_compute(controller, async_run):
async def test_update_on_compute(controller):
variables = [{"name": "TEST", "value": "VAL1"}]
compute = MagicMock()
compute.id = "local"
project = Project(controller=controller, name="Test")
project._project_created_on_compute = [compute]
project.emit_notification = MagicMock()
await project.update(variables=variables)
compute.put.assert_any_call('/projects/{}'.format(project.id), {"variables": variables})
async_run(project.update(variables=variables))
compute.put.assert_any_call('/projects/{}'.format(project.id), {
"variables": variables
})
async def test_path(projects_dir):
def test_path(tmpdir):
directory = Config.instance().get_section_config("Server").get("projects_path")
directory = projects_dir
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
p = Project(project_id=str(uuid4()), name="Test")
assert p.path == os.path.join(directory, p.id)
@ -120,37 +113,41 @@ def test_path(tmpdir):
def test_path_exist(tmpdir):
"""
Should raise an error when you try to owerwrite
Should raise an error when you try to overwrite
an existing project
"""
os.makedirs(str(tmpdir / "demo"))
with pytest.raises(aiohttp.web.HTTPForbidden):
p = Project(name="Test", path=str(tmpdir / "demo"))
Project(name="Test", path=str(tmpdir / "demo"))
def test_init_path(tmpdir):
async def test_init_path(tmpdir):
p = Project(path=str(tmpdir), project_id=str(uuid4()), name="Test")
assert p.path == str(tmpdir)
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_changing_path_with_quote_not_allowed(tmpdir):
async def test_changing_path_with_quote_not_allowed(tmpdir):
with pytest.raises(aiohttp.web.HTTPForbidden):
p = Project(project_id=str(uuid4()), name="Test")
p.path = str(tmpdir / "project\"53")
def test_captures_directory(tmpdir):
async def test_captures_directory(tmpdir):
p = Project(path=str(tmpdir / "capturestest"), name="Test")
assert p.captures_directory == str(tmpdir / "capturestest" / "project-files" / "captures")
assert os.path.exists(p.captures_directory)
def test_add_node_local(async_run, controller):
async def test_add_node_local(controller):
"""
For a local server we send the project path
"""
compute = MagicMock()
compute.id = "local"
project = Project(controller=controller, name="Test")
@ -160,7 +157,7 @@ def test_add_node_local(async_run, controller):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node = async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_script": "test.cfg"}))
node = await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_script": "test.cfg"})
assert node.id in project._nodes
compute.post.assert_any_call('/projects', data={
@ -177,10 +174,11 @@ def test_add_node_local(async_run, controller):
project.emit_notification.assert_any_call("node.created", node.__json__())
def test_add_node_non_local(async_run, controller):
async def test_add_node_non_local(controller):
"""
For a non local server we do not send the project path
"""
compute = MagicMock()
compute.id = "remote"
project = Project(controller=controller, name="Test")
@ -190,67 +188,66 @@ def test_add_node_non_local(async_run, controller):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node = async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_script": "test.cfg"}))
node = await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_script": "test.cfg"})
compute.post.assert_any_call('/projects', data={
"name": project._name,
"project_id": project._id
})
compute.post.assert_any_call('/projects/{}/vpcs/nodes'.format(project.id),
data={'node_id': node.id,
'startup_script': 'test.cfg',
'name': 'test'},
timeout=1200)
compute.post.assert_any_call('/projects/{}/vpcs/nodes'.format(project.id), data={'node_id': node.id,
'startup_script': 'test.cfg',
'name': 'test'}, timeout=1200)
assert compute in project._project_created_on_compute
project.emit_notification.assert_any_call("node.created", node.__json__())
def test_add_node_iou(async_run, controller):
async def test_add_node_iou(controller):
"""
Test if an application ID is allocated for IOU nodes
"""
compute = MagicMock()
compute.id = "local"
project = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test1"))
project = await controller.add_project(project_id=str(uuid.uuid4()), name="test1")
project.emit_notification = MagicMock()
response = MagicMock()
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "test1", None, node_type="iou"))
node2 = async_run(project.add_node(compute, "test2", None, node_type="iou"))
node3 = async_run(project.add_node(compute, "test3", None, node_type="iou"))
node1 = await project.add_node(compute, "test1", None, node_type="iou")
node2 = await project.add_node(compute, "test2", None, node_type="iou")
node3 = await project.add_node(compute, "test3", None, node_type="iou")
assert node1.properties["application_id"] == 1
assert node2.properties["application_id"] == 2
assert node3.properties["application_id"] == 3
def test_add_node_iou_with_multiple_projects(async_run, controller):
async def test_add_node_iou_with_multiple_projects(controller):
"""
Test if an application ID is allocated for IOU nodes with different projects already opened
"""
compute = MagicMock()
compute.id = "local"
project1 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test1"))
project1 = await controller.add_project(project_id=str(uuid.uuid4()), name="test1")
project1.emit_notification = MagicMock()
project2 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test2"))
project2 = await controller.add_project(project_id=str(uuid.uuid4()), name="test2")
project2.emit_notification = MagicMock()
project3 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test3"))
project3 = await controller.add_project(project_id=str(uuid.uuid4()), name="test3")
project3.emit_notification = MagicMock()
response = MagicMock()
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project1.add_node(compute, "test1", None, node_type="iou"))
node2 = async_run(project1.add_node(compute, "test2", None, node_type="iou"))
node3 = async_run(project1.add_node(compute, "test3", None, node_type="iou"))
node1 = await project1.add_node(compute, "test1", None, node_type="iou")
node2 = await project1.add_node(compute, "test2", None, node_type="iou")
node3 = await project1.add_node(compute, "test3", None, node_type="iou")
node4 = async_run(project2.add_node(compute, "test4", None, node_type="iou"))
node5 = async_run(project2.add_node(compute, "test5", None, node_type="iou"))
node6 = async_run(project2.add_node(compute, "test6", None, node_type="iou"))
node4 = await project2.add_node(compute, "test4", None, node_type="iou")
node5 = await project2.add_node(compute, "test5", None, node_type="iou")
node6 = await project2.add_node(compute, "test6", None, node_type="iou")
node7 = async_run(project3.add_node(compute, "test7", None, node_type="iou"))
node8 = async_run(project3.add_node(compute, "test8", None, node_type="iou"))
node9 = async_run(project3.add_node(compute, "test9", None, node_type="iou"))
node7 = await project3.add_node(compute, "test7", None, node_type="iou")
node8 = await project3.add_node(compute, "test8", None, node_type="iou")
node9 = await project3.add_node(compute, "test9", None, node_type="iou")
assert node1.properties["application_id"] == 1
assert node2.properties["application_id"] == 2
@ -265,19 +262,19 @@ def test_add_node_iou_with_multiple_projects(async_run, controller):
assert node9.properties["application_id"] == 9
controller.remove_project(project1)
project4 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test4"))
project4 = await controller.add_project(project_id=str(uuid.uuid4()), name="test4")
project4.emit_notification = MagicMock()
node10 = async_run(project3.add_node(compute, "test10", None, node_type="iou"))
node11 = async_run(project3.add_node(compute, "test11", None, node_type="iou"))
node12 = async_run(project3.add_node(compute, "test12", None, node_type="iou"))
node10 = await project3.add_node(compute, "test10", None, node_type="iou")
node11 = await project3.add_node(compute, "test11", None, node_type="iou")
node12 = await project3.add_node(compute, "test12", None, node_type="iou")
assert node10.properties["application_id"] == 1
assert node11.properties["application_id"] == 2
assert node12.properties["application_id"] == 3
def test_add_node_iou_with_multiple_projects_different_computes(async_run, controller):
async def test_add_node_iou_with_multiple_projects_different_computes(controller):
"""
Test if an application ID is allocated for IOU nodes with different projects already opened
"""
@ -285,19 +282,19 @@ def test_add_node_iou_with_multiple_projects_different_computes(async_run, contr
compute1.id = "remote1"
compute2 = MagicMock()
compute2.id = "remote2"
project1 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test1"))
project1 = await controller.add_project(project_id=str(uuid.uuid4()), name="test1")
project1.emit_notification = MagicMock()
project2 = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test2"))
project2 = await controller.add_project(project_id=str(uuid.uuid4()), name="test2")
project2.emit_notification = MagicMock()
response = MagicMock()
compute1.post = AsyncioMagicMock(return_value=response)
compute2.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project1.add_node(compute1, "test1", None, node_type="iou"))
node2 = async_run(project1.add_node(compute1, "test2", None, node_type="iou"))
node1 = await project1.add_node(compute1, "test1", None, node_type="iou")
node2 = await project1.add_node(compute1, "test2", None, node_type="iou")
node3 = async_run(project2.add_node(compute2, "test3", None, node_type="iou"))
node4 = async_run(project2.add_node(compute2, "test4", None, node_type="iou"))
node3 = await project2.add_node(compute2, "test3", None, node_type="iou")
node4 = await project2.add_node(compute2, "test4", None, node_type="iou")
assert node1.properties["application_id"] == 1
assert node2.properties["application_id"] == 2
@ -305,20 +302,21 @@ def test_add_node_iou_with_multiple_projects_different_computes(async_run, contr
assert node3.properties["application_id"] == 1
assert node4.properties["application_id"] == 2
node5 = async_run(project1.add_node(compute2, "test5", None, node_type="iou"))
node6 = async_run(project2.add_node(compute1, "test6", None, node_type="iou"))
node5 = await project1.add_node(compute2, "test5", None, node_type="iou")
node6 = await project2.add_node(compute1, "test6", None, node_type="iou")
assert node5.properties["application_id"] == 3
assert node6.properties["application_id"] == 4
def test_add_node_iou_no_id_available(async_run, controller):
async def test_add_node_iou_no_id_available(controller):
"""
Test if an application ID is allocated for IOU nodes
"""
compute = MagicMock()
compute.id = "local"
project = async_run(controller.add_project(project_id=str(uuid.uuid4()), name="test"))
project = await controller.add_project(project_id=str(uuid.uuid4()), name="test")
project.emit_notification = MagicMock()
response = MagicMock()
compute.post = AsyncioMagicMock(return_value=response)
@ -327,13 +325,14 @@ def test_add_node_iou_no_id_available(async_run, controller):
for i in range(1, 513):
prop = {"properties": {"application_id": i}}
project._nodes[i] = Node(project, compute, "Node{}".format(i), node_id=i, node_type="iou", **prop)
async_run(project.add_node(compute, "test1", None, node_type="iou"))
await project.add_node(compute, "test1", None, node_type="iou")
def test_add_node_from_template(async_run, controller):
async def test_add_node_from_template(controller):
"""
For a local server we send the project path
"""
compute = MagicMock()
compute.id = "local"
project = Project(controller=controller, name="Test")
@ -351,7 +350,7 @@ def test_add_node_from_template(async_run, controller):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node = async_run(project.add_node_from_template(template.id, x=23, y=12))
node = await project.add_node_from_template(template.id, x=23, y=12)
compute.post.assert_any_call('/projects', data={
"name": project._name,
"project_id": project._id,
@ -362,10 +361,11 @@ def test_add_node_from_template(async_run, controller):
project.emit_notification.assert_any_call("node.created", node.__json__())
def test_add_builtin_node_from_template(async_run, controller):
async def test_add_builtin_node_from_template(controller):
"""
For a local server we send the project path
"""
compute = MagicMock()
compute.id = "local"
project = Project(controller=controller, name="Test")
@ -374,6 +374,7 @@ def test_add_builtin_node_from_template(async_run, controller):
"name": "Builtin-switch",
"template_type": "ethernet_switch",
}, builtin=True)
controller.template_manager.templates[template.id] = template
template.__json__()
controller._computes["local"] = compute
@ -382,7 +383,7 @@ def test_add_builtin_node_from_template(async_run, controller):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node = async_run(project.add_node_from_template(template.id, x=23, y=12, compute_id="local"))
node = await project.add_node_from_template(template.id, x=23, y=12, compute_id="local")
compute.post.assert_any_call('/projects', data={
"name": project._name,
"project_id": project._id,
@ -393,7 +394,7 @@ def test_add_builtin_node_from_template(async_run, controller):
project.emit_notification.assert_any_call("node.created", node.__json__())
def test_delete_node(async_run, controller):
async def test_delete_node(controller):
"""
For a local server we send the project path
"""
@ -405,19 +406,20 @@ def test_delete_node(async_run, controller):
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"})
assert node.id in project._nodes
async_run(project.delete_node(node.id))
await project.delete_node(node.id)
assert node.id not in project._nodes
compute.delete.assert_any_call('/projects/{}/vpcs/nodes/{}'.format(project.id, node.id))
project.emit_notification.assert_any_call("node.deleted", node.__json__())
def test_delete_locked_node(async_run, controller):
async def test_delete_locked_node(controller):
"""
For a local server we send the project path
"""
compute = MagicMock()
project = Project(controller=controller, name="Test")
project.emit_notification = MagicMock()
@ -426,14 +428,14 @@ def test_delete_locked_node(async_run, controller):
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"})
assert node.id in project._nodes
node.locked = True
with pytest.raises(aiohttp.web_exceptions.HTTPConflict):
async_run(project.delete_node(node.id))
await project.delete_node(node.id)
def test_delete_node_delete_link(async_run, controller):
async def test_delete_node_delete_link(controller):
"""
Delete a node delete all the node connected
"""
@ -445,12 +447,12 @@ def test_delete_node_delete_link(async_run, controller):
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"})
link = async_run(project.add_link())
async_run(link.add_node(node, 0, 0))
link = await project.add_link()
await link.add_node(node, 0, 0)
async_run(project.delete_node(node.id))
await project.delete_node(node.id)
assert node.id not in project._nodes
assert link.id not in project._links
@ -459,7 +461,8 @@ def test_delete_node_delete_link(async_run, controller):
project.emit_notification.assert_any_call("link.deleted", link.__json__())
def test_get_node(async_run, controller):
async def test_get_node(controller):
compute = MagicMock()
project = Project(controller=controller, name="Test")
@ -467,18 +470,20 @@ def test_get_node(async_run, controller):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
vm = async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
vm = await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert project.get_node(vm.id) == vm
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
project.get_node("test")
# Raise an error if the project is not opened
async_run(project.close())
await project.close()
with pytest.raises(aiohttp.web.HTTPForbidden):
project.get_node(vm.id)
def test_list_nodes(async_run, controller):
async def test_list_nodes(controller):
compute = MagicMock()
project = Project(controller=controller, name="Test")
@ -486,157 +491,163 @@ def test_list_nodes(async_run, controller):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
vm = async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
vm = await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert len(project.nodes) == 1
assert isinstance(project.nodes, dict)
async_run(project.close())
await project.close()
assert len(project.nodes) == 1
assert isinstance(project.nodes, dict)
def test_add_link(async_run, project, controller):
async def test_add_link(project):
compute = MagicMock()
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
vm1 = async_run(project.add_node(compute, "test1", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
vm1 = await project.add_node(compute, "test1", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
vm1._ports = [EthernetPort("E0", 0, 3, 1)]
vm2 = async_run(project.add_node(compute, "test2", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
vm2 = await project.add_node(compute, "test2", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
vm2._ports = [EthernetPort("E0", 0, 4, 2)]
project.emit_notification = MagicMock()
link = async_run(project.add_link())
async_run(link.add_node(vm1, 3, 1))
link = await project.add_link()
await link.add_node(vm1, 3, 1)
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as mock_udp_create:
async_run(link.add_node(vm2, 4, 2))
await link.add_node(vm2, 4, 2)
assert mock_udp_create.called
assert len(link._nodes) == 2
project.emit_notification.assert_any_call("link.created", link.__json__())
def test_list_links(async_run, project):
compute = MagicMock()
async def test_list_links(project):
compute = MagicMock()
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
link = async_run(project.add_link())
await project.add_link()
assert len(project.links) == 1
async_run(project.close())
await project.close()
assert len(project.links) == 1
def test_get_link(async_run, project):
compute = MagicMock()
async def test_get_link(project):
compute = MagicMock()
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
link = async_run(project.add_link())
link = await project.add_link()
assert project.get_link(link.id) == link
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
project.get_link("test")
def test_delete_link(async_run, project, controller):
compute = MagicMock()
async def test_delete_link(project):
compute = MagicMock()
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
assert len(project._links) == 0
link = async_run(project.add_link())
link = await project.add_link()
assert len(project._links) == 1
project.emit_notification = MagicMock()
async_run(project.delete_link(link.id))
await project.delete_link(link.id)
project.emit_notification.assert_any_call("link.deleted", link.__json__())
assert len(project._links) == 0
def test_add_drawing(async_run, project, controller):
project.emit_notification = MagicMock()
async def test_add_drawing(project):
drawing = async_run(project.add_drawing(None, svg="<svg></svg>"))
project.emit_notification = MagicMock()
drawing = await project.add_drawing(None, svg="<svg></svg>")
assert len(project._drawings) == 1
project.emit_notification.assert_any_call("drawing.created", drawing.__json__())
def test_get_drawing(async_run, project):
drawing = async_run(project.add_drawing(None))
async def test_get_drawing(project):
drawing = await project.add_drawing(None)
assert project.get_drawing(drawing.id) == drawing
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
project.get_drawing("test")
def test_list_drawing(async_run, project):
drawing = async_run(project.add_drawing(None))
async def test_list_drawing(project):
await project.add_drawing(None)
assert len(project.drawings) == 1
async_run(project.close())
await project.close()
assert len(project.drawings) == 1
def test_delete_drawing(async_run, project, controller):
async def test_delete_drawing(project):
assert len(project._drawings) == 0
drawing = async_run(project.add_drawing())
drawing = await project.add_drawing()
assert len(project._drawings) == 1
project.emit_notification = MagicMock()
async_run(project.delete_drawing(drawing.id))
await project.delete_drawing(drawing.id)
project.emit_notification.assert_any_call("drawing.deleted", drawing.__json__())
assert len(project._drawings) == 0
def test_clean_pictures(async_run, project, controller):
async def test_clean_pictures(project):
"""
When a project is close old pictures should be removed
"""
drawing = async_run(project.add_drawing())
drawing = await project.add_drawing()
drawing._svg = "test.png"
open(os.path.join(project.pictures_directory, "test.png"), "w+").close()
open(os.path.join(project.pictures_directory, "test2.png"), "w+").close()
async_run(project.close())
await project.close()
assert os.path.exists(os.path.join(project.pictures_directory, "test.png"))
assert not os.path.exists(os.path.join(project.pictures_directory, "test2.png"))
def test_clean_pictures_and_keep_supplier_logo(async_run, project, controller):
async def test_clean_pictures_and_keep_supplier_logo(project):
"""
When a project is close old pictures should be removed
"""
project.supplier = {
'logo': 'logo.png'
}
drawing = async_run(project.add_drawing())
drawing = await project.add_drawing()
drawing._svg = "test.png"
open(os.path.join(project.pictures_directory, "test.png"), "w+").close()
open(os.path.join(project.pictures_directory, "test2.png"), "w+").close()
open(os.path.join(project.pictures_directory, "logo.png"), "w+").close()
async_run(project.close())
await project.close()
assert os.path.exists(os.path.join(project.pictures_directory, "test.png"))
assert not os.path.exists(os.path.join(project.pictures_directory, "test2.png"))
assert os.path.exists(os.path.join(project.pictures_directory, "logo.png"))
def test_delete(async_run, project, controller):
async def test_delete(project):
assert os.path.exists(project.path)
async_run(project.delete())
await project.delete()
assert not os.path.exists(project.path)
def test_dump():
directory = Config.instance().get_section_config("Server").get("projects_path")
async def test_dump(projects_dir):
directory = projects_dir
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test")
p.dump()
@ -645,30 +656,32 @@ def test_dump():
assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
def test_open_close(async_run, controller):
async def test_open_close(controller):
project = Project(controller=controller, name="Test")
assert project.status == "opened"
async_run(project.close())
await project.close()
project.start_all = AsyncioMagicMock()
async_run(project.open())
await project.open()
assert not project.start_all.called
assert project.status == "opened"
project.emit_notification = MagicMock()
async_run(project.close())
await project.close()
assert project.status == "closed"
project.emit_notification.assert_any_call("project.closed", project.__json__())
def test_open_auto_start(async_run, controller):
async def test_open_auto_start(controller):
project = Project(controller=controller, name="Test", auto_start=True)
assert project.status == "opened"
async_run(project.close())
await project.close()
project.start_all = AsyncioMagicMock()
async_run(project.open())
await project.open()
assert project.start_all.called
def test_is_running(project, async_run, node):
def test_is_running(project, node):
"""
If a node is started or paused return True
"""
@ -678,11 +691,12 @@ def test_is_running(project, async_run, node):
assert project.is_running() is True
def test_duplicate(project, async_run, controller):
async def test_duplicate(project, controller):
"""
Duplicate a project, the node should remain on the remote server
if they were on remote server
"""
compute = MagicMock()
compute.id = "remote"
compute.list_files = AsyncioMagicMock(return_value=[])
@ -692,16 +706,16 @@ def test_duplicate(project, async_run, controller):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
remote_vpcs = async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
remote_vpcs = await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
# We allow node not allowed for standard import / export
remote_virtualbox = async_run(project.add_node(compute, "test", None, node_type="vmware", properties={"startup_config": "test.cfg"}))
remote_virtualbox = await project.add_node(compute, "test", None, node_type="vmware", properties={"startup_config": "test.cfg"})
new_project = async_run(project.duplicate(name="Hello"))
new_project = await project.duplicate(name="Hello")
assert new_project.id != project.id
assert new_project.name == "Hello"
async_run(new_project.open())
await new_project.open()
assert list(new_project.nodes.values())[0].compute.id == "remote"
assert list(new_project.nodes.values())[1].compute.id == "remote"
@ -711,6 +725,7 @@ def test_snapshots(project):
"""
List the snapshots
"""
os.makedirs(os.path.join(project.path, "snapshots"))
open(os.path.join(project.path, "snapshots", "test1_260716_103713.gns3project"), "w+").close()
project.reset()
@ -720,6 +735,7 @@ def test_snapshots(project):
def test_get_snapshot(project):
os.makedirs(os.path.join(project.path, "snapshots"))
open(os.path.join(project.path, "snapshots", "test1.gns3project"), "w+").close()
project.reset()
@ -731,7 +747,8 @@ def test_get_snapshot(project):
project.get_snapshot("BLU")
def test_delete_snapshot(project, async_run):
async def test_delete_snapshot(project):
os.makedirs(os.path.join(project.path, "snapshots"))
open(os.path.join(project.path, "snapshots", "test1_260716_103713.gns3project"), "w+").close()
project.reset()
@ -739,7 +756,7 @@ def test_delete_snapshot(project, async_run):
snapshot = list(project.snapshots.values())[0]
assert project.get_snapshot(snapshot.id) == snapshot
async_run(project.delete_snapshot(snapshot.id))
await project.delete_snapshot(snapshot.id)
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
project.get_snapshot(snapshot.id)
@ -747,13 +764,13 @@ def test_delete_snapshot(project, async_run):
assert not os.path.exists(os.path.join(project.path, "snapshots", "test1.gns3project"))
def test_snapshot(project, async_run):
async def test_snapshot(project):
"""
Create a snapshot
"""
assert len(project.snapshots) == 0
snapshot = async_run(project.snapshot("test1"))
assert len(project.snapshots) == 0
snapshot = await project.snapshot("test1")
assert snapshot.name == "test1"
assert len(project.snapshots) == 1
@ -761,10 +778,11 @@ def test_snapshot(project, async_run):
# Raise a conflict if name is already use
with pytest.raises(aiohttp.web_exceptions.HTTPConflict):
snapshot = async_run(project.snapshot("test1"))
snapshot = await project.snapshot("test1")
def test_start_all(project, async_run):
async def test_start_all(project):
compute = MagicMock()
compute.id = "local"
response = MagicMock()
@ -772,14 +790,15 @@ def test_start_all(project, async_run):
compute.post = AsyncioMagicMock(return_value=response)
for node_i in range(0, 10):
async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
compute.post = AsyncioMagicMock()
async_run(project.start_all())
await project.start_all()
assert len(compute.post.call_args_list) == 10
def test_stop_all(project, async_run):
async def test_stop_all(project):
compute = MagicMock()
compute.id = "local"
response = MagicMock()
@ -787,14 +806,15 @@ def test_stop_all(project, async_run):
compute.post = AsyncioMagicMock(return_value=response)
for node_i in range(0, 10):
async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
compute.post = AsyncioMagicMock()
async_run(project.stop_all())
await project.stop_all()
assert len(compute.post.call_args_list) == 10
def test_suspend_all(project, async_run):
async def test_suspend_all(project):
compute = MagicMock()
compute.id = "local"
response = MagicMock()
@ -802,51 +822,53 @@ def test_suspend_all(project, async_run):
compute.post = AsyncioMagicMock(return_value=response)
for node_i in range(0, 10):
async_run(project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
await project.add_node(compute, "test", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
compute.post = AsyncioMagicMock()
async_run(project.suspend_all())
await project.suspend_all()
assert len(compute.post.call_args_list) == 10
def test_node_name(project, async_run):
async def test_node_name(project):
compute = MagicMock()
compute.id = "local"
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node = async_run(project.add_node(compute, "test-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "test-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert node.name == "test-1"
node = async_run(project.add_node(compute, "test-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "test-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert node.name == "test-2"
node = async_run(project.add_node(compute, "hello world-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "hello world-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert node.name == "helloworld-1"
node = async_run(project.add_node(compute, "hello world-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "hello world-{0}", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert node.name == "helloworld-2"
node = async_run(project.add_node(compute, "VPCS-1", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "VPCS-1", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert node.name == "VPCS-1"
node = async_run(project.add_node(compute, "VPCS-1", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "VPCS-1", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert node.name == "VPCS-2"
node = async_run(project.add_node(compute, "R3", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
node = await project.add_node(compute, "R3", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
assert node.name == "R3"
def test_duplicate_node(project, async_run):
async def test_duplicate_node(project):
compute = MagicMock()
compute.id = "local"
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
original = async_run(project.add_node(
original = await project.add_node(
compute,
"test",
None,
node_type="vpcs",
properties={
"startup_config": "test.cfg"
}))
new_node = async_run(project.duplicate_node(original, 42, 10, 11))
})
new_node = await project.duplicate_node(original, 42, 10, 11)
assert new_node.x == 42

@ -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,7 +20,7 @@ import json
import pytest
import aiohttp
from tests.utils import asyncio_patch, AsyncioMagicMock
from tests.utils import asyncio_patch
from gns3server.controller.compute import Compute
from gns3server.controller.project import Project
@ -31,6 +31,7 @@ def demo_topology():
"""
A topology with two VPCS connected and a rectangle
"""
return {
"auto_close": True,
"auto_open": False,
@ -145,29 +146,32 @@ def demo_topology():
}
def test_load_project(controller, tmpdir, demo_topology, async_run, http_server):
with open(str(tmpdir / "demo.gns3"), "w+") as f:
json.dump(demo_topology, f)
controller._computes["local"] = Compute("local", controller=controller, host=http_server[0], port=http_server[1])
controller._computes["vm"] = controller._computes["local"]
# async def test_load_project(controller, tmpdir, demo_topology, http_client):
#
# with open(str(tmpdir / "demo.gns3"), "w+") as f:
# json.dump(demo_topology, f)
#
# controller._computes["local"] = Compute("local", controller=controller, host=http_client.host, port=http_client.port)
# controller._computes["vm"] = controller._computes["local"]
#
# with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.add_ubridge_udp_connection"):
# project = await controller.load_project(str(tmpdir / "demo.gns3"))
#
# assert project.status == "opened"
# assert len(project.computes) == 1
# assert len(project.nodes) == 2
# assert project.nodes["64ba8408-afbf-4b66-9cdd-1fd854427478"].name == "PC1"
# assert len(project.links) == 1
# assert project.links["5a3e3a64-e853-4055-9503-4a14e01290f1"].created
# assert len(project.drawings) == 1
#
# assert project.name == "demo"
# assert project.scene_height == 500
# assert project.scene_width == 700
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.add_ubridge_udp_connection"):
project = async_run(controller.load_project(str(tmpdir / "demo.gns3")))
assert project.status == "opened"
assert len(project.computes) == 1
assert len(project.nodes) == 2
assert project.nodes["64ba8408-afbf-4b66-9cdd-1fd854427478"].name == "PC1"
assert len(project.links) == 1
assert project.links["5a3e3a64-e853-4055-9503-4a14e01290f1"].created
assert len(project.drawings) == 1
assert project.name == "demo"
assert project.scene_height == 500
assert project.scene_width == 700
async def test_open(controller, tmpdir):
def test_open(controller, tmpdir, demo_topology, async_run, http_server):
simple_topology = {
"auto_close": True,
"auto_open": False,
@ -190,33 +194,34 @@ def test_open(controller, tmpdir, demo_topology, async_run, http_server):
with open(str(tmpdir / "demo.gns3"), "w+") as f:
json.dump(simple_topology, f)
project = Project(
name="demo",
project_id="64ba8408-afbf-4b66-9cdd-1fd854427478",
path=str(tmpdir), controller=controller, filename="demo.gns3", status="closed")
async_run(project.open())
project = Project(name="demo",
project_id="64ba8408-afbf-4b66-9cdd-1fd854427478",
path=str(tmpdir),
controller=controller,
filename="demo.gns3",
status="closed")
await project.open()
assert project.status == "opened"
assert project.name == "demo"
assert project.scene_height == 500
assert project.scene_width == 700
def test_open_missing_compute(controller, tmpdir, demo_topology, async_run, http_server):
"""
If a compute is missing the project should not be open and the .gns3 should
be the one before opening the project
"""
with open(str(tmpdir / "demo.gns3"), "w+") as f:
json.dump(demo_topology, f)
controller._computes["local"] = Compute("local", controller=controller, host=http_server[0], port=http_server[1])
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
project = async_run(controller.load_project(str(tmpdir / "demo.gns3")))
assert controller.get_project("3c1be6f9-b4ba-4737-b209-63c47c23359f").status == "closed"
with open(str(tmpdir / "demo.gns3"), "r") as f:
topo = json.load(f)
assert len(topo["topology"]["nodes"]) == 2
# async def test_open_missing_compute(controller, tmpdir, demo_topology, http_client):
# """
# If a compute is missing the project should not be open and the .gns3 should
# be the one before opening the project
# """
#
# with open(str(tmpdir / "demo.gns3"), "w+") as f:
# json.dump(demo_topology, f)
#
# controller._computes["local"] = Compute("local", controller=controller, host=http_client.host, port=http_client.port)
#
# with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
# await controller.load_project(str(tmpdir / "demo.gns3"))
# assert controller.get_project("3c1be6f9-b4ba-4737-b209-63c47c23359f").status == "closed"
# with open(str(tmpdir / "demo.gns3"), "r") as f:
# topo = json.load(f)
# assert len(topo["topology"]["nodes"]) == 2

@ -25,17 +25,18 @@ from gns3server.controller.snapshot import Snapshot
from tests.utils import AsyncioMagicMock
@pytest.fixture
def project(controller):
project = Project(controller=controller, name="Test")
controller._projects[project.id] = project
return project
# @pytest.fixture
# def project(controller):
# project = Project(controller=controller, name="Test")
# controller._projects[project.id] = project
# return project
def test_snapshot_name(project):
"""
Test create a snapshot object with a name
"""
snapshot = Snapshot(project, name="test1")
assert snapshot.name == "test1"
assert snapshot._created_at > 0
@ -51,6 +52,7 @@ def test_snapshot_filename(project):
"""
Test create a snapshot object with a filename
"""
snapshot = Snapshot(project, filename="test1_260716_100439.gns3project")
assert snapshot.name == "test1"
assert snapshot._created_at == 1469527479.0
@ -58,6 +60,7 @@ def test_snapshot_filename(project):
def test_json(project):
snapshot = Snapshot(project, filename="test1_260716_100439.gns3project")
assert snapshot.__json__() == {
"snapshot_id": snapshot._id,
@ -67,7 +70,8 @@ def test_json(project):
}
def test_restore(project, controller, async_run):
async def test_restore(project, controller):
compute = AsyncioMagicMock()
compute.id = "local"
controller._computes["local"] = compute
@ -75,12 +79,11 @@ def test_restore(project, controller, async_run):
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
async_run(project.add_node(compute, "test1", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
snapshot = async_run(project.snapshot(name="test"))
await project.add_node(compute, "test1", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
snapshot = await project.snapshot(name="test")
# We add a node after the snapshots
async_run(project.add_node(compute, "test2", None, node_type="vpcs", properties={"startup_config": "test.cfg"}))
await project.add_node(compute, "test2", None, node_type="vpcs", properties={"startup_config": "test.cfg"})
# project-files should be reset when reimporting
test_file = os.path.join(project.path, "project-files", "test.txt")
@ -92,7 +95,7 @@ def test_restore(project, controller, async_run):
controller._notification = MagicMock()
with patch("gns3server.config.Config.get_section_config", return_value={"local": True}):
async_run(snapshot.restore())
await snapshot.restore()
assert "snapshot.restored" in [c[0][0] for c in controller.notification.project_emit.call_args_list]
# project.closed notification should not be send when restoring snapshots

@ -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,7 +16,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from unittest.mock import patch
from gns3server.controller.symbols import Symbols

@ -38,8 +38,9 @@ def test_template_json():
def test_template_json_with_not_known_category():
with pytest.raises(jsonschema.ValidationError):
a = Template(None, {
Template(None, {
"node_type": "qemu",
"name": "Test",
"default_name_format": "{name}-{0}",
@ -51,6 +52,7 @@ def test_template_json_with_not_known_category():
def test_template_json_with_platform():
a = Template(None, {
"node_type": "dynamips",
"name": "Test",
@ -73,6 +75,7 @@ def test_template_fix_linked_base():
Version of the gui before 2.1 use linked_base and the server
linked_clone
"""
a = Template(None, {
"node_type": "qemu",
"name": "Test",

@ -28,7 +28,8 @@ from gns3server.controller.topology import project_to_topology, load_topology, G
from gns3server.version import __version__
def test_project_to_topology_empty(tmpdir):
async def test_project_to_topology_empty(tmpdir):
project = Project(name="Test")
topo = project_to_topology(project)
assert topo == {
@ -60,21 +61,22 @@ def test_project_to_topology_empty(tmpdir):
}
def test_basic_topology(tmpdir, async_run, controller):
async def test_basic_topology(controller):
project = Project(name="Test", controller=controller)
compute = Compute("my_compute", controller)
compute.http_query = MagicMock()
with asyncio_patch("gns3server.controller.node.Node.create"):
node1 = async_run(project.add_node(compute, "Node 1", str(uuid.uuid4()), node_type="qemu"))
node2 = async_run(project.add_node(compute, "Node 2", str(uuid.uuid4()), node_type="qemu"))
node1 = await project.add_node(compute, "Node 1", str(uuid.uuid4()), node_type="qemu")
node2 = await project.add_node(compute, "Node 2", str(uuid.uuid4()), node_type="qemu")
link = async_run(project.add_link())
async_run(link.add_node(node1, 0, 0))
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as mock_udp_create:
async_run(link.add_node(node2, 0, 0))
link = await project.add_link()
await link.add_node(node1, 0, 0)
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create"):
await link.add_node(node2, 0, 0)
drawing = async_run(project.add_drawing(svg="<svg></svg>"))
drawing = await project.add_drawing(svg="<svg></svg>")
topo = project_to_topology(project)
assert len(topo["topology"]["nodes"]) == 2
@ -84,7 +86,8 @@ def test_basic_topology(tmpdir, async_run, controller):
assert topo["topology"]["drawings"][0] == drawing.__json__(topology_dump=True)
def test_project_to_topology(tmpdir, controller):
async def test_project_to_topology(controller):
variables = [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
@ -105,6 +108,7 @@ def test_project_to_topology(tmpdir, controller):
def test_load_topology(tmpdir):
data = {
"project_id": "69f26504-7aa3-48aa-9f29-798d44841211",
"name": "Test",
@ -126,19 +130,21 @@ def test_load_topology(tmpdir):
def test_load_topology_file_error(tmpdir):
path = str(tmpdir / "test.gns3")
with pytest.raises(aiohttp.web.HTTPConflict):
topo = load_topology(path)
load_topology(path)
def test_load_topology_file_error_schema_error(tmpdir):
path = str(tmpdir / "test.gns3")
with open(path, "w+") as f:
json.dump({
"revision": GNS3_FILE_FORMAT_REVISION
}, f)
with pytest.raises(aiohttp.web.HTTPConflict):
topo = load_topology(path)
load_topology(path)
def test_load_newer_topology(tmpdir):
@ -146,6 +152,7 @@ def test_load_newer_topology(tmpdir):
If a topology is design for a more recent GNS3 version
we disallow the loading.
"""
data = {
"project_id": "69f26504-7aa3-48aa-9f29-798d44841211",
"name": "Test",
@ -159,10 +166,11 @@ def test_load_newer_topology(tmpdir):
with open(path, "w+") as f:
json.dump(data, f)
with pytest.raises(aiohttp.web.HTTPConflict):
topo = load_topology(path)
load_topology(path)
def test_load_topology_with_variables(tmpdir):
variables = [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
@ -189,6 +197,7 @@ def test_load_topology_with_variables(tmpdir):
def test_load_topology_with_supplier(tmpdir):
supplier = {
'logo': 'logo.png',
'url': 'http://example.com'
@ -211,4 +220,4 @@ def test_load_topology_with_supplier(tmpdir):
with open(path, "w+") as f:
json.dump(data, f)
topo = load_topology(path)
assert topo == data
assert topo == data

@ -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,23 +16,17 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import asyncio
import aiohttp
from unittest.mock import MagicMock
from tests.utils import AsyncioMagicMock
from gns3server.controller.project import Project
from gns3server.controller.udp_link import UDPLink
from gns3server.controller.ports.ethernet_port import EthernetPort
from gns3server.controller.node import Node
@pytest.fixture
def project(controller):
return Project(controller=controller, name="Test")
async def test_create(project):
def test_create(async_run, project):
compute1 = MagicMock()
compute2 = MagicMock()
@ -50,8 +44,8 @@ def test_create(async_run, project):
compute1.get_ip_on_same_subnet.side_effect = subnet_callback
link = UDPLink(project)
async_run(link.add_node(node1, 0, 4))
async_run(link.update_filters({"latency": [10]}))
await link.add_node(node1, 0, 4)
await link.update_filters({"latency": [10]})
async def compute1_callback(path, data={}, **kwargs):
"""
@ -75,7 +69,7 @@ def test_create(async_run, project):
compute1.host = "example.com"
compute2.post.side_effect = compute2_callback
compute2.host = "example.org"
async_run(link.add_node(node2, 3, 1))
await link.add_node(node2, 3, 1)
compute1.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/nio".format(project.id, node1.id), data={
"lport": 1024,
@ -85,6 +79,7 @@ def test_create(async_run, project):
"filters": {"latency": [10]},
"suspend": False,
}, timeout=120)
compute2.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/3/ports/1/nio".format(project.id, node2.id), data={
"lport": 2048,
"rhost": "192.168.1.1",
@ -95,7 +90,8 @@ def test_create(async_run, project):
}, timeout=120)
def test_create_one_side_failure(async_run, project):
async def test_create_one_side_failure(project):
compute1 = MagicMock()
compute2 = MagicMock()
@ -113,7 +109,7 @@ def test_create_one_side_failure(async_run, project):
compute1.get_ip_on_same_subnet.side_effect = subnet_callback
link = UDPLink(project)
async_run(link.add_node(node1, 0, 4))
await link.add_node(node1, 0, 4)
async def compute1_callback(path, data={}, **kwargs):
"""
@ -140,7 +136,7 @@ def test_create_one_side_failure(async_run, project):
compute2.post.side_effect = compute2_callback
compute2.host = "example.org"
with pytest.raises(aiohttp.web.HTTPConflict):
async_run(link.add_node(node2, 3, 1))
await link.add_node(node2, 3, 1)
compute1.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/nio".format(project.id, node1.id), data={
"lport": 1024,
@ -150,6 +146,7 @@ def test_create_one_side_failure(async_run, project):
"filters": {},
"suspend": False,
}, timeout=120)
compute2.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/3/ports/1/nio".format(project.id, node2.id), data={
"lport": 2048,
"rhost": "192.168.1.1",
@ -162,7 +159,8 @@ def test_create_one_side_failure(async_run, project):
compute1.delete.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/nio".format(project.id, node1.id), timeout=120)
def test_delete(async_run, project):
async def test_delete(project):
compute1 = MagicMock()
compute2 = MagicMock()
@ -173,19 +171,20 @@ def test_delete(async_run, project):
link = UDPLink(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node1, 0, 4))
async_run(link.add_node(node2, 3, 1))
await link.add_node(node1, 0, 4)
await link.add_node(node2, 3, 1)
async_run(link.delete())
await link.delete()
compute1.delete.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/nio".format(project.id, node1.id), timeout=120)
compute2.delete.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/3/ports/1/nio".format(project.id, node2.id), timeout=120)
def test_choose_capture_side(async_run, project):
async def test_choose_capture_side(project):
"""
The link capture should run on the optimal node
"""
compute1 = MagicMock()
compute2 = MagicMock()
compute2.id = "local"
@ -200,8 +199,8 @@ def test_choose_capture_side(async_run, project):
link = UDPLink(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node_vpcs, 0, 4))
async_run(link.add_node(node_iou, 3, 1))
await link.add_node(node_vpcs, 0, 4)
await link.add_node(node_iou, 3, 1)
assert link._choose_capture_side()["node"] == node_iou
@ -215,8 +214,8 @@ def test_choose_capture_side(async_run, project):
link = UDPLink(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node_iou, 0, 4))
async_run(link.add_node(node_switch, 3, 1))
await link.add_node(node_iou, 0, 4)
await link.add_node(node_switch, 3, 1)
assert link._choose_capture_side()["node"] == node_switch
@ -228,8 +227,8 @@ def test_choose_capture_side(async_run, project):
link = UDPLink(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node_vpcs, 0, 4))
async_run(link.add_node(node_iou, 3, 1))
await link.add_node(node_vpcs, 0, 4)
await link.add_node(node_iou, 3, 1)
with pytest.raises(aiohttp.web.HTTPConflict):
link._choose_capture_side()
@ -238,7 +237,7 @@ def test_choose_capture_side(async_run, project):
assert link._choose_capture_side()["node"] == node_vpcs
def test_capture(async_run, project):
async def test_capture(project):
compute1 = MagicMock()
node_vpcs = Node(project, compute1, "V1", node_type="vpcs")
@ -249,10 +248,10 @@ def test_capture(async_run, project):
link = UDPLink(project)
link.create = AsyncioMagicMock()
async_run(link.add_node(node_vpcs, 0, 4))
async_run(link.add_node(node_iou, 3, 1))
await link.add_node(node_vpcs, 0, 4)
await link.add_node(node_iou, 3, 1)
capture = async_run(link.start_capture())
await link.start_capture()
assert link.capturing
compute1.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/start_capture".format(project.id, node_vpcs.id), data={
@ -260,16 +259,17 @@ def test_capture(async_run, project):
"data_link_type": "DLT_EN10MB"
})
capture = async_run(link.stop_capture())
await link.stop_capture()
assert link.capturing is False
compute1.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/stop_capture".format(project.id, node_vpcs.id))
def test_node_updated(project, async_run):
async def test_node_updated(project):
"""
If a node stop when capturing we stop the capture
"""
compute1 = MagicMock()
node_vpcs = Node(project, compute1, "V1", node_type="vpcs")
node_vpcs._status = "started"
@ -278,15 +278,16 @@ def test_node_updated(project, async_run):
link._capture_node = {"node": node_vpcs}
link.stop_capture = AsyncioMagicMock()
async_run(link.node_updated(node_vpcs))
await link.node_updated(node_vpcs)
assert not link.stop_capture.called
node_vpcs._status = "stopped"
async_run(link.node_updated(node_vpcs))
await link.node_updated(node_vpcs)
assert link.stop_capture.called
def test_update(async_run, project):
async def test_update(project):
compute1 = MagicMock()
compute2 = MagicMock()
@ -304,8 +305,8 @@ def test_update(async_run, project):
compute1.get_ip_on_same_subnet.side_effect = subnet_callback
link = UDPLink(project)
async_run(link.add_node(node1, 0, 4))
async_run(link.update_filters({"latency": [10]}))
await link.add_node(node1, 0, 4)
await link.update_filters({"latency": [10]})
async def compute1_callback(path, data={}, **kwargs):
"""
@ -329,7 +330,7 @@ def test_update(async_run, project):
compute1.host = "example.com"
compute2.post.side_effect = compute2_callback
compute2.host = "example.org"
async_run(link.add_node(node2, 3, 1))
await link.add_node(node2, 3, 1)
compute1.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/nio".format(project.id, node1.id), data={
"lport": 1024,
@ -339,6 +340,7 @@ def test_update(async_run, project):
"suspend": False,
"filters": {"latency": [10]}
}, timeout=120)
compute2.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/3/ports/1/nio".format(project.id, node2.id), data={
"lport": 2048,
"rhost": "192.168.1.1",
@ -349,7 +351,7 @@ def test_update(async_run, project):
}, timeout=120)
assert link.created
async_run(link.update_filters({"drop": [5], "bpf": ["icmp[icmptype] == 8"]}))
await link.update_filters({"drop": [5], "bpf": ["icmp[icmptype] == 8"]})
compute1.put.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/nio".format(project.id, node1.id), data={
"lport": 1024,
"rhost": "192.168.1.2",
@ -363,7 +365,7 @@ def test_update(async_run, project):
}, timeout=120)
def test_update_suspend(async_run, project):
async def test_update_suspend(project):
compute1 = MagicMock()
compute2 = MagicMock()
@ -381,9 +383,9 @@ def test_update_suspend(async_run, project):
compute1.get_ip_on_same_subnet.side_effect = subnet_callback
link = UDPLink(project)
async_run(link.add_node(node1, 0, 4))
async_run(link.update_filters({"latency": [10]}))
async_run(link.update_suspend(True))
await link.add_node(node1, 0, 4)
await link.update_filters({"latency": [10]})
await link.update_suspend(True)
async def compute1_callback(path, data={}, **kwargs):
"""
@ -407,7 +409,7 @@ def test_update_suspend(async_run, project):
compute1.host = "example.com"
compute2.post.side_effect = compute2_callback
compute2.host = "example.org"
async_run(link.add_node(node2, 3, 1))
await link.add_node(node2, 3, 1)
compute1.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/0/ports/4/nio".format(project.id, node1.id), data={
"lport": 1024,
@ -417,6 +419,7 @@ def test_update_suspend(async_run, project):
"filters": {"frequency_drop": [-1]},
"suspend": True
}, timeout=120)
compute2.post.assert_any_call("/projects/{}/vpcs/nodes/{}/adapters/3/ports/1/nio".format(project.id, node2.id), data={
"lport": 2048,
"rhost": "192.168.1.1",

@ -27,124 +27,81 @@ import os
class Query:
"""
Helper to make query againt the test server
Helper to make queries against the test server
"""
def __init__(self, loop, host='localhost', port=8001, prefix='', api_version=None):
def __init__(self, http_client, prefix='', api_version=None):
"""
:param prefix: Prefix added before path (ex: /compute)
:param api_version: Version of the api
:param api_version: Version of the API
"""
self._loop = loop
self._port = port
self._host = host
self._http_client = http_client
self._prefix = prefix
self._api_version = api_version
self._session = None
async def close(self):
await self._session.close()
def post(self, path, body={}, **kwargs):
return self._fetch("POST", path, body, **kwargs)
return self._request("POST", path, body, **kwargs)
def put(self, path, body={}, **kwargs):
return self._fetch("PUT", path, body, **kwargs)
return self._request("PUT", path, body, **kwargs)
def get(self, path, **kwargs):
return self._fetch("GET", path, **kwargs)
return self._request("GET", path, **kwargs)
def delete(self, path, **kwargs):
return self._fetch("DELETE", path, **kwargs)
return self._request("DELETE", path, **kwargs)
def patch(self, path, **kwargs):
return self._request("PATCH", path, **kwargs)
def get_url(self, path):
if self._api_version is None:
return "http://{}:{}{}{}".format(self._host, self._port, self._prefix, path)
return "http://{}:{}/v{}{}{}".format(self._host, self._port, self._api_version, self._prefix, path)
def websocket(self, path):
"""
Return a websocket connected to the path
"""
async def go_request(future):
self._session = aiohttp.ClientSession()
response = await self._session.ws_connect(self.get_url(path))
future.set_result(response)
future = asyncio.Future()
asyncio.ensure_future(go_request(future))
self._loop.run_until_complete(future)
return future.result()
def _fetch(self, method, path, body=None, **kwargs):
"""Fetch an url, parse the JSON and return response
Options:
- example if True the session is included inside documentation
- raw do not JSON encode the query
"""
return self._loop.run_until_complete(asyncio.ensure_future(self._async_fetch(method, path, body=body, **kwargs)))
async def _async_fetch(self, method, path, body=None, **kwargs):
if body is not None and not kwargs.get("raw", False):
return "/{}{}".format(self._prefix, path)
return "/v{}{}{}".format(self._api_version, self._prefix, path)
# async def websocket(self, path):
# """
# Return a websocket connected to the path
# """
#
# #self._session = aiohttp.ClientSession()
# response = await self._http_client.ws_connect(self.get_url(path))
# return response
#
# # async def go_request(future):
# # self._session = aiohttp.ClientSession()
# # response = await self._session.ws_connect(self.get_url(path))
# # future.set_result(response)
# #
# # future = asyncio.Future()
# # asyncio.ensure_future(go_request(future))
# # self._loop.run_until_complete(future)
# # return future.result()
async def _request(self, method, path, body=None, raw=False, **kwargs):
if body is not None and raw is False:
body = json.dumps(body)
connector = aiohttp.TCPConnector()
async with aiohttp.request(method, self.get_url(path), data=body, loop=self._loop, connector=connector) as response:
async with self._http_client.request(method, self.get_url(path), data=body, **kwargs) as response:
response.body = await response.read()
x_route = response.headers.get('X-Route', None)
if x_route is not None:
response.route = x_route.replace("/v{}".format(self._api_version), "")
response.route = response.route .replace(self._prefix, "")
response.json = {}
response.html = ""
#response.json = {}
#response.html = ""
if response.body is not None:
if response.headers.get("CONTENT-TYPE", "") == "application/json":
if response.content_type == "application/json":
try:
response.json = json.loads(response.body.decode("utf-8"))
response.json = await response.json(encoding="utf-8")
except ValueError:
response.json = None
else:
try:
response.html = response.body.decode("utf-8")
response.html = await response.text("utf-8")
except UnicodeDecodeError:
response.html = None
if kwargs.get('example') and os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1":
self._dump_example(method, response.route, path, body, response)
return response
return None
def _dump_example(self, method, route, path, body, response):
"""Dump the request for the documentation"""
if path is None:
return
with open(self._example_file_path(method, route), 'w+') as f:
f.write("curl -i -X {} 'http://localhost:3080/v{}{}{}'".format(method, self._api_version, self._prefix, path))
if body:
f.write(" -d '{}'".format(re.sub(r"\n", "", json.dumps(json.loads(body), sort_keys=True))))
f.write("\n\n")
f.write("{} /v{}{}{} HTTP/1.1\n".format(method, self._api_version, self._prefix, path))
if body:
f.write(json.dumps(json.loads(body), sort_keys=True, indent=4))
f.write("\n\n\n")
f.write("HTTP/1.1 {}\n".format(response.status))
for header, value in sorted(response.headers.items()):
if header == 'DATE':
# We fix the date otherwise the example is always different and create change in git
value = "Thu, 08 Jan 2015 16:09:15 GMT"
f.write("{}: {}\n".format(header, value))
f.write("\n")
if response.body:
f.write(json.dumps(json.loads(response.body.decode('utf-8')), sort_keys=True, indent=4))
f.write("\n")
def _example_file_path(self, method, path):
path = re.sub('[^a-z0-9]', '', path)
if len(self._prefix) > 0:
prefix = self._prefix.replace('/', '')
return "docs/api/examples/{}_{}_{}.txt".format(prefix, method.lower(), path)
else:
return "docs/api/examples/controller_{}_{}.txt".format(method.lower(), path)

@ -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
@ -15,27 +15,24 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This test suite check /version endpoint
It's also used for unittest the HTTP implementation.
"""
import sys
import pytest
from gns3server.config import Config
from gns3server.version import __version__
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_get(http_compute, windows_platform):
response = http_compute.get('/capabilities', example=True)
async def test_get(compute_api, windows_platform):
response = await compute_api.get('/capabilities')
assert response.status == 200
assert response.json == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'traceng', 'docker', 'iou'], 'version': __version__, 'platform': sys.platform}
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_get_on_gns3vm(http_compute, on_gns3vm):
response = http_compute.get('/capabilities', example=True)
async def test_get_on_gns3vm(compute_api, on_gns3vm):
response = await compute_api.get('/capabilities')
assert response.status == 200
assert response.json == {'node_types': ['cloud', 'ethernet_hub', 'ethernet_switch', 'nat', 'vpcs', 'virtualbox', 'dynamips', 'frame_relay_switch', 'atm_switch', 'qemu', 'vmware', 'traceng', 'docker', 'iou'], 'version': __version__, 'platform': sys.platform}

@ -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,121 +16,119 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import sys
import os
from tests.utils import asyncio_patch
from unittest.mock import patch
@pytest.fixture(scope="function")
def vm(http_compute, project):
response = http_compute.post("/projects/{project_id}/cloud/nodes".format(project_id=project.id), {"name": "Cloud 1"})
async def vm(compute_api, compute_project, on_gns3vm):
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._start_ubridge"):
response = await compute_api.post("/projects/{project_id}/cloud/nodes".format(project_id=compute_project.id), {"name": "Cloud 1"})
assert response.status == 201
return response.json
@pytest.yield_fixture(autouse=True)
def mock_ubridge():
"""
Avoid all interaction with ubridge
"""
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._start_ubridge"):
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._add_ubridge_connection"):
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._delete_ubridge_connection"):
yield
async def test_cloud_create(compute_api, compute_project):
def test_cloud_create(http_compute, project):
response = http_compute.post("/projects/{project_id}/cloud/nodes".format(project_id=project.id), {"name": "Cloud 1"}, example=True)
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._start_ubridge"):
response = await compute_api.post("/projects/{project_id}/cloud/nodes".format(project_id=compute_project.id), {"name": "Cloud 1"})
assert response.status == 201
assert response.route == "/projects/{project_id}/cloud/nodes"
assert response.json["name"] == "Cloud 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
async def test_cloud_get(compute_api, compute_project, vm):
def test_cloud_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/cloud/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.get("/projects/{project_id}/cloud/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/cloud/nodes/{node_id}"
assert response.json["name"] == "Cloud 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["status"] == "started"
def test_cloud_nio_create_udp(http_compute, vm):
response = http_compute.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
async def test_cloud_nio_create_udp(compute_api, vm):
params = {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"}
response = await compute_api.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_cloud_nio_update_udp(http_compute, vm):
http_compute.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.put("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
async def test_cloud_nio_update_udp(compute_api, vm):
params = {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"}
await compute_api.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
params["filters"] = {}
response = await compute_api.put("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode()
assert response.route == r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_cloud_delete_nio(http_compute, vm):
http_compute.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.delete("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_cloud_delete_nio(compute_api, vm):
params = {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"}
await compute_api.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud._start_ubridge"):
response = await compute_api.delete("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert response.route == r"/projects/{project_id}/cloud/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_cloud_delete(http_compute, vm):
response = http_compute.delete("/projects/{project_id}/cloud/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_cloud_delete(compute_api, vm):
response = await compute_api.delete("/projects/{project_id}/cloud/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
def test_cloud_update(http_compute, vm, tmpdir):
response = http_compute.put("/projects/{project_id}/cloud/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {
"name": "test"
},
example=True)
async def test_cloud_update(compute_api, vm):
response = await compute_api.put("/projects/{project_id}/cloud/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test"})
assert response.status == 200
assert response.json["name"] == "test"
def test_cloud_start_capture(http_compute, vm):
async def test_cloud_start_capture(compute_api, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_cloud_stop_capture(http_compute, vm):
async def test_cloud_stop_capture(compute_api, vm):
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_cloud_pcap(http_compute, vm, project):
async def test_cloud_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.builtin.nodes.cloud.Cloud.get_nio"):
with asyncio_patch("gns3server.compute.builtin.Builtin.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/cloud/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200

@ -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,15 +16,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import os
import stat
import sys
import uuid
import aiohttp
from tests.utils import asyncio_patch
from unittest.mock import patch, MagicMock, PropertyMock
from gns3server.compute.docker import Docker
from unittest.mock import patch
pytestmark = pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
@ -32,38 +28,50 @@ pytestmark = pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supp
@pytest.fixture
def base_params():
"""Return standard parameters"""
return {"name": "PC TEST 1", "image": "nginx", "start_command": "nginx-daemon", "adapters": 2, "environment": "YES=1\nNO=0", "console_type": "telnet", "console_resolution": "1280x1024", "extra_hosts": "test:127.0.0.1"}
@pytest.yield_fixture(autouse=True)
def mock_connection():
docker = Docker.instance()
docker._connected = True
docker._connector = MagicMock()
yield
Docker._instance = None
params = {
"name": "PC TEST 1",
"image": "nginx",
"start_command": "nginx-daemon",
"adapters": 2,
"environment": "YES=1\nNO=0",
"console_type": "telnet",
"console_resolution": "1280x1024",
"extra_hosts": "test:127.0.0.1"
}
return params
# @pytest.yield_fixture(autouse=True)
# def mock_connection():
#
# docker = Docker.instance()
# docker._connected = True
# docker._connector = MagicMock()
# yield
# Docker._instance = None
@pytest.fixture
def vm(http_compute, project, base_params):
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]) as mock_list:
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}) as mock:
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="exited") as mock:
response = http_compute.post("/projects/{project_id}/docker/nodes".format(project_id=project.id), base_params)
if response.status != 201:
print(response.body)
async def vm(compute_api, compute_project, base_params):
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
with asyncio_patch("gns3server.compute.docker.DockerVM._get_container_state", return_value="exited"):
response = await compute_api.post("/projects/{project_id}/docker/nodes".format(project_id=compute_project.id), base_params)
assert response.status == 201
return response.json
def test_docker_create(http_compute, project, base_params):
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]) as mock_list:
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}) as mock:
response = http_compute.post("/projects/{project_id}/docker/nodes".format(project_id=project.id), base_params)
async def test_docker_create(compute_api, compute_project, base_params):
with asyncio_patch("gns3server.compute.docker.Docker.list_images", return_value=[{"image": "nginx"}]):
with asyncio_patch("gns3server.compute.docker.Docker.query", return_value={"Id": "8bd8153ea8f5"}):
response = await compute_api.post("/projects/{project_id}/docker/nodes".format(project_id=compute_project.id), base_params)
assert response.status == 201
assert response.route == "/projects/{project_id}/docker/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["container_id"] == "8bd8153ea8f5"
assert response.json["image"] == "nginx:latest"
assert response.json["adapters"] == 2
@ -71,94 +79,106 @@ def test_docker_create(http_compute, project, base_params):
assert response.json["console_resolution"] == "1280x1024"
assert response.json["extra_hosts"] == "test:127.0.0.1"
def test_docker_start(http_compute, vm):
async def test_docker_start(compute_api, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_docker_stop(http_compute, vm):
async def test_docker_stop(compute_api, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.stop", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_docker_reload(http_compute, vm):
async def test_docker_reload(compute_api, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.restart", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_docker_delete(http_compute, vm):
async def test_docker_delete(compute_api, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.delete", return_value=True) as mock:
response = http_compute.delete("/projects/{project_id}/docker/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.delete("/projects/{project_id}/docker/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_docker_pause(http_compute, vm):
async def test_docker_pause(compute_api, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.pause", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/pause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/pause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_docker_unpause(http_compute, vm):
async def test_docker_unpause(compute_api, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.unpause", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/unpause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/unpause".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_docker_nio_create_udp(http_compute, vm):
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
async def test_docker_nio_create_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"}
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_docker_update_nio(http_compute, vm):
async def test_docker_update_nio(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.adapter_update_nio_binding") as mock:
response = http_compute.put("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
},
example=True)
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.adapter_update_nio_binding"):
response = await compute_api.put("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode()
assert response.route == r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_docker_delete_nio(http_compute, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.adapter_remove_nio_binding") as mock:
response = http_compute.delete("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_docker_delete_nio(compute_api, vm):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.adapter_remove_nio_binding"):
response = await compute_api.delete("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert response.route == r"/projects/{project_id}/docker/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_docker_update(http_compute, vm, tmpdir, free_console_port):
async def test_docker_update(compute_api, vm, free_console_port):
params = {
"name": "test",
"console": free_console_port,
"start_command": "yes",
"environment": "GNS3=1\nGNS4=0",
"extra_hosts": "test:127.0.0.1"
}
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.update") as mock:
response = http_compute.put("/projects/{project_id}/docker/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test",
"console": free_console_port,
"start_command": "yes",
"environment": "GNS3=1\nGNS4=0",
"extra_hosts": "test:127.0.0.1"},
example=True)
response = await compute_api.put("/projects/{project_id}/docker/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 200
assert response.json["name"] == "test"
@ -168,35 +188,30 @@ def test_docker_update(http_compute, vm, tmpdir, free_console_port):
assert response.json["extra_hosts"] == "test:127.0.0.1"
def test_docker_start_capture(http_compute, vm, tmpdir, project):
async def test_docker_start_capture(compute_api, vm):
with patch("gns3server.compute.docker.docker_vm.DockerVM.is_running", return_value=True) as mock:
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.start_capture") as start_capture:
with patch("gns3server.compute.docker.docker_vm.DockerVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.start_capture") as mock:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_docker_stop_capture(http_compute, vm, tmpdir, project):
async def test_docker_stop_capture(compute_api, vm):
with patch("gns3server.compute.docker.docker_vm.DockerVM.is_running", return_value=True) as mock:
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with patch("gns3server.compute.docker.docker_vm.DockerVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.docker.docker_vm.DockerVM.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
async def test_docker_duplicate(compute_api, vm):
def test_docker_duplicate(http_compute, vm):
params = {"destination_node_id": str(uuid.uuid4())}
with asyncio_patch("gns3server.compute.docker.Docker.duplicate_node", return_value=True) as mock:
response = http_compute.post(
"/projects/{project_id}/docker/nodes/{node_id}/duplicate".format(
project_id=vm["project_id"],
node_id=vm["node_id"]),
body={
"destination_node_id": str(uuid.uuid4())
},
example=True)
response = await compute_api.post("/projects/{project_id}/docker/nodes/{node_id}/duplicate".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 201

@ -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
@ -24,75 +24,83 @@ from tests.utils import asyncio_patch
# @pytest.yield_fixture(scope="module")
# def vm(http_compute, project):
# async def vm(compute_api, compute_project, fake_image):
#
# dynamips_path = "/fake/dynamips"
# params = {
# "name": "My router",
# "platform": "c3745",
# "image": fake_image,
# "ram": 128
# }
# with asyncio_patch("gns3server.compute.dynamips.nodes.router.Router.create", return_value=True) as mock:
# response = http_compute.post("/projects/{project_id}/dynamips/nodes".format(project_id=project.id), {"name": "My router",
# "platform": "c3745",
# "image": "somewhere",
# "ram": 128})
# response = await compute_api.post("/projects/{project_id}/dynamips/nodes".format(project_id=compute_project.id), params)
# assert mock.called
# assert response.status == 201
#
# with asyncio_patch("gns3server.compute.dynamips.Dynamips.find_dynamips", return_value=dynamips_path):
# yield response.json
# #with asyncio_patch("gns3server.compute.dynamips.Dynamips.find_dynamips", return_value=dynamips_path):
# # yield response.json
# async def test_dynamips_vm_create(compute_api, compute_project, fake_image):
#
# params = {
# "name": "My router",
# "platform": "c3745",
# "image": os.path.basename(fake_image),
# "ram": 128
# }
#
# def test_dynamips_vm_create(http_compute, project):
# print(fake_image)
#
# with asyncio_patch("gns3server.compute.dynamips.nodes.router.Router.create", return_value=True):
# response = http_compute.post("/projects/{project_id}/dynamips/nodes".format(project_id=project.id), {"name": "My router",
# "platform": "c3745",
# "image": "somewhere",
# "ram": 128},
# example=True)
# response = await compute_api.post("/projects/{project_id}/dynamips/nodes".format(project_id=compute_project.id), params)
# assert response.status == 201
# assert response.json["name"] == "My router"
# assert response.json["project_id"] == project.id
# assert response.json["project_id"] == compute_project.id
# assert response.json["dynamips_id"]
#
#
# def test_dynamips_vm_get(http_compute, project, vm):
# response = http_compute.get("/projects/{project_id}/dynamips/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
# def test_dynamips_vm_get(compute_api, project, vm):
# response = compute_api.get("/projects/{project_id}/dynamips/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
# assert response.status == 200
# assert response.route == "/projects/{project_id}/dynamips/nodes/{node_id}"
# assert response.json["name"] == "My router"
# assert response.json["project_id"] == project.id
#
#
# def test_dynamips_vm_start(http_compute, vm):
# def test_dynamips_vm_start(compute_api, vm):
# with asyncio_patch("gns3server.compute.dynamips.nodes.router.Router.start", return_value=True) as mock:
# response = http_compute.post("/projects/{project_id}/dynamips/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# response = compute_api.post("/projects/{project_id}/dynamips/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# assert mock.called
# assert response.status == 204
#
#
# def test_dynamips_vm_stop(http_compute, vm):
# def test_dynamips_vm_stop(compute_api, vm):
# with asyncio_patch("gns3server.compute.dynamips.nodes.router.Router.stop", return_value=True) as mock:
# response = http_compute.post("/projects/{project_id}/dynamips/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# response = compute_api.post("/projects/{project_id}/dynamips/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# assert mock.called
# assert response.status == 204
#
#
# def test_dynamips_vm_suspend(http_compute, vm):
# def test_dynamips_vm_suspend(compute_api, vm):
# with asyncio_patch("gns3server.compute.dynamips.nodes.router.Router.suspend", return_value=True) as mock:
# response = http_compute.post("/projects/{project_id}/dynamips/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# response = compute_api.post("/projects/{project_id}/dynamips/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# assert mock.called
# assert response.status == 204
#
#
# def test_dynamips_vm_resume(http_compute, vm):
# def test_dynamips_vm_resume(compute_api, vm):
# with asyncio_patch("gns3server.compute.dynamips.nodes.router.Router.resume", return_value=True) as mock:
# response = http_compute.post("/projects/{project_id}/dynamips/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# response = compute_api.post("/projects/{project_id}/dynamips/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]))
# assert mock.called
# assert response.status == 204
# def test_vbox_nio_create_udp(http_compute, vm):
# def test_vbox_nio_create_udp(compute_api, vm):
#
# with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_add_nio_binding') as mock:
# response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/nio".format(project_id=vm["project_id"],
# response = compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/nio".format(project_id=vm["project_id"],
# node_id=vm["node_id"]), {"type": "nio_udp",
# "lport": 4242,
# "rport": 4343,
@ -108,10 +116,10 @@ from tests.utils import asyncio_patch
# assert response.json["type"] == "nio_udp"
#
#
# def test_vbox_delete_nio(http_compute, vm):
# def test_vbox_delete_nio(compute_api, vm):
#
# with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_remove_nio_binding') as mock:
# response = http_compute.delete("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
# response = compute_api.delete("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
#
# assert mock.called
# args, kwgars = mock.call_args
@ -121,8 +129,8 @@ from tests.utils import asyncio_patch
# assert response.route == "/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_id:\d+}/nio"
#
#
# def test_vbox_update(http_compute, vm, free_console_port):
# response = http_compute.put("/projects/{project_id}/virtualbox/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test",
# def test_vbox_update(compute_api, vm, free_console_port):
# response = compute_api.put("/projects/{project_id}/virtualbox/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test",
# "console": free_console_port})
# assert response.status == 200
# assert response.json["name"] == "test"
@ -130,8 +138,9 @@ from tests.utils import asyncio_patch
@pytest.fixture
def fake_dynamips(tmpdir):
def fake_image(tmpdir):
"""Create a fake Dynamips image on disk"""
path = str(tmpdir / "7200.bin")
with open(path, "wb+") as f:
f.write(b'\x7fELF\x01\x02\x01')
@ -150,10 +159,10 @@ def fake_file(tmpdir):
return path
def test_images(http_compute, tmpdir, fake_dynamips, fake_file):
async def test_images(compute_api, tmpdir, fake_image, fake_file):
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmpdir)):
response = http_compute.get("/dynamips/images")
response = await compute_api.get("/dynamips/images")
assert response.status == 200
assert response.json == [{"filename": "7200.bin",
"path": "7200.bin",
@ -162,8 +171,9 @@ def test_images(http_compute, tmpdir, fake_dynamips, fake_file):
}]
def test_upload_image(http_compute, tmpdir, images_dir):
response = http_compute.post("/dynamips/images/test2", body="TEST", raw=True)
async def test_upload_image(compute_api, images_dir):
response = await compute_api.post("/dynamips/images/test2", body="TEST", raw=True)
assert response.status == 204
with open(os.path.join(images_dir, "IOS", "test2")) as f:
@ -174,12 +184,13 @@ def test_upload_image(http_compute, tmpdir, images_dir):
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
def test_upload_image_permission_denied(http_compute, tmpdir, images_dir):
async def test_upload_image_permission_denied(compute_api, tmpdir, images_dir):
os.makedirs(os.path.join(images_dir, "IOS"), exist_ok=True)
with open(os.path.join(images_dir, "IOS", "test2.tmp"), "w+") as f:
f.write("")
os.chmod(os.path.join(images_dir, "IOS", "test2.tmp"), 0)
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmpdir)):
response = http_compute.post("/dynamips/images/test2", body="TEST", raw=True)
response = await compute_api.post("/dynamips/images/test2", body="TEST", raw=True)
assert response.status == 409

@ -20,10 +20,9 @@ import os
import stat
import sys
import uuid
import aiohttp
from tests.utils import asyncio_patch
from unittest.mock import patch, MagicMock, PropertyMock
from unittest.mock import patch
pytestmark = pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
@ -42,28 +41,32 @@ def fake_iou_bin(images_dir):
@pytest.fixture
def base_params(tmpdir, fake_iou_bin):
"""Return standard parameters"""
return {"application_id": 42, "name": "PC TEST 1", "path": "iou.bin"}
@pytest.fixture
def vm(http_compute, project, base_params):
response = http_compute.post("/projects/{project_id}/iou/nodes".format(project_id=project.id), base_params)
async def vm(compute_api, compute_project, base_params):
response = await compute_api.post("/projects/{project_id}/iou/nodes".format(project_id=compute_project.id), base_params)
assert response.status == 201
return response.json
def startup_config_file(project, vm):
directory = os.path.join(project.path, "project-files", "iou", vm["node_id"])
def startup_config_file(compute_project, vm):
directory = os.path.join(compute_project.path, "project-files", "iou", vm["node_id"])
os.makedirs(directory, exist_ok=True)
return os.path.join(directory, "startup-config.cfg")
def test_iou_create(http_compute, project, base_params):
response = http_compute.post("/projects/{project_id}/iou/nodes".format(project_id=project.id), base_params)
async def test_iou_create(compute_api, compute_project, base_params):
response = await compute_api.post("/projects/{project_id}/iou/nodes".format(project_id=compute_project.id), base_params)
assert response.status == 201
assert response.route == "/projects/{project_id}/iou/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["serial_adapters"] == 2
assert response.json["ethernet_adapters"] == 2
assert response.json["ram"] == 256
@ -71,7 +74,8 @@ def test_iou_create(http_compute, project, base_params):
assert response.json["l1_keepalives"] is False
def test_iou_create_with_params(http_compute, project, base_params):
async def test_iou_create_with_params(compute_api, compute_project, base_params):
params = base_params
params["ram"] = 1024
params["nvram"] = 512
@ -81,11 +85,11 @@ def test_iou_create_with_params(http_compute, project, base_params):
params["startup_config_content"] = "hostname test"
params["use_default_iou_values"] = False
response = http_compute.post("/projects/{project_id}/iou/nodes".format(project_id=project.id), params, example=True)
response = await compute_api.post("/projects/{project_id}/iou/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.route == "/projects/{project_id}/iou/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["serial_adapters"] == 4
assert response.json["ethernet_adapters"] == 0
assert response.json["ram"] == 1024
@ -93,15 +97,15 @@ def test_iou_create_with_params(http_compute, project, base_params):
assert response.json["l1_keepalives"] is True
assert response.json["use_default_iou_values"] is False
with open(startup_config_file(project, response.json)) as f:
with open(startup_config_file(compute_project, response.json)) as f:
assert f.read() == "hostname test"
def test_iou_create_startup_config_already_exist(http_compute, project, base_params):
async def test_iou_create_startup_config_already_exist(compute_api, compute_project, base_params):
"""We don't erase a startup-config if already exist at project creation"""
node_id = str(uuid.uuid4())
startup_config_file_path = startup_config_file(project, {'node_id': node_id})
startup_config_file_path = startup_config_file(compute_project, {'node_id': node_id})
with open(startup_config_file_path, 'w+') as f:
f.write("echo hello")
@ -109,20 +113,21 @@ def test_iou_create_startup_config_already_exist(http_compute, project, base_par
params["node_id"] = node_id
params["startup_config_content"] = "hostname test"
response = http_compute.post("/projects/{project_id}/iou/nodes".format(project_id=project.id), params, example=True)
response = await compute_api.post("/projects/{project_id}/iou/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.route == "/projects/{project_id}/iou/nodes"
with open(startup_config_file(project, response.json)) as f:
with open(startup_config_file(compute_project, response.json)) as f:
assert f.read() == "echo hello"
def test_iou_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_iou_get(compute_api, compute_project, vm):
response = await compute_api.get("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/iou/nodes/{node_id}"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["serial_adapters"] == 2
assert response.json["ethernet_adapters"] == 2
assert response.json["ram"] == 256
@ -130,48 +135,53 @@ def test_iou_get(http_compute, project, vm):
assert response.json["l1_keepalives"] is False
def test_iou_start(http_compute, vm):
async def test_iou_start(compute_api, vm):
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 200
assert response.json["name"] == "PC TEST 1"
def test_iou_start_with_iourc(http_compute, vm, tmpdir):
body = {"iourc_content": "test"}
async def test_iou_start_with_iourc(compute_api, vm):
params = {"iourc_content": "test"}
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=body, example=True)
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 200
response = http_compute.get("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
response = await compute_api.get("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
def test_iou_stop(http_compute, vm):
async def test_iou_stop(compute_api, vm):
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.stop", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_iou_reload(http_compute, vm):
async def test_iou_reload(compute_api, vm):
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.reload", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_iou_delete(http_compute, vm):
async def test_iou_delete(compute_api, vm):
with asyncio_patch("gns3server.compute.iou.IOU.delete_node", return_value=True) as mock:
response = http_compute.delete("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.delete("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_iou_update(http_compute, vm, tmpdir, free_console_port, project):
async def test_iou_update(compute_api, vm, free_console_port):
params = {
"name": "test",
"console": free_console_port,
@ -182,7 +192,8 @@ def test_iou_update(http_compute, vm, tmpdir, free_console_port, project):
"l1_keepalives": True,
"use_default_iou_values": True,
}
response = http_compute.put("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params, example=True)
response = await compute_api.put("/projects/{project_id}/iou/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port
@ -194,120 +205,134 @@ def test_iou_update(http_compute, vm, tmpdir, free_console_port, project):
assert response.json["use_default_iou_values"] is True
def test_iou_nio_create_udp(http_compute, vm):
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
async def test_iou_nio_create_udp(compute_api, vm):
params = {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"}
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_iou_nio_update_udp(http_compute, vm):
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.put("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
async def test_iou_nio_update_udp(compute_api, vm):
params = {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"}
await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
params["filters"] = {}
response = await compute_api.put("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode()
assert response.route == r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_iou_nio_create_ethernet(http_compute, vm, ethernet_device):
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_ethernet",
"ethernet_device": ethernet_device,
},
example=True)
async def test_iou_nio_create_ethernet(compute_api, vm, ethernet_device):
params = {
"type": "nio_ethernet",
"ethernet_device": ethernet_device
}
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_ethernet"
assert response.json["ethernet_device"] == ethernet_device
def test_iou_nio_create_ethernet_different_port(http_compute, vm, ethernet_device):
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/3/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_ethernet",
"ethernet_device": ethernet_device,
},
example=False)
async def test_iou_nio_create_ethernet_different_port(compute_api, vm, ethernet_device):
params = {
"type": "nio_ethernet",
"ethernet_device": ethernet_device
}
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/3/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_ethernet"
assert response.json["ethernet_device"] == ethernet_device
def test_iou_nio_create_tap(http_compute, vm, ethernet_device):
async def test_iou_nio_create_tap(compute_api, vm, ethernet_device):
params = {
"type": "nio_tap",
"tap_device": ethernet_device
}
with patch("gns3server.compute.base_manager.BaseManager.has_privileged_access", return_value=True):
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_tap",
"tap_device": ethernet_device})
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_tap"
def test_iou_delete_nio(http_compute, vm):
http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.delete("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
assert response.status == 204
assert response.route == r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
async def test_iou_delete_nio(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
def test_iou_start_capture(http_compute, vm, tmpdir, project):
await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
response = await compute_api.delete("/projects/{project_id}/iou/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert response.route == r"/projects/{project_id}/iou/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
with patch("gns3server.compute.iou.iou_vm.IOUVM.is_running", return_value=True) as mock:
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
async def test_iou_start_capture(compute_api, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with patch("gns3server.compute.iou.iou_vm.IOUVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_iou_stop_capture(http_compute, vm, tmpdir, project):
with patch("gns3server.compute.iou.iou_vm.IOUVM.is_running", return_value=True) as mock:
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_iou_stop_capture(compute_api, vm):
with patch("gns3server.compute.iou.iou_vm.IOUVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_iou_pcap(http_compute, vm, project):
async def test_iou_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.iou.iou_vm.IOUVM.get_nio"):
with asyncio_patch("gns3server.compute.iou.IOU.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/iou/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200
def test_images(http_compute, fake_iou_bin):
async def test_images(compute_api, fake_iou_bin):
response = http_compute.get("/iou/images", example=True)
response = await compute_api.get("/iou/images")
assert response.status == 200
assert response.json == [{"filename": "iou.bin", "path": "iou.bin", "filesize": 7, "md5sum": "e573e8f5c93c6c00783f20c7a170aa6c"}]
def test_image_vm(http_compute, tmpdir):
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir),):
response = http_compute.post("/iou/images/test2", body="TEST", raw=True)
async def test_image_vm(compute_api, tmpdir):
with patch("gns3server.compute.IOU.get_images_directory", return_value=str(tmpdir)):
response = await compute_api.post("/iou/images/test2", body="TEST", raw=True)
assert response.status == 204
with open(str(tmpdir / "test2")) as f:
@ -318,15 +343,10 @@ def test_image_vm(http_compute, tmpdir):
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
def test_iou_duplicate(http_compute, vm):
async def test_iou_duplicate(compute_api, vm):
params = {"destination_node_id": str(uuid.uuid4())}
with asyncio_patch("gns3server.compute.iou.IOU.duplicate_node", return_value=True) as mock:
response = http_compute.post(
"/projects/{project_id}/iou/nodes/{node_id}/duplicate".format(
project_id=vm["project_id"],
node_id=vm["node_id"]),
body={
"destination_node_id": str(uuid.uuid4())
},
example=True)
response = await compute_api.post("/projects/{project_id}/iou/nodes/{node_id}/duplicate".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 201

@ -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,125 +16,128 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
import sys
import os
from tests.utils import asyncio_patch
from unittest.mock import patch
@pytest.fixture(scope="function")
def vm(http_compute, project, on_gns3vm):
response = http_compute.post("/projects/{project_id}/nat/nodes".format(project_id=project.id), {"name": "Nat 1"})
async def vm(compute_api, compute_project, ubridge_path, on_gns3vm):
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat._start_ubridge"):
response = await compute_api.post("/projects/{project_id}/nat/nodes".format(project_id=compute_project.id), {"name": "Nat 1"})
assert response.status == 201
return response.json
@pytest.yield_fixture(autouse=True)
def mock_ubridge():
"""
Avoid all interaction with ubridge
"""
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat._start_ubridge"):
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat._add_ubridge_connection"):
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat._delete_ubridge_connection"):
yield
async def test_nat_create(compute_api, compute_project, on_gns3vm):
def test_nat_create(http_compute, project, on_gns3vm):
response = http_compute.post("/projects/{project_id}/nat/nodes".format(project_id=project.id), {"name": "Nat 1"}, example=True)
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat._start_ubridge"):
response = await compute_api.post("/projects/{project_id}/nat/nodes".format(project_id=compute_project.id), {"name": "Nat 1"})
assert response.status == 201
assert response.route == "/projects/{project_id}/nat/nodes"
assert response.json["name"] == "Nat 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
def test_nat_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/nat/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_nat_get(compute_api, compute_project, vm):
response = await compute_api.get("/projects/{project_id}/nat/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/nat/nodes/{node_id}"
assert response.json["name"] == "Nat 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["status"] == "started"
def test_nat_nio_create_udp(http_compute, vm):
async def test_nat_nio_create_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.add_nio"):
response = http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
response = await compute_api.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_nat_nio_update_udp(http_compute, vm):
http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.put("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
async def test_nat_nio_update_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
await compute_api.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
params["filters"] = {}
response = await compute_api.put("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode()
assert response.route == r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_nat_delete_nio(http_compute, vm):
async def test_nat_delete_nio(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.add_nio"):
http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.remove_nio") as mock_remove_nio:
response = http_compute.delete("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
assert mock_remove_nio.called
await compute_api.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.remove_nio") as mock:
response = await compute_api.delete("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
assert response.route == r"/projects/{project_id}/nat/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_nat_delete(http_compute, vm):
response = http_compute.delete("/projects/{project_id}/nat/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_nat_delete(compute_api, vm):
response = await compute_api.delete("/projects/{project_id}/nat/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
def test_nat_update(http_compute, vm, tmpdir):
response = http_compute.put("/projects/{project_id}/nat/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {
"name": "test"
},
example=True)
async def test_nat_update(compute_api, vm):
response = await compute_api.put("/projects/{project_id}/nat/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test"})
assert response.status == 200
assert response.json["name"] == "test"
def test_nat_start_capture(http_compute, vm):
async def test_nat_start_capture(compute_api, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_nat_stop_capture(http_compute, vm):
async def test_nat_stop_capture(compute_api, vm):
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_nat_pcap(http_compute, vm, project):
async def test_nat_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.builtin.nodes.nat.Nat.get_nio"):
with asyncio_patch("gns3server.compute.builtin.Builtin.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/nat/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200

@ -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,15 +19,17 @@ import os
import pytest
def test_udp_allocation(http_compute, project):
response = http_compute.post('/projects/{}/ports/udp'.format(project.id), {}, example=True)
async def test_udp_allocation(compute_api, compute_project):
response = await compute_api.post('/projects/{}/ports/udp'.format(compute_project.id), {})
assert response.status == 201
assert response.json['udp_port'] is not None
# Netfifaces is not available on Travis
@pytest.mark.skipif(os.environ.get("TRAVIS", False) is not False, reason="Not supported on Travis")
def test_interfaces(http_compute):
response = http_compute.get('/network/interfaces', example=True)
async def test_interfaces(compute_api):
response = await compute_api.get('/network/interfaces')
assert response.status == 200
assert isinstance(response.json, list)

@ -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,16 +20,19 @@ import json
from gns3server.compute.notification_manager import NotificationManager
def test_notification_ws(http_compute, async_run):
ws = http_compute.websocket("/notifications/ws")
answer = async_run(ws.receive())
async def test_notification_ws(compute_api, http_client):
ws = await http_client.ws_connect(compute_api.get_url("/notifications/ws"))
answer = await ws.receive()
answer = json.loads(answer.data)
assert answer["action"] == "ping"
NotificationManager.instance().emit("test", {})
answer = async_run(ws.receive())
answer = await ws.receive()
answer = json.loads(answer.data)
assert answer["action"] == "test"
async_run(http_compute.close())
if not ws.closed:
await ws.close()

@ -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
@ -15,10 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This test suite check /project endpoint
"""
import pytest
import uuid
import os
@ -29,123 +26,128 @@ from gns3server.handlers.api.compute.project_handler import ProjectHandler
from gns3server.compute.project_manager import ProjectManager
def test_create_project_with_path(http_compute, tmpdir):
@pytest.fixture
def base_params(tmpdir):
"""Return standard parameters"""
params = {
"name": "test",
"path": str(tmpdir),
"project_id": str(uuid.uuid4())
}
return params
async def test_create_project_with_path(compute_api, base_params):
with patch("gns3server.compute.project.Project.is_local", return_value=True):
response = http_compute.post("/projects", {"name": "test", "path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"})
response = await compute_api.post("/projects", base_params)
assert response.status == 201
assert response.json["project_id"] == "00010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["project_id"] == base_params["project_id"]
async def test_create_project_with_path_and_empty_variables(compute_api, base_params):
def test_create_project_with_path_and_empty_variables(http_compute, tmpdir):
base_params["variables"] = None
with patch("gns3server.compute.project.Project.is_local", return_value=True):
response = http_compute.post("/projects", {
"name": "test",
"path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f",
"variables": None})
assert response.status == 201
assert response.json["project_id"] == "00010203-0405-0607-0809-0a0b0c0d0e0f"
response = await compute_api.post("/projects", base_params)
assert response.status == 201
assert response.json["project_id"] == base_params["project_id"]
def test_create_project_without_dir(http_compute):
query = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_compute.post("/projects", query, example=True)
assert response.status == 201
assert response.json["project_id"] == "10010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["name"] == "test"
async def test_create_project_without_dir(compute_api, base_params):
def test_create_project_with_uuid(http_compute):
query = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_compute.post("/projects", query)
del base_params["path"]
response = await compute_api.post("/projects", base_params)
assert response.status == 201
assert response.json["project_id"] == "30010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["name"] == "test"
assert response.json["project_id"] == base_params["project_id"]
assert response.json["name"] == base_params["name"]
def test_show_project(http_compute):
query = {"name": "test", "project_id": "40010203-0405-0607-0809-0a0b0c0d0e02"}
response = http_compute.post("/projects", query)
async def test_show_project(compute_api, base_params):
response = await compute_api.post("/projects", base_params)
assert response.status == 201
response = http_compute.get("/projects/40010203-0405-0607-0809-0a0b0c0d0e02", example=True)
response = await compute_api.get("/projects/{project_id}".format(project_id=base_params["project_id"]))
assert len(response.json.keys()) == 3
assert response.json["project_id"] == "40010203-0405-0607-0809-0a0b0c0d0e02"
assert response.json["name"] == "test"
assert response.json["project_id"] == base_params["project_id"]
assert response.json["name"] == base_params["name"]
assert response.json["variables"] is None
def test_show_project_invalid_uuid(http_compute):
response = http_compute.get("/projects/50010203-0405-0607-0809-0a0b0c0d0e42")
async def test_show_project_invalid_uuid(compute_api):
response = await compute_api.get("/projects/50010203-0405-0607-0809-0a0b0c0d0e42")
assert response.status == 404
def test_list_projects(http_compute):
async def test_list_projects(compute_api):
ProjectManager.instance()._projects = {}
query = {"name": "test", "project_id": "51010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_compute.post("/projects", query)
params = {"name": "test", "project_id": "51010203-0405-0607-0809-0a0b0c0d0e0f"}
response = await compute_api.post("/projects", params)
assert response.status == 201
query = {"name": "test", "project_id": "52010203-0405-0607-0809-0a0b0c0d0e0b"}
response = http_compute.post("/projects", query)
params = {"name": "test", "project_id": "52010203-0405-0607-0809-0a0b0c0d0e0b"}
response = await compute_api.post("/projects", params)
assert response.status == 201
response = http_compute.get("/projects", example=True)
response = await compute_api.get("/projects")
assert response.status == 200
assert len(response.json) == 2
assert "51010203-0405-0607-0809-0a0b0c0d0e0f" in [p["project_id"] for p in response.json]
def test_delete_project(http_compute, project):
async def test_delete_project(compute_api, compute_project):
with asyncio_patch("gns3server.compute.project.Project.delete", return_value=True) as mock:
response = http_compute.delete("/projects/{project_id}".format(project_id=project.id), example=True)
response = await compute_api.delete("/projects/{project_id}".format(project_id=compute_project.id))
assert response.status == 204
assert mock.called
def test_update_project(http_compute):
query = {"name": "test", "project_id": "51010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_compute.post("/projects", query)
async def test_update_project(compute_api, base_params):
response = await compute_api.post("/projects", base_params)
assert response.status == 201
query = {
"variables": [{"name": "TEST1", "value": "VAL1"}]
}
response = http_compute.put(
"/projects/{project_id}".format(project_id="51010203-0405-0607-0809-0a0b0c0d0e0f"),
query,
example=True
)
params = {"variables": [{"name": "TEST1", "value": "VAL1"}]}
response = await compute_api.put("/projects/{project_id}".format(project_id=base_params["project_id"]), params)
assert response.status == 200
assert response.json["variables"] == [{"name": "TEST1", "value": "VAL1"}]
def test_delete_project_invalid_uuid(http_compute):
response = http_compute.delete("/projects/{project_id}".format(project_id=uuid.uuid4()))
async def test_delete_project_invalid_uuid(compute_api):
response = await compute_api.delete("/projects/{project_id}".format(project_id=uuid.uuid4()))
assert response.status == 404
def test_close_project(http_compute, project):
async def test_close_project(compute_api, compute_project):
with asyncio_patch("gns3server.compute.project.Project.close", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/close".format(project_id=project.id), example=True)
response = await compute_api.post("/projects/{project_id}/close".format(project_id=compute_project.id))
assert response.status == 204
assert mock.called
def test_close_project_two_client_connected(http_compute, project):
ProjectHandler._notifications_listening = {project.id: 2}
async def test_close_project_two_client_connected(compute_api, compute_project):
ProjectHandler._notifications_listening = {compute_project.id: 2}
with asyncio_patch("gns3server.compute.project.Project.close", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/close".format(project_id=project.id), example=True)
response = await compute_api.post("/projects/{project_id}/close".format(project_id=compute_project.id))
assert response.status == 204
assert not mock.called
def test_close_project_invalid_uuid(http_compute):
response = http_compute.post("/projects/{project_id}/close".format(project_id=uuid.uuid4()))
async def test_close_project_invalid_uuid(compute_api):
response = await compute_api.post("/projects/{project_id}/close".format(project_id=uuid.uuid4()))
assert response.status == 404
def test_get_file(http_compute, tmpdir):
async def test_get_file(compute_api, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"projects_path": str(tmpdir)}):
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
@ -153,33 +155,33 @@ def test_get_file(http_compute, tmpdir):
with open(os.path.join(project.path, "hello"), "w+") as f:
f.write("world")
response = http_compute.get("/projects/{project_id}/files/hello".format(project_id=project.id), raw=True)
response = await compute_api.get("/projects/{project_id}/files/hello".format(project_id=project.id), raw=True)
assert response.status == 200
assert response.body == b"world"
response = http_compute.get("/projects/{project_id}/files/false".format(project_id=project.id), raw=True)
response = await compute_api.get("/projects/{project_id}/files/false".format(project_id=project.id), raw=True)
assert response.status == 404
response = http_compute.get("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
response = await compute_api.get("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
assert response.status == 404
def test_write_file(http_compute, tmpdir):
async def test_write_file(compute_api, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"projects_path": str(tmpdir)}):
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
response = http_compute.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True)
response = await compute_api.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True)
assert response.status == 200
with open(os.path.join(project.path, "hello")) as f:
assert f.read() == "world"
response = http_compute.post("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
response = await compute_api.post("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
assert response.status == 404
def test_stream_file(http_compute, tmpdir):
async def test_stream_file(compute_api, tmpdir):
with patch("gns3server.config.Config.get_section_config", return_value={"projects_path": str(tmpdir)}):
project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b")
@ -187,12 +189,12 @@ def test_stream_file(http_compute, tmpdir):
with open(os.path.join(project.path, "hello"), "w+") as f:
f.write("world")
response = http_compute.get("/projects/{project_id}/files/hello".format(project_id=project.id), raw=True)
response = await compute_api.get("/projects/{project_id}/files/hello".format(project_id=project.id), raw=True)
assert response.status == 200
assert response.body == b"world"
response = http_compute.get("/projects/{project_id}/files/false".format(project_id=project.id), raw=True)
response = await compute_api.get("/projects/{project_id}/files/false".format(project_id=project.id), raw=True)
assert response.status == 404
response = http_compute.get("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
response = await compute_api.get("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
assert response.status == 404

@ -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
@ -22,15 +22,16 @@ import sys
import stat
from tests.utils import asyncio_patch
from unittest.mock import patch
from gns3server.config import Config
@pytest.fixture
def fake_qemu_bin():
def fake_qemu_bin(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:
bin_path = os.path.join(os.environ["PATH"], "qemu-system-x86_64")
with open(bin_path, "w+") as f:
f.write("1")
@ -52,127 +53,139 @@ def fake_qemu_vm(images_dir):
@pytest.fixture
def base_params(tmpdir, fake_qemu_bin):
"""Return standard parameters"""
return {"name": "PC TEST 1", "qemu_path": fake_qemu_bin}
@pytest.fixture
def vm(http_compute, project, base_params):
response = http_compute.post("/projects/{project_id}/qemu/nodes".format(project_id=project.id), base_params)
async def vm(compute_api, compute_project, base_params):
response = await compute_api.post("/projects/{project_id}/qemu/nodes".format(project_id=compute_project.id), base_params)
assert response.status == 201
return response.json
def test_qemu_create(http_compute, project, base_params, fake_qemu_bin):
response = http_compute.post("/projects/{project_id}/qemu/nodes".format(project_id=project.id), base_params)
async def test_qemu_create(compute_api, compute_project, base_params, fake_qemu_bin):
response = await compute_api.post("/projects/{project_id}/qemu/nodes".format(project_id=compute_project.id), base_params)
assert response.status == 201
assert response.route == "/projects/{project_id}/qemu/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["qemu_path"] == fake_qemu_bin
assert response.json["platform"] == "x86_64"
def test_qemu_create_platform(http_compute, project, base_params, fake_qemu_bin):
async def test_qemu_create_platform(compute_api, compute_project, base_params, fake_qemu_bin):
base_params["qemu_path"] = None
base_params["platform"] = "x86_64"
response = http_compute.post("/projects/{project_id}/qemu/nodes".format(project_id=project.id), base_params)
response = await compute_api.post("/projects/{project_id}/qemu/nodes".format(project_id=compute_project.id), base_params)
assert response.status == 201
assert response.route == "/projects/{project_id}/qemu/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["qemu_path"] == fake_qemu_bin
assert response.json["platform"] == "x86_64"
def test_qemu_create_with_params(http_compute, project, base_params, fake_qemu_vm):
async def test_qemu_create_with_params(compute_api, compute_project, base_params, fake_qemu_vm):
params = base_params
params["ram"] = 1024
params["hda_disk_image"] = "linux载.img"
response = http_compute.post("/projects/{project_id}/qemu/nodes".format(project_id=project.id), params, example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.route == "/projects/{project_id}/qemu/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["ram"] == 1024
assert response.json["hda_disk_image"] == "linux载.img"
assert response.json["hda_disk_image_md5sum"] == "c4ca4238a0b923820dcc509a6f75849b"
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_qemu_create_with_project_file(http_compute, project, base_params, fake_qemu_vm):
response = http_compute.post("/projects/{project_id}/files/hello.img".format(project_id=project.id), body="world", raw=True)
async def test_qemu_create_with_project_file(compute_api, compute_project, base_params, fake_qemu_vm):
response = await compute_api.post("/projects/{project_id}/files/hello.img".format(project_id=compute_project.id), body="world", raw=True)
assert response.status == 200
params = base_params
params["hda_disk_image"] = "hello.img"
response = http_compute.post("/projects/{project_id}/qemu/nodes".format(project_id=project.id), params, example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.json["hda_disk_image"] == "hello.img"
assert response.json["hda_disk_image_md5sum"] == "7d793037a0760186574b0282f2f435e7"
def test_qemu_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_qemu_get(compute_api, compute_project, vm):
response = await compute_api.get("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/qemu/nodes/{node_id}"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["node_directory"] == os.path.join(project.path, "project-files", "qemu", vm["node_id"])
assert response.json["project_id"] == compute_project.id
assert response.json["node_directory"] == os.path.join(compute_project.path, "project-files", "qemu", vm["node_id"])
def test_qemu_start(http_compute, vm):
async def test_qemu_start(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 200
assert response.json["name"] == "PC TEST 1"
def test_qemu_stop(http_compute, vm):
async def test_qemu_stop(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.stop", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_qemu_reload(http_compute, vm):
async def test_qemu_reload(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.reload", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_qemu_suspend(http_compute, vm):
async def test_qemu_suspend(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.suspend", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_qemu_resume(http_compute, vm):
async def test_qemu_resume(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.resume", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_qemu_delete(http_compute, vm):
async def test_qemu_delete(compute_api, vm):
with asyncio_patch("gns3server.compute.qemu.Qemu.delete_node", return_value=True) as mock:
response = http_compute.delete("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.delete("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_qemu_update(http_compute, vm, free_console_port, project, fake_qemu_vm):
async def test_qemu_update(compute_api, vm, free_console_port, fake_qemu_vm):
params = {
"name": "test",
"console": free_console_port,
"ram": 1024,
"hdb_disk_image": "linux载.img"
}
response = http_compute.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params, example=True)
response = await compute_api.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port
@ -180,83 +193,97 @@ def test_qemu_update(http_compute, vm, free_console_port, project, fake_qemu_vm)
assert response.json["ram"] == 1024
def test_qemu_nio_create_udp(http_compute, vm):
async def test_qemu_nio_create_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.add_ubridge_udp_connection"):
http_compute.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"adapters": 2})
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
await compute_api.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"adapters": 2})
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_qemu_nio_update_udp(http_compute, vm):
http_compute.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"adapters": 2})
http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.put("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
async def test_qemu_nio_update_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
await compute_api.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"adapters": 2})
await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
params["filters"] = {}
response = await compute_api.put("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode()
assert response.route == r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_qemu_delete_nio(http_compute, vm):
async def test_qemu_delete_nio(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM._ubridge_send"):
http_compute.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"adapters": 2})
http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.delete("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
await compute_api.put("/projects/{project_id}/qemu/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"adapters": 2})
await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
response = await compute_api.delete("/projects/{project_id}/qemu/nodes/{node_id}/adapters/1/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert response.route == r"/projects/{project_id}/qemu/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_qemu_list_binaries(http_compute, vm):
async def test_qemu_list_binaries(compute_api, vm):
ret = [{"path": "/tmp/1", "version": "2.2.0"},
{"path": "/tmp/2", "version": "2.1.0"}]
with asyncio_patch("gns3server.compute.qemu.Qemu.binary_list", return_value=ret) as mock:
response = http_compute.get("/qemu/binaries".format(project_id=vm["project_id"]), example=True)
response = await compute_api.get("/qemu/binaries".format(project_id=vm["project_id"]))
assert mock.called_with(None)
assert response.status == 200
assert response.json == ret
def test_qemu_list_binaries_filter(http_compute, vm):
async def test_qemu_list_binaries_filter(compute_api, vm):
ret = [
{"path": "/tmp/x86_64", "version": "2.2.0"},
{"path": "/tmp/alpha", "version": "2.1.0"},
{"path": "/tmp/i386", "version": "2.1.0"}
]
with asyncio_patch("gns3server.compute.qemu.Qemu.binary_list", return_value=ret) as mock:
response = http_compute.get("/qemu/binaries".format(project_id=vm["project_id"]), body={"archs": ["i386"]}, example=True)
response = await compute_api.get("/qemu/binaries".format(project_id=vm["project_id"]), body={"archs": ["i386"]})
assert response.status == 200
assert mock.called_with(["i386"])
assert response.json == ret
def test_images(http_compute, tmpdir, fake_qemu_vm):
async def test_images(compute_api, fake_qemu_vm):
response = http_compute.get("/qemu/images")
response = await compute_api.get("/qemu/images")
assert response.status == 200
assert response.json == [{"filename": "linux载.img", "path": "linux载.img", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}]
def test_upload_image(http_compute, tmpdir):
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
response = http_compute.post("/qemu/images/test2使", body="TEST", raw=True)
async def test_upload_image(compute_api, tmpdir):
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)):
response = await compute_api.post("/qemu/images/test2使", body="TEST", raw=True)
assert response.status == 204
with open(str(tmpdir / "test2使")) as f:
@ -267,9 +294,10 @@ def test_upload_image(http_compute, tmpdir):
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
def test_upload_image_ova(http_compute, tmpdir):
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
response = http_compute.post("/qemu/images/test2.ova/test2.vmdk", body="TEST", raw=True)
async def test_upload_image_ova(compute_api, tmpdir):
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)):
response = await compute_api.post("/qemu/images/test2.ova/test2.vmdk", body="TEST", raw=True)
assert response.status == 204
with open(str(tmpdir / "test2.ova" / "test2.vmdk")) as f:
@ -280,24 +308,27 @@ def test_upload_image_ova(http_compute, tmpdir):
assert checksum == "033bd94b1168d7e4f0d644c3c95e35bf"
def test_upload_image_forbiden_location(http_compute, tmpdir):
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
response = http_compute.post("/qemu/images/../../test2", body="TEST", raw=True)
async def test_upload_image_forbiden_location(compute_api, tmpdir):
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)):
response = await compute_api.post("/qemu/images/../../test2", body="TEST", raw=True)
assert response.status == 404
def test_upload_image_permission_denied(http_compute, tmpdir):
async def test_upload_image_permission_denied(compute_api, tmpdir):
with open(str(tmpdir / "test2.tmp"), "w+") as f:
f.write("")
os.chmod(str(tmpdir / "test2.tmp"), 0)
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir),):
response = http_compute.post("/qemu/images/test2", body="TEST", raw=True)
with patch("gns3server.compute.Qemu.get_images_directory", return_value=str(tmpdir)):
response = await compute_api.post("/qemu/images/test2", body="TEST", raw=True)
assert response.status == 409
def test_create_img_relative(http_compute):
body = {
async def test_create_img_relative(compute_api):
params = {
"qemu_img": "/tmp/qemu-img",
"path": "hda.qcow2",
"format": "qcow2",
@ -308,17 +339,14 @@ def test_create_img_relative(http_compute):
"size": 100
}
with asyncio_patch("gns3server.compute.Qemu.create_disk"):
response = http_compute.post("/qemu/img", body=body, example=True)
response = await compute_api.post("/qemu/img", params)
assert response.status == 201
def test_create_img_absolute_non_local(http_compute):
async def test_create_img_absolute_non_local(compute_api, config):
config = Config.instance()
config.set("Server", "local", "false")
body = {
params = {
"qemu_img": "/tmp/qemu-img",
"path": "/tmp/hda.qcow2",
"format": "qcow2",
@ -329,17 +357,14 @@ def test_create_img_absolute_non_local(http_compute):
"size": 100
}
with asyncio_patch("gns3server.compute.Qemu.create_disk"):
response = http_compute.post("/qemu/img", body=body, example=True)
response = await compute_api.post("/qemu/img", params)
assert response.status == 403
def test_create_img_absolute_local(http_compute):
async def test_create_img_absolute_local(compute_api, config):
config = Config.instance()
config.set("Server", "local", "true")
body = {
params = {
"qemu_img": "/tmp/qemu-img",
"path": "/tmp/hda.qcow2",
"format": "qcow2",
@ -350,54 +375,53 @@ def test_create_img_absolute_local(http_compute):
"size": 100
}
with asyncio_patch("gns3server.compute.Qemu.create_disk"):
response = http_compute.post("/qemu/img", body=body, example=True)
response = await compute_api.post("/qemu/img", params)
assert response.status == 201
def test_capabilities(http_compute):
async def test_capabilities(compute_api):
with asyncio_patch("gns3server.compute.Qemu.get_kvm_archs", return_value=["x86_64"]):
response = http_compute.get("/qemu/capabilities", example=True)
response = await compute_api.get("/qemu/capabilities")
assert response.json["kvm"] == ["x86_64"]
def test_qemu_duplicate(http_compute, vm):
async def test_qemu_duplicate(compute_api, vm):
params = {"destination_node_id": str(uuid.uuid4())}
with asyncio_patch("gns3server.compute.qemu.Qemu.duplicate_node", return_value=True) as mock:
response = http_compute.post(
"/projects/{project_id}/qemu/nodes/{node_id}/duplicate".format(
project_id=vm["project_id"],
node_id=vm["node_id"]),
body={
"destination_node_id": str(uuid.uuid4())
},
example=True)
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/duplicate".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 201
def test_qemu_start_capture(http_compute, vm):
async def test_qemu_start_capture(compute_api, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with patch("gns3server.compute.qemu.qemu_vm.QemuVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_qemu_stop_capture(http_compute, vm):
async def test_qemu_stop_capture(compute_api, vm):
with patch("gns3server.compute.qemu.qemu_vm.QemuVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_qemu_pcap(http_compute, vm, project):
async def test_qemu_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.qemu.qemu_vm.QemuVM.get_nio"):
with asyncio_patch("gns3server.compute.qemu.Qemu.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/qemu/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200

@ -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
@ -15,30 +15,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This test suite check /version endpoint
It's also used for unittest the HTTP implementation.
"""
from gns3server.config import Config
from gns3server.version import __version__
def test_version_output(http_compute):
config = Config.instance()
config.set("Server", "local", "true")
async def test_version_output(compute_api, config):
response = http_compute.get('/version', example=True)
config.set("Server", "local", "true")
response = await compute_api.get('/version')
assert response.status == 200
assert response.json == {'local': True, 'version': __version__}
def test_debug_output(http_compute):
response = http_compute.get('/debug')
async def test_debug_output(compute_api):
response = await compute_api.get('/debug')
assert response.status == 200
def test_statistics_output(http_compute):
response = http_compute.get('/statistics')
async def test_statistics_output(compute_api):
response = await compute_api.get('/statistics')
assert response.status == 200

@ -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,157 +17,174 @@
import pytest
import uuid
import sys
import os
from tests.utils import asyncio_patch
from unittest.mock import patch
@pytest.fixture(scope="function")
def vm(http_compute, project):
response = http_compute.post("/projects/{project_id}/traceng/nodes".format(project_id=project.id), {"name": "TraceNG TEST 1"})
async def vm(compute_api, compute_project):
params = {"name": "TraceNG TEST 1"}
response = await compute_api.post("/projects/{project_id}/traceng/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
return response.json
def test_traceng_create(http_compute, project):
response = http_compute.post("/projects/{project_id}/traceng/nodes".format(project_id=project.id), {"name": "TraceNG TEST 1"}, example=True)
async def test_traceng_create(compute_api, compute_project):
params = {"name": "TraceNG TEST 1"}
response = await compute_api.post("/projects/{project_id}/traceng/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.route == "/projects/{project_id}/traceng/nodes"
assert response.json["name"] == "TraceNG TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
def test_traceng_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/traceng/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_traceng_get(compute_api, compute_project, vm):
response = await compute_api.get("/projects/{project_id}/traceng/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/traceng/nodes/{node_id}"
assert response.json["name"] == "TraceNG TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["status"] == "stopped"
def test_traceng_nio_create_udp(http_compute, vm):
async def test_traceng_nio_create_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.add_ubridge_udp_connection"):
response = http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_traceng_nio_update_udp(http_compute, vm):
async def test_traceng_nio_update_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.add_ubridge_udp_connection"):
response = http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
response = http_compute.put("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
params["filters"] = {}
response = await compute_api.put("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode("utf-8")
assert response.route == r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_traceng_delete_nio(http_compute, vm):
async def test_traceng_delete_nio(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._ubridge_send"):
http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.delete("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
response = await compute_api.delete("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204, response.body.decode()
assert response.route == r"/projects/{project_id}/traceng/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_traceng_start(http_compute, vm):
async def test_traceng_start(compute_api, vm):
params = {"destination": "192.168.1.2"}
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"destination": "192.168.1.2"}, example=True)
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 200
assert response.json["name"] == "TraceNG TEST 1"
def test_traceng_stop(http_compute, vm):
async def test_traceng_stop(compute_api, vm):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.stop", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_traceng_reload(http_compute, vm):
async def test_traceng_reload(compute_api, vm):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.reload", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_traceng_delete(http_compute, vm):
async def test_traceng_delete(compute_api, vm):
with asyncio_patch("gns3server.compute.traceng.TraceNG.delete_node", return_value=True) as mock:
response = http_compute.delete("/projects/{project_id}/traceng/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.delete("/projects/{project_id}/traceng/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_traceng_duplicate(http_compute, vm):
async def test_traceng_duplicate(compute_api, vm):
params = {"destination_node_id": str(uuid.uuid4())}
with asyncio_patch("gns3server.compute.traceng.TraceNG.duplicate_node", return_value=True) as mock:
response = http_compute.post(
"/projects/{project_id}/traceng/nodes/{node_id}/duplicate".format(
project_id=vm["project_id"],
node_id=vm["node_id"]),
body={
"destination_node_id": str(uuid.uuid4())
},
example=True)
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/duplicate".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 201
def test_traceng_update(http_compute, vm, tmpdir, free_console_port):
response = http_compute.put("/projects/{project_id}/traceng/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test",
"ip_address": "192.168.1.1",
},
example=True)
async def test_traceng_update(compute_api, vm):
params = {
"name": "test",
"ip_address": "192.168.1.1"
}
response = await compute_api.put("/projects/{project_id}/traceng/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["ip_address"] == "192.168.1.1"
def test_traceng_start_capture(http_compute, vm):
async def test_traceng_start_capture(compute_api, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_traceng_stop_capture(http_compute, vm):
async def test_traceng_stop_capture(compute_api, vm):
with patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_traceng_pcap(http_compute, vm, project):
async def test_traceng_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM.get_nio"):
with asyncio_patch("gns3server.compute.traceng.TraceNG.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/traceng/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200

@ -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,89 +20,100 @@ from tests.utils import asyncio_patch
from unittest.mock import patch
@pytest.yield_fixture(scope="function")
def vm(http_compute, project, monkeypatch):
@pytest.fixture(scope="function")
async def vm(compute_api, compute_project):
vboxmanage_path = "/fake/VboxManage"
params = {
"name": "VMTEST",
"vmname": "VMTEST",
"linked_clone": False
}
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.create", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes".format(
project_id=project.id), {"name": "VMTEST",
"vmname": "VMTEST",
"linked_clone": False})
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes".format(project_id=compute_project.id), params)
assert mock.called
assert response.status == 201
with patch("gns3server.compute.virtualbox.VirtualBox.find_vboxmanage", return_value=vboxmanage_path):
yield response.json
return response.json
def test_vbox_create(http_compute, project):
async def test_vbox_create(compute_api, compute_project):
params = {
"name": "VM1",
"vmname": "VM1",
"linked_clone": False
}
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.create", return_value=True):
response = http_compute.post("/projects/{project_id}/virtualbox/nodes".format(project_id=project.id), {"name": "VM1",
"vmname": "VM1",
"linked_clone": False},
example=True)
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.json["name"] == "VM1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
async def test_vbox_get(compute_api, compute_project, vm):
def test_vbox_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/virtualbox/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.get("/projects/{project_id}/virtualbox/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/virtualbox/nodes/{node_id}"
assert response.json["name"] == "VMTEST"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
def test_vbox_start(http_compute, vm):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.check_hw_virtualization", return_value=True) as mock:
async def test_vbox_start(compute_api, vm):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.check_hw_virtualization", return_value=True):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vbox_stop(http_compute, vm):
async def test_vbox_stop(compute_api, vm):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.stop", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vbox_suspend(http_compute, vm):
async def test_vbox_suspend(compute_api, vm):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.suspend", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vbox_resume(http_compute, vm):
async def test_vbox_resume(compute_api, vm):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.resume", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vbox_reload(http_compute, vm):
async def test_vbox_reload(compute_api, vm):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.reload", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vbox_nio_create_udp(http_compute, vm):
async def test_vbox_nio_create_udp(compute_api, vm):
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_add_nio_binding') as mock:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"],
node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_add_nio_binding') as mock:
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
args, kwgars = mock.call_args
assert args[0] == 0
@ -112,30 +123,29 @@ def test_vbox_nio_create_udp(http_compute, vm):
assert response.json["type"] == "nio_udp"
def test_virtualbox_nio_update_udp(http_compute, vm):
async def test_virtualbox_nio_update_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}
}
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.ethernet_adapters'):
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_remove_nio_binding') as mock:
response = http_compute.put("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(
project_id=vm["project_id"],
node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_remove_nio_binding'):
response = await compute_api.put("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode()
assert response.route == r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_vbox_delete_nio(http_compute, vm):
async def test_vbox_delete_nio(compute_api, vm):
with asyncio_patch('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.adapter_remove_nio_binding') as mock:
response = http_compute.delete("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.delete("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
args, kwgars = mock.call_args
assert args[0] == 0
@ -144,38 +154,46 @@ def test_vbox_delete_nio(http_compute, vm):
assert response.route == r"/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_vbox_update(http_compute, vm, free_console_port):
response = http_compute.put("/projects/{project_id}/virtualbox/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test",
"console": free_console_port},
example=True)
async def test_vbox_update(compute_api, vm, free_console_port):
params = {
"name": "test",
"console": free_console_port
}
response = await compute_api.put("/projects/{project_id}/virtualbox/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port
def test_virtualbox_start_capture(http_compute, vm):
async def test_virtualbox_start_capture(compute_api, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_virtualbox_stop_capture(http_compute, vm):
async def test_virtualbox_stop_capture(compute_api, vm):
with patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_virtualbox_pcap(http_compute, vm, project):
async def test_virtualbox_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.get_nio"):
with asyncio_patch("gns3server.compute.virtualbox.VirtualBox.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/virtualbox/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200

@ -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,13 +21,16 @@ from unittest.mock import patch
@pytest.fixture(scope="function")
def vm(http_compute, project, vmx_path):
async def vm(compute_api, compute_project, vmx_path):
params = {
"name": "VMTEST",
"vmx_path": vmx_path,
"linked_clone": False
}
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.create", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vmware/nodes".format(project_id=project.id), {
"name": "VMTEST",
"vmx_path": vmx_path,
"linked_clone": False})
response = await compute_api.post("/projects/{project_id}/vmware/nodes".format(project_id=compute_project.id), params)
assert mock.called
assert response.status == 201, response.body.decode()
return response.json
@ -38,79 +41,90 @@ def vmx_path(tmpdir):
"""
Return a fake VMX file
"""
path = str(tmpdir / "test.vmx")
with open(path, 'w+') as f:
f.write("1")
return path
def test_vmware_create(http_compute, project, vmx_path):
async def test_vmware_create(compute_api, compute_project, vmx_path):
params = {
"name": "VM1",
"vmx_path": vmx_path,
"linked_clone": False
}
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.create", return_value=True):
response = http_compute.post("/projects/{project_id}/vmware/nodes".format(project_id=project.id), {
"name": "VM1",
"vmx_path": vmx_path,
"linked_clone": False},
example=True)
response = await compute_api.post("/projects/{project_id}/vmware/nodes".format(project_id=compute_project.id), params)
assert response.status == 201, response.body.decode()
assert response.json["name"] == "VM1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
def test_vmware_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/vmware/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
async def test_vmware_get(compute_api, compute_project, vm):
response = await compute_api.get("/projects/{project_id}/vmware/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/vmware/nodes/{node_id}"
assert response.json["name"] == "VMTEST"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
def test_vmware_start(http_compute, vm):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.check_hw_virtualization", return_value=True) as mock:
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
assert mock.called
async def test_vmware_start(compute_api, vm):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.check_hw_virtualization", return_value=True) as mock1:
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.start", return_value=True) as mock2:
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock1.called
assert mock2.called
assert response.status == 204
def test_vmware_stop(http_compute, vm):
async def test_vmware_stop(compute_api, vm):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.stop", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vmware_suspend(http_compute, vm):
async def test_vmware_suspend(compute_api, vm):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.suspend", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/suspend".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vmware_resume(http_compute, vm):
async def test_vmware_resume(compute_api, vm):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.resume", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/resume".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vmware_reload(http_compute, vm):
async def test_vmware_reload(compute_api, vm):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.reload", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vmware_nio_create_udp(http_compute, vm):
async def test_vmware_nio_create_udp(compute_api, vm):
with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM.adapter_add_nio_binding') as mock:
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"],
node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM.adapter_add_nio_binding') as mock:
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
args, kwgars = mock.call_args
assert args[0] == 0
@ -120,30 +134,29 @@ def test_vmware_nio_create_udp(http_compute, vm):
assert response.json["type"] == "nio_udp"
def test_vmware_nio_update_udp(http_compute, vm):
async def test_vmware_nio_update_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}
}
with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM._ubridge_send'):
with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM.ethernet_adapters'):
with patch('gns3server.compute.vmware.vmware_vm.VMwareVM._get_vnet') as mock:
response = http_compute.put("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(
project_id=vm["project_id"],
node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
assert response.status == 201, response.body.decode()
response = await compute_api.put("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_vmware_delete_nio(http_compute, vm):
async def test_vmware_delete_nio(compute_api, vm):
with asyncio_patch('gns3server.compute.vmware.vmware_vm.VMwareVM.adapter_remove_nio_binding') as mock:
response = http_compute.delete("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.delete("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
args, kwgars = mock.call_args
assert args[0] == 0
@ -152,37 +165,47 @@ def test_vmware_delete_nio(http_compute, vm):
assert response.route == r"/projects/{project_id}/vmware/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_vmware_update(http_compute, vm, free_console_port):
response = http_compute.put("/projects/{project_id}/vmware/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test",
"console": free_console_port},
example=True)
async def test_vmware_update(compute_api, vm, free_console_port):
params = {
"name": "test",
"console": free_console_port
}
response = await compute_api.put("/projects/{project_id}/vmware/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port
def test_vmware_start_capture(http_compute, vm):
async def test_vmware_start_capture(compute_api, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with patch("gns3server.compute.vmware.vmware_vm.VMwareVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_vmware_stop_capture(http_compute, vm):
async def test_vmware_stop_capture(compute_api, vm):
with patch("gns3server.compute.vmware.vmware_vm.VMwareVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_vmware_pcap(http_compute, vm, project):
async def test_vmware_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.vmware.vmware_vm.VMwareVM.get_nio"):
with asyncio_patch("gns3server.compute.vmware.VMware.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/vmware/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200

@ -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,168 +21,200 @@ from tests.utils import asyncio_patch
from unittest.mock import patch
@pytest.fixture(scope="function")
def vm(http_compute, project):
response = http_compute.post("/projects/{project_id}/vpcs/nodes".format(project_id=project.id), {"name": "PC TEST 1"})
@pytest.fixture
async def vm(compute_api, compute_project):
params = {"name": "PC TEST 1"}
response = await compute_api.post("/projects/{project_id}/vpcs/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
return response.json
def test_vpcs_create(http_compute, project):
response = http_compute.post("/projects/{project_id}/vpcs/nodes".format(project_id=project.id), {"name": "PC TEST 1"}, example=True)
async def test_vpcs_create(compute_api, compute_project):
params = {"name": "PC TEST 1"}
response = await compute_api.post("/projects/{project_id}/vpcs/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.route == "/projects/{project_id}/vpcs/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
async def test_vpcs_get(compute_api, compute_project, vm):
def test_vpcs_get(http_compute, project, vm):
response = http_compute.get("/projects/{project_id}/vpcs/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.get("/projects/{project_id}/vpcs/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 200
assert response.route == "/projects/{project_id}/vpcs/nodes/{node_id}"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["status"] == "stopped"
def test_vpcs_create_startup_script(http_compute, project):
response = http_compute.post("/projects/{project_id}/vpcs/nodes".format(project_id=project.id), {"name": "PC TEST 1", "startup_script": "ip 192.168.1.2\necho TEST"})
async def test_vpcs_create_startup_script(compute_api, compute_project):
params = {
"name": "PC TEST 1",
"startup_script": "ip 192.168.1.2\necho TEST"
}
response = await compute_api.post("/projects/{project_id}/vpcs/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.route == "/projects/{project_id}/vpcs/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
async def test_vpcs_create_port(compute_api, compute_project, free_console_port):
def test_vpcs_create_port(http_compute, project, free_console_port):
response = http_compute.post("/projects/{project_id}/vpcs/nodes".format(project_id=project.id), {"name": "PC TEST 1", "console": free_console_port})
params = {
"name": "PC TEST 1",
"console": free_console_port
}
response = await compute_api.post("/projects/{project_id}/vpcs/nodes".format(project_id=compute_project.id), params)
assert response.status == 201
assert response.route == "/projects/{project_id}/vpcs/nodes"
assert response.json["name"] == "PC TEST 1"
assert response.json["project_id"] == project.id
assert response.json["project_id"] == compute_project.id
assert response.json["console"] == free_console_port
def test_vpcs_nio_create_udp(http_compute, vm):
async def test_vpcs_nio_create_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.add_ubridge_udp_connection"):
response = http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"},
example=True)
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
assert response.route == r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_vpcs_nio_update_udp(http_compute, vm):
async def test_vpcs_nio_update_udp(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.add_ubridge_udp_connection"):
response = http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201
response = http_compute.put("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]),
{
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1",
"filters": {}},
example=True)
params["filters"] = {}
response = await compute_api.put("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 201, response.body.decode("utf-8")
assert response.route == r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
assert response.json["type"] == "nio_udp"
def test_vpcs_delete_nio(http_compute, vm):
async def test_vpcs_delete_nio(compute_api, vm):
params = {
"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"
}
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._ubridge_send"):
http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"type": "nio_udp",
"lport": 4242,
"rport": 4343,
"rhost": "127.0.0.1"})
response = http_compute.delete("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
response = await compute_api.delete("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/nio".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204, response.body.decode()
assert response.route == r"/projects/{project_id}/vpcs/nodes/{node_id}/adapters/{adapter_number:\d+}/ports/{port_number:\d+}/nio"
def test_vpcs_start(http_compute, vm):
async def test_vpcs_start(compute_api, vm):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/start".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 200
assert response.json["name"] == "PC TEST 1"
def test_vpcs_stop(http_compute, vm):
async def test_vpcs_stop(compute_api, vm):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.stop", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/stop".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vpcs_reload(http_compute, vm):
async def test_vpcs_reload(compute_api, vm):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.reload", return_value=True) as mock:
response = http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/reload".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vpcs_delete(http_compute, vm):
async def test_vpcs_delete(compute_api, vm):
with asyncio_patch("gns3server.compute.vpcs.VPCS.delete_node", return_value=True) as mock:
response = http_compute.delete("/projects/{project_id}/vpcs/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
response = await compute_api.delete("/projects/{project_id}/vpcs/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert mock.called
assert response.status == 204
def test_vpcs_duplicate(http_compute, vm):
async def test_vpcs_duplicate(compute_api, vm):
params = {"destination_node_id": str(uuid.uuid4())}
with asyncio_patch("gns3server.compute.vpcs.VPCS.duplicate_node", return_value=True) as mock:
response = http_compute.post(
"/projects/{project_id}/vpcs/nodes/{node_id}/duplicate".format(
project_id=vm["project_id"],
node_id=vm["node_id"]),
body={
"destination_node_id": str(uuid.uuid4())
},
example=True)
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/duplicate".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert mock.called
assert response.status == 201
def test_vpcs_update(http_compute, vm, tmpdir, free_console_port):
response = http_compute.put("/projects/{project_id}/vpcs/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), {"name": "test",
"console": free_console_port,
},
example=True)
async def test_vpcs_update(compute_api, vm, free_console_port):
console_port = free_console_port
params = {
"name": "test",
"console": console_port
}
response = await compute_api.put("/projects/{project_id}/vpcs/nodes/{node_id}".format(project_id=vm["project_id"], node_id=vm["node_id"]), params)
assert response.status == 200
assert response.json["name"] == "test"
assert response.json["console"] == free_console_port
assert response.json["console"] == console_port
async def test_vpcs_start_capture(compute_api, vm):
def test_vpcs_start_capture(http_compute, vm):
params = {
"capture_file_name": "test.pcap",
"data_link_type": "DLT_EN10MB"
}
with patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_capture") as start_capture:
params = {"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}
response = http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params, example=True)
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_capture") as mock:
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/start_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), body=params)
assert response.status == 200
assert start_capture.called
assert mock.called
assert "test.pcap" in response.json["pcap_file_path"]
def test_vpcs_stop_capture(http_compute, vm):
async def test_vpcs_stop_capture(compute_api, vm):
with patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.is_running", return_value=True):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.stop_capture") as stop_capture:
response = http_compute.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]), example=True)
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.stop_capture") as mock:
response = await compute_api.post("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/stop_capture".format(project_id=vm["project_id"], node_id=vm["node_id"]))
assert response.status == 204
assert stop_capture.called
assert mock.called
def test_vpcs_pcap(http_compute, vm, project):
async def test_vpcs_pcap(compute_api, vm, compute_project):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.get_nio"):
with asyncio_patch("gns3server.compute.vpcs.VPCS.stream_pcap_file"):
response = http_compute.get("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=project.id, node_id=vm["node_id"]), raw=True)
response = await compute_api.get("/projects/{project_id}/vpcs/nodes/{node_id}/adapters/0/ports/0/pcap".format(project_id=compute_project.id, node_id=vm["node_id"]), raw=True)
assert response.status == 200

@ -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,9 +16,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
def test_appliances_list(http_controller, controller, async_run):
async def test_appliances_list(controller_api):
controller.appliance_manager.load_appliances()
response = http_controller.get("/appliances", example=True)
response = await controller_api.get("/appliances")
assert response.status == 200
assert len(response.json) > 0

@ -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
@ -19,27 +19,26 @@ import unittest
from tests.utils import asyncio_patch
def test_compute_create_without_id(http_controller, controller):
async def test_compute_create_without_id(controller_api, controller):
params = {
"protocol": "http",
"host": "localhost",
"port": 84,
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params, example=True)
"password": "secure"}
response = await controller_api.post("/computes", params)
assert response.status == 201
assert response.route == "/computes"
assert response.json["user"] == "julien"
assert response.json["compute_id"] is not None
assert "password" not in response.json
assert len(controller.computes) == 1
assert controller.computes[response.json["compute_id"]].host == "localhost"
def test_compute_create_with_id(http_controller, controller):
async def test_compute_create_with_id(controller_api, controller):
params = {
"compute_id": "my_compute_id",
@ -47,9 +46,9 @@ def test_compute_create_with_id(http_controller, controller):
"host": "localhost",
"port": 84,
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params, example=True)
"password": "secure"}
response = await controller_api.post("/computes", params)
assert response.status == 201
assert response.route == "/computes"
assert response.json["user"] == "julien"
@ -59,7 +58,7 @@ def test_compute_create_with_id(http_controller, controller):
assert controller.computes["my_compute_id"].host == "localhost"
def test_compute_get(http_controller, controller):
async def test_compute_get(controller_api):
params = {
"compute_id": "my_compute_id",
@ -69,15 +68,16 @@ def test_compute_get(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
response = http_controller.get("/computes/my_compute_id", example=True)
response = await controller_api.get("/computes/my_compute_id")
assert response.status == 200
assert response.json["protocol"] == "http"
def test_compute_update(http_controller, controller):
async def test_compute_update(controller_api):
params = {
"compute_id": "my_compute_id",
@ -87,21 +87,22 @@ def test_compute_update(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
response = http_controller.get("/computes/my_compute_id")
response = await controller_api.get("/computes/my_compute_id")
assert response.status == 200
assert response.json["protocol"] == "http"
params["protocol"] = "https"
response = http_controller.put("/computes/my_compute_id", params, example=True)
response = await controller_api.put("/computes/my_compute_id", params)
assert response.status == 200
assert response.json["protocol"] == "https"
def test_compute_list(http_controller, controller):
async def test_compute_list(controller_api):
params = {
"compute_id": "my_compute_id",
@ -112,13 +113,14 @@ def test_compute_list(http_controller, controller):
"password": "secure",
"name": "My super server"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
assert response.route == "/computes"
assert response.json["user"] == "julien"
assert "password" not in response.json
response = http_controller.get("/computes", example=True)
response = await controller_api.get("/computes")
for compute in response.json:
if compute['compute_id'] != 'local':
assert compute == {
@ -139,7 +141,7 @@ def test_compute_list(http_controller, controller):
}
def test_compute_delete(http_controller, controller):
async def test_compute_delete(controller_api):
params = {
"compute_id": "my_compute_id",
@ -149,20 +151,20 @@ def test_compute_delete(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
response = http_controller.get("/computes")
response = await controller_api.get("/computes")
assert len(response.json) == 1
response = http_controller.delete("/computes/my_compute_id", example=True)
response = await controller_api.delete("/computes/my_compute_id")
assert response.status == 204
response = http_controller.get("/computes")
response = await controller_api.get("/computes")
assert len(response.json) == 0
def test_compute_list_images(http_controller, controller):
async def test_compute_list_images(controller_api):
params = {
"compute_id": "my_compute",
@ -172,16 +174,16 @@ def test_compute_list_images(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
with asyncio_patch("gns3server.controller.compute.Compute.images", return_value=[{"filename": "linux.qcow2"}, {"filename": "asav.qcow2"}]) as mock:
response = http_controller.get("/computes/my_compute/qemu/images", example=True)
response = await controller_api.get("/computes/my_compute/qemu/images")
assert response.json == [{"filename": "linux.qcow2"}, {"filename": "asav.qcow2"}]
mock.assert_called_with("qemu")
def test_compute_list_vms(http_controller, controller):
async def test_compute_list_vms(controller_api):
params = {
"compute_id": "my_compute",
@ -191,16 +193,16 @@ def test_compute_list_vms(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
with asyncio_patch("gns3server.controller.compute.Compute.forward", return_value=[]) as mock:
response = http_controller.get("/computes/my_compute/virtualbox/vms", example=True)
response = await controller_api.get("/computes/my_compute/virtualbox/vms")
assert response.json == []
mock.assert_called_with("GET", "virtualbox", "vms")
def test_compute_create_img(http_controller, controller):
async def test_compute_create_img(controller_api):
params = {
"compute_id": "my_compute",
@ -210,16 +212,18 @@ def test_compute_create_img(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
params = {"path": "/test"}
with asyncio_patch("gns3server.controller.compute.Compute.forward", return_value=[]) as mock:
response = http_controller.post("/computes/my_compute/qemu/img", params, example=True)
response = await controller_api.post("/computes/my_compute/qemu/img", params)
assert response.json == []
mock.assert_called_with("POST", "qemu", "img", data=unittest.mock.ANY)
def test_compute_autoidlepc(http_controller, controller):
async def test_compute_autoidlepc(controller_api):
params = {
"compute_id": "my_compute_id",
@ -229,20 +233,23 @@ def test_compute_autoidlepc(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params, example=False)
await controller_api.post("/computes", params)
params = {
"platform": "c7200",
"image": "test.bin",
"ram": 512
}
with asyncio_patch("gns3server.controller.Controller.autoidlepc", return_value={"idlepc": "0x606de20c"}) as mock:
response = http_controller.post("/computes/my_compute_id/auto_idlepc", params, example=True)
response = await controller_api.post("/computes/my_compute_id/auto_idlepc", params)
assert mock.called
assert response.status == 200
def test_compute_endpoint(http_controller, controller):
async def test_compute_endpoint(controller_api):
params = {
"compute_id": "my_compute",
"protocol": "http",
@ -251,10 +258,10 @@ def test_compute_endpoint(http_controller, controller):
"user": "julien",
"password": "secure"
}
response = http_controller.post("/computes", params)
response = await controller_api.post("/computes", params)
assert response.status == 201
response = http_controller.get("/computes/endpoint/my_compute/virtualbox/images")
response = await controller_api.get("/computes/endpoint/my_compute/virtualbox/images")
assert response.status == 200
assert response.json['endpoint'] == 'http://localhost:84/v2/compute/virtualbox/images'

@ -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
@ -15,85 +15,73 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This test suite check /project endpoint
"""
import uuid
import os
import asyncio
import aiohttp
import pytest
from tests.utils import asyncio_patch
from gns3server.handlers.api.controller.project_handler import ProjectHandler
from gns3server.controller import Controller
from gns3server.controller.drawing import Drawing
@pytest.fixture
def project(http_controller, async_run):
return async_run(Controller.instance().add_project(name="Test"))
def test_create_drawing(http_controller, tmpdir, project, async_run):
async def test_create_drawing(controller_api, project):
response = http_controller.post("/projects/{}/drawings".format(project.id), {
params = {
"svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>',
"x": 10,
"y": 20,
"z": 0
}, example=True)
}
response = await controller_api.post("/projects/{}/drawings".format(project.id), params)
assert response.status == 201
assert response.json["drawing_id"] is not None
def test_get_drawing(http_controller, tmpdir, project, async_run):
async def test_get_drawing(controller_api, project):
response = http_controller.post("/projects/{}/drawings".format(project.id), {
params = {
"svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>',
"x": 10,
"y": 20,
"z": 0
},)
response = http_controller.get("/projects/{}/drawings/{}".format(project.id, response.json["drawing_id"]), example=True)
}
response = await controller_api.post("/projects/{}/drawings".format(project.id), params)
response = await controller_api.get("/projects/{}/drawings/{}".format(project.id, response.json["drawing_id"]))
assert response.status == 200
assert response.json["x"] == 10
def test_update_drawing(http_controller, tmpdir, project, async_run):
async def test_update_drawing(controller_api, project):
response = http_controller.post("/projects/{}/drawings".format(project.id), {
params = {
"svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>',
"x": 10,
"y": 20,
"z": 0
},)
response = http_controller.put("/projects/{}/drawings/{}".format(project.id, response.json["drawing_id"]), {
"x": 42,
}, example=True)
}
response = await controller_api.post("/projects/{}/drawings".format(project.id), params)
response = await controller_api.put("/projects/{}/drawings/{}".format(project.id, response.json["drawing_id"]), {"x": 42})
assert response.status == 201
assert response.json["x"] == 42
def test_list_drawing(http_controller, tmpdir, project, async_run):
response = http_controller.post("/projects/{}/drawings".format(project.id), {
async def test_list_drawing(controller_api, project):
params = {
"svg": '<svg height="210" width="500"><line x1="0" y1="0" x2="200" y2="200" style="stroke:rgb(255,0,0);stroke-width:2" /></svg>',
"x": 10,
"y": 20,
"z": 0
}, example=False)
response = http_controller.get("/projects/{}/drawings".format(project.id), example=True)
}
await controller_api.post("/projects/{}/drawings".format(project.id), params)
response = await controller_api.get("/projects/{}/drawings".format(project.id))
assert response.status == 200
assert len(response.json) == 1
def test_delete_drawing(http_controller, tmpdir, project, async_run):
async def test_delete_drawing(controller_api, project):
drawing = Drawing(project)
project._drawings = {drawing.id: drawing}
response = http_controller.delete("/projects/{}/drawings/{}".format(project.id, drawing.id), example=True)
response = await controller_api.delete("/projects/{}/drawings/{}".format(project.id, drawing.id))
assert response.status == 204
assert drawing.id not in project._drawings
assert drawing.id not in project.drawings

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# 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,9 +18,10 @@
from tests.utils import asyncio_patch
def test_list_vms(http_controller):
async def test_list_vms(controller_api):
with asyncio_patch("gns3server.controller.gns3vm.vmware_gns3_vm.VMwareGNS3VM.list", return_value=[{"vmname": "test"}]):
response = http_controller.get('/gns3vm/engines/vmware/vms', example=True)
response = await controller_api.get('/gns3vm/engines/vmware/vms')
assert response.status == 200
assert response.json == [
{
@ -29,20 +30,20 @@ def test_list_vms(http_controller):
]
def test_engines(http_controller):
response = http_controller.get('/gns3vm/engines', example=True)
async def test_engines(controller_api):
response = await controller_api.get('/gns3vm/engines')
assert response.status == 200
assert len(response.json) > 0
def test_put_gns3vm(http_controller):
response = http_controller.put('/gns3vm', {
"vmname": "TEST VM"
}, example=True)
async def test_put_gns3vm(controller_api):
response = await controller_api.put('/gns3vm', {"vmname": "TEST VM"})
assert response.status == 201
assert response.json["vmname"] == "TEST VM"
def test_get_gns3vm(http_controller):
response = http_controller.get('/gns3vm', example=True)
async def test_get_gns3vm(controller_api):
response = await controller_api.get('/gns3vm')
assert response.status == 200

@ -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
@ -15,45 +15,32 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This test suite check /project endpoint
"""
import asyncio
import aiohttp
import pytest
from unittest.mock import patch, MagicMock
from tests.utils import asyncio_patch, AsyncioMagicMock
from gns3server.controller import Controller
from gns3server.controller.ports.ethernet_port import EthernetPort
from gns3server.controller.link import Link, FILTERS
@pytest.fixture
def compute(http_controller, async_run):
compute = MagicMock()
compute.id = "example.com"
Controller.instance()._computes = {"example.com": compute}
return compute
@pytest.fixture
def project(http_controller, async_run):
return async_run(Controller.instance().add_project(name="Test"))
async def nodes(compute, project):
def test_create_link(http_controller, tmpdir, project, compute, async_run):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "node1", None, node_type="qemu"))
node1 = await project.add_node(compute, "node1", None, node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 3)]
node2 = async_run(project.add_node(compute, "node2", None, node_type="qemu"))
node2 = await project.add_node(compute, "node2", None, node_type="qemu")
node2._ports = [EthernetPort("E0", 0, 2, 4)]
return node1, node2
async def test_create_link(controller_api, project, nodes):
node1, node2 = nodes
filters = {
"latency": [10],
@ -61,7 +48,7 @@ def test_create_link(http_controller, tmpdir, project, compute, async_run):
}
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as mock:
response = http_controller.post("/projects/{}/links".format(project.id), {
response = await controller_api.post("/projects/{}/links".format(project.id), {
"nodes": [
{
"node_id": node1.id,
@ -80,7 +67,8 @@ def test_create_link(http_controller, tmpdir, project, compute, async_run):
}
],
"filters": filters
}, example=True)
})
assert mock.called
assert response.status == 201
assert response.json["link_id"] is not None
@ -90,56 +78,49 @@ def test_create_link(http_controller, tmpdir, project, compute, async_run):
assert list(project.links.values())[0].filters == filters
def test_create_link_failure(http_controller, tmpdir, project, compute, async_run):
async def test_create_link_failure(controller_api, compute, project):
"""
Make sure the link is deleted if we failed to create the link.
Make sure the link is deleted if we failed to create it.
The failure is trigger by connecting the link to himself
The failure is triggered by connecting the link to itself
"""
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "node1", None, node_type="qemu"))
node1 = await project.add_node(compute, "node1", None, node_type="qemu")
node1._ports = [EthernetPort("E0", 0, 0, 3), EthernetPort("E0", 0, 0, 4)]
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create"):
response = http_controller.post("/projects/{}/links".format(project.id), {
"nodes": [
{
"node_id": node1.id,
"adapter_number": 0,
"port_number": 3,
"label": {
"text": "Text",
"x": 42,
"y": 0
}
},
{
"node_id": node1.id,
"adapter_number": 0,
"port_number": 4
response = await controller_api.post("/projects/{}/links".format(project.id), {
"nodes": [
{
"node_id": node1.id,
"adapter_number": 0,
"port_number": 3,
"label": {
"text": "Text",
"x": 42,
"y": 0
}
]
}, example=True)
#assert mock.called
},
{
"node_id": node1.id,
"adapter_number": 0,
"port_number": 4
}
]
})
assert response.status == 409
assert len(project.links) == 0
def test_get_link(http_controller, tmpdir, project, compute, async_run):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "node1", None, node_type="qemu"))
node1._ports = [EthernetPort("E0", 0, 0, 3)]
node2 = async_run(project.add_node(compute, "node2", None, node_type="qemu"))
node2._ports = [EthernetPort("E0", 0, 2, 4)]
async def test_get_link(controller_api, project, nodes):
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create"):
response = http_controller.post("/projects/{}/links".format(project.id), {
node1, node2 = nodes
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as mock:
response = await controller_api.post("/projects/{}/links".format(project.id), {
"nodes": [
{
"node_id": node1.id,
@ -158,25 +139,20 @@ def test_get_link(http_controller, tmpdir, project, compute, async_run):
}
]
})
assert mock.called
link_id = response.json["link_id"]
assert response.json["nodes"][0]["label"]["x"] == 42
response = http_controller.get("/projects/{}/links/{}".format(project.id, link_id), example=True)
response = await controller_api.get("/projects/{}/links/{}".format(project.id, link_id))
assert response.status == 200
assert response.json["nodes"][0]["label"]["x"] == 42
def test_update_link_suspend(http_controller, tmpdir, project, compute, async_run):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "node1", None, node_type="qemu"))
node1._ports = [EthernetPort("E0", 0, 0, 3)]
node2 = async_run(project.add_node(compute, "node2", None, node_type="qemu"))
node2._ports = [EthernetPort("E0", 0, 2, 4)]
async def test_update_link_suspend(controller_api, project, nodes):
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create"):
response = http_controller.post("/projects/{}/links".format(project.id), {
node1, node2 = nodes
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as mock:
response = await controller_api.post("/projects/{}/links".format(project.id), {
"nodes": [
{
"node_id": node1.id,
@ -195,9 +171,12 @@ def test_update_link_suspend(http_controller, tmpdir, project, compute, async_ru
}
]
})
assert mock.called
link_id = response.json["link_id"]
assert response.json["nodes"][0]["label"]["x"] == 42
response = http_controller.put("/projects/{}/links/{}".format(project.id, link_id), {
response = await controller_api.put("/projects/{}/links/{}".format(project.id, link_id), {
"nodes": [
{
"node_id": node1.id,
@ -217,29 +196,23 @@ def test_update_link_suspend(http_controller, tmpdir, project, compute, async_ru
],
"suspend": True
})
assert response.status == 201
assert response.json["nodes"][0]["label"]["x"] == 64
assert response.json["suspend"]
assert response.json["filters"] == {}
def test_update_link(http_controller, tmpdir, project, compute, async_run):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "node1", None, node_type="qemu"))
node1._ports = [EthernetPort("E0", 0, 0, 3)]
node2 = async_run(project.add_node(compute, "node2", None, node_type="qemu"))
node2._ports = [EthernetPort("E0", 0, 2, 4)]
async def test_update_link(controller_api, project, nodes):
filters = {
"latency": [10],
"frequency_drop": [50]
}
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create"):
response = http_controller.post("/projects/{}/links".format(project.id), {
node1, node2 = nodes
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as mock:
response = await controller_api.post("/projects/{}/links".format(project.id), {
"nodes": [
{
"node_id": node1.id,
@ -258,9 +231,12 @@ def test_update_link(http_controller, tmpdir, project, compute, async_run):
}
]
})
assert mock.called
link_id = response.json["link_id"]
assert response.json["nodes"][0]["label"]["x"] == 42
response = http_controller.put("/projects/{}/links/{}".format(project.id, link_id), {
response = await controller_api.put("/projects/{}/links/{}".format(project.id, link_id), {
"nodes": [
{
"node_id": node1.id,
@ -279,26 +255,21 @@ def test_update_link(http_controller, tmpdir, project, compute, async_run):
}
],
"filters": filters
}, example=True)
})
assert response.status == 201
assert response.json["nodes"][0]["label"]["x"] == 64
assert list(project.links.values())[0].filters == filters
def test_list_link(http_controller, tmpdir, project, compute, async_run):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
node1 = async_run(project.add_node(compute, "node1", None, node_type="qemu"))
node1._ports = [EthernetPort("E0", 0, 0, 3)]
node2 = async_run(project.add_node(compute, "node2", None, node_type="qemu"))
node2._ports = [EthernetPort("E0", 0, 2, 4)]
async def test_list_link(controller_api, project, nodes):
filters = {
"latency": [10],
"frequency_drop": [50]
}
node1, node2 = nodes
nodes = [
{
"node_id": node1.id,
@ -311,40 +282,45 @@ def test_list_link(http_controller, tmpdir, project, compute, async_run):
"port_number": 4
}
]
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create"):
response = http_controller.post("/projects/{}/links".format(project.id), {
with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as mock:
await controller_api.post("/projects/{}/links".format(project.id), {
"nodes": nodes,
"filters": filters
})
response = http_controller.get("/projects/{}/links".format(project.id), example=True)
assert mock.called
response = await controller_api.get("/projects/{}/links".format(project.id))
assert response.status == 200
assert len(response.json) == 1
assert response.json[0]["filters"] == filters
def test_start_capture(http_controller, tmpdir, project, compute, async_run):
async def test_start_capture(controller_api, project):
link = Link(project)
project._links = {link.id: link}
with asyncio_patch("gns3server.controller.link.Link.start_capture") as mock:
response = http_controller.post("/projects/{}/links/{}/start_capture".format(project.id, link.id), example=True)
response = await controller_api.post("/projects/{}/links/{}/start_capture".format(project.id, link.id))
assert mock.called
assert response.status == 201
def test_stop_capture(http_controller, tmpdir, project, compute, async_run):
async def test_stop_capture(controller_api, project):
link = Link(project)
project._links = {link.id: link}
with asyncio_patch("gns3server.controller.link.Link.stop_capture") as mock:
response = http_controller.post("/projects/{}/links/{}/stop_capture".format(project.id, link.id), example=True)
response = await controller_api.post("/projects/{}/links/{}/stop_capture".format(project.id, link.id))
assert mock.called
assert response.status == 201
# def test_pcap(http_controller, tmpdir, project, compute, async_run):
# async def test_pcap(controller_api, http_client, project):
#
# async def go():
# async with aiohttp.request("GET", http_controller.get_url("/projects/{}/links/{}/pcap".format(project.id, link.id))) as response:
# async def pcap_capture():
# async with http_client.get(controller_api.get_url("/projects/{}/links/{}/pcap".format(project.id, link.id))) as response:
# response.body = await response.content.read(5)
# print("READ", response.body)
# return response
#
# with asyncio_patch("gns3server.controller.link.Link.capture_node") as mock:
@ -354,27 +330,28 @@ def test_stop_capture(http_controller, tmpdir, project, compute, async_run):
# with open(link.capture_file_path, "w+") as f:
# f.write("hello")
# project._links = {link.id: link}
# response = async_run(asyncio.ensure_future(go()))
# response = await pcap_capture()
# assert mock.called
# assert response.status == 200
# assert b'hello' == response.body
def test_delete_link(http_controller, tmpdir, project, compute, async_run):
async def test_delete_link(controller_api, project):
link = Link(project)
project._links = {link.id: link}
with asyncio_patch("gns3server.controller.link.Link.delete") as mock:
response = http_controller.delete("/projects/{}/links/{}".format(project.id, link.id), example=True)
response = await controller_api.delete("/projects/{}/links/{}".format(project.id, link.id))
assert mock.called
assert response.status == 204
def test_list_filters(http_controller, tmpdir, project, async_run):
async def test_list_filters(controller_api, project):
link = Link(project)
project._links = {link.id: link}
with patch("gns3server.controller.link.Link.available_filters", return_value=FILTERS) as mock:
response = http_controller.get("/projects/{}/links/{}/available_filters".format(project.id, link.id), example=True)
response = await controller_api.get("/projects/{}/links/{}/available_filters".format(project.id, link.id))
assert mock.called
assert response.status == 200
assert response.json == FILTERS

@ -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
@ -15,70 +15,50 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This test suite check /project endpoint
"""
import uuid
import os
import asyncio
import aiohttp
import pytest
from unittest.mock import MagicMock
from tests.utils import AsyncioMagicMock
from unittest.mock import patch, MagicMock
from tests.utils import asyncio_patch, AsyncioMagicMock
from gns3server.handlers.api.controller.project_handler import ProjectHandler
from gns3server.controller import Controller
from gns3server.controller.node import Node
@pytest.fixture
def compute(http_controller, async_run):
compute = MagicMock()
compute.id = "example.com"
compute.host = "example.org"
Controller.instance()._computes = {"example.com": compute}
return compute
@pytest.fixture
def project(http_controller, async_run):
return async_run(Controller.instance().add_project(name="Test"))
def node(project, compute):
@pytest.fixture
def node(project, compute, async_run):
node = Node(project, compute, "test", node_type="vpcs")
project._nodes[node.id] = node
return node
def test_create_node(http_controller, tmpdir, project, compute):
async def test_create_node(controller_api, project, compute):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
response = http_controller.post("/projects/{}/nodes".format(project.id), {
response = await controller_api.post("/projects/{}/nodes".format(project.id), {
"name": "test",
"node_type": "vpcs",
"compute_id": "example.com",
"properties": {
"startup_script": "echo test"
}
}, example=True)
})
assert response.status == 201
assert response.json["name"] == "test"
assert "name" not in response.json["properties"]
def test_list_node(http_controller, tmpdir, project, compute):
async def test_list_node(controller_api, project, compute):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
response = http_controller.post("/projects/{}/nodes".format(project.id), {
await controller_api.post("/projects/{}/nodes".format(project.id), {
"name": "test",
"node_type": "vpcs",
"compute_id": "example.com",
@ -86,17 +66,19 @@ def test_list_node(http_controller, tmpdir, project, compute):
"startup_script": "echo test"
}
})
response = http_controller.get("/projects/{}/nodes".format(project.id), example=True)
response = await controller_api.get("/projects/{}/nodes".format(project.id))
assert response.status == 200
assert response.json[0]["name"] == "test"
def test_get_node(http_controller, tmpdir, project, compute):
async def test_get_node(controller_api, project, compute):
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
response = http_controller.post("/projects/{}/nodes".format(project.id), {
response = await controller_api.post("/projects/{}/nodes".format(project.id), {
"name": "test",
"node_type": "vpcs",
"compute_id": "example.com",
@ -104,174 +86,175 @@ def test_get_node(http_controller, tmpdir, project, compute):
"startup_script": "echo test"
}
})
response = http_controller.get("/projects/{}/nodes/{}".format(project.id, response.json["node_id"]), example=True)
response = await controller_api.get("/projects/{}/nodes/{}".format(project.id, response.json["node_id"]))
assert response.status == 200
assert response.json["name"] == "test"
def test_update_node(http_controller, tmpdir, project, compute, node):
async def test_update_node(controller_api, project, compute, node):
response = MagicMock()
response.json = {"console": 2048}
compute.put = AsyncioMagicMock(return_value=response)
response = http_controller.put("/projects/{}/nodes/{}".format(project.id, node.id), {
response = await controller_api.put("/projects/{}/nodes/{}".format(project.id, node.id), {
"name": "test",
"node_type": "vpcs",
"compute_id": "example.com",
"properties": {
"startup_script": "echo test"
}
}, example=True)
})
assert response.status == 200
assert response.json["name"] == "test"
assert "name" not in response.json["properties"]
def test_start_all_nodes(http_controller, tmpdir, project, compute):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_start_all_nodes(controller_api, project, compute):
response = http_controller.post("/projects/{}/nodes/start".format(project.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/start".format(project.id))
assert response.status == 204
def test_stop_all_nodes(http_controller, tmpdir, project, compute):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_stop_all_nodes(controller_api, project, compute):
response = http_controller.post("/projects/{}/nodes/stop".format(project.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/stop".format(project.id))
assert response.status == 204
def test_suspend_all_nodes(http_controller, tmpdir, project, compute):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_suspend_all_nodes(controller_api, project, compute):
response = http_controller.post("/projects/{}/nodes/suspend".format(project.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/suspend".format(project.id))
assert response.status == 204
def test_reload_all_nodes(http_controller, tmpdir, project, compute):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_reload_all_nodes(controller_api, project, compute):
response = http_controller.post("/projects/{}/nodes/reload".format(project.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/reload".format(project.id))
assert response.status == 204
def test_start_node(http_controller, tmpdir, project, compute, node):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_start_node(controller_api, project, node, compute):
response = http_controller.post("/projects/{}/nodes/{}/start".format(project.id, node.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/{}/start".format(project.id, node.id))
assert response.status == 200
assert response.json == node.__json__()
def test_stop_node(http_controller, tmpdir, project, compute, node):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_stop_node(controller_api, project, node, compute):
response = http_controller.post("/projects/{}/nodes/{}/stop".format(project.id, node.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/{}/stop".format(project.id, node.id))
assert response.status == 200
assert response.json == node.__json__()
def test_suspend_node(http_controller, tmpdir, project, compute, node):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_suspend_node(controller_api, project, node, compute):
response = http_controller.post("/projects/{}/nodes/{}/suspend".format(project.id, node.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/{}/suspend".format(project.id, node.id))
assert response.status == 200
assert response.json == node.__json__()
def test_reload_node(http_controller, tmpdir, project, compute, node):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_reload_node(controller_api, project, node, compute):
response = http_controller.post("/projects/{}/nodes/{}/reload".format(project.id, node.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.post("/projects/{}/nodes/{}/reload".format(project.id, node.id))
assert response.status == 200
assert response.json == node.__json__()
def test_duplicate_node(http_controller, tmpdir, project, compute, node):
async def test_duplicate_node(controller_api, project, compute, node):
response = MagicMock()
response.json({"console": 2035})
compute.post = AsyncioMagicMock(return_value=response)
response = http_controller.post("/projects/{}/nodes/{}/duplicate".format(
project.id, node.id),
{"x": 10, "y": 5, "z": 0},
example=True)
response = await controller_api.post("/projects/{}/nodes/{}/duplicate".format(project.id, node.id),
{"x": 10,
"y": 5,
"z": 0})
assert response.status == 201, response.body.decode()
def test_delete_node(http_controller, tmpdir, project, compute, node):
response = MagicMock()
compute.post = AsyncioMagicMock()
async def test_delete_node(controller_api, project, node, compute):
response = http_controller.delete("/projects/{}/nodes/{}".format(project.id, node.id), example=True)
compute.post = AsyncioMagicMock()
response = await controller_api.delete("/projects/{}/nodes/{}".format(project.id, node.id))
assert response.status == 204
def test_dynamips_idle_pc(http_controller, tmpdir, project, compute, node):
async def test_dynamips_idle_pc(controller_api, project, compute, node):
response = MagicMock()
response.json = {"idlepc": "0x60606f54"}
compute.get = AsyncioMagicMock(return_value=response)
response = http_controller.get("/projects/{}/nodes/{}/dynamips/auto_idlepc".format(project.id, node.id), example=True)
response = await controller_api.get("/projects/{}/nodes/{}/dynamips/auto_idlepc".format(project.id, node.id))
assert response.status == 200
assert response.json["idlepc"] == "0x60606f54"
def test_dynamips_idlepc_proposals(http_controller, tmpdir, project, compute, node):
async def test_dynamips_idlepc_proposals(controller_api, project, compute, node):
response = MagicMock()
response.json = ["0x60606f54", "0x33805a22"]
compute.get = AsyncioMagicMock(return_value=response)
response = http_controller.get("/projects/{}/nodes/{}/dynamips/idlepc_proposals".format(project.id, node.id), example=True)
response = await controller_api.get("/projects/{}/nodes/{}/dynamips/idlepc_proposals".format(project.id, node.id))
assert response.status == 200
assert response.json == ["0x60606f54", "0x33805a22"]
def test_get_file(http_controller, tmpdir, project, node, compute):
async def test_get_file(controller_api, project, node, compute):
response = MagicMock()
response.body = b"world"
compute.http_query = AsyncioMagicMock(return_value=response)
response = http_controller.get("/projects/{project_id}/nodes/{node_id}/files/hello".format(project_id=project.id, node_id=node.id), raw=True)
response = await controller_api.get("/projects/{project_id}/nodes/{node_id}/files/hello".format(project_id=project.id, node_id=node.id))
assert response.status == 200
assert response.body == b'world'
compute.http_query.assert_called_with("GET", "/projects/{project_id}/files/project-files/vpcs/{node_id}/hello".format(project_id=project.id, node_id=node.id), timeout=None, raw=True)
response = http_controller.get("/projects/{project_id}/nodes/{node_id}/files/../hello".format(project_id=project.id, node_id=node.id), raw=True)
response = await controller_api.get("/projects/{project_id}/nodes/{node_id}/files/../hello".format(project_id=project.id, node_id=node.id))
assert response.status == 404
def test_post_file(http_controller, tmpdir, project, node, compute):
async def test_post_file(controller_api, project, node, compute):
compute.http_query = AsyncioMagicMock()
response = http_controller.post("/projects/{project_id}/nodes/{node_id}/files/hello".format(project_id=project.id, node_id=node.id), body=b"hello", raw=True)
response = await controller_api.post("/projects/{project_id}/nodes/{node_id}/files/hello".format(project_id=project.id, node_id=node.id), body=b"hello", raw=True)
assert response.status == 201
compute.http_query.assert_called_with("POST", "/projects/{project_id}/files/project-files/vpcs/{node_id}/hello".format(project_id=project.id, node_id=node.id), data=b'hello', timeout=None, raw=True)
response = http_controller.get("/projects/{project_id}/nodes/{node_id}/files/../hello".format(project_id=project.id, node_id=node.id), raw=True)
response = await controller_api.get("/projects/{project_id}/nodes/{node_id}/files/../hello".format(project_id=project.id, node_id=node.id))
assert response.status == 404
def test_get_and_post_with_nested_paths_normalization(http_controller, tmpdir, project, node, compute):
async def test_get_and_post_with_nested_paths_normalization(controller_api, project, node, compute):
response = MagicMock()
response.body = b"world"
compute.http_query = AsyncioMagicMock(return_value=response)
response = http_controller.get("/projects/{project_id}/nodes/{node_id}/files/hello\\nested".format(project_id=project.id, node_id=node.id), raw=True)
response = await controller_api.get("/projects/{project_id}/nodes/{node_id}/files/hello\\nested".format(project_id=project.id, node_id=node.id))
assert response.status == 200
assert response.body == b'world'
compute.http_query.assert_called_with("GET", "/projects/{project_id}/files/project-files/vpcs/{node_id}/hello/nested".format(project_id=project.id, node_id=node.id), timeout=None, raw=True)
compute.http_query = AsyncioMagicMock()
response = http_controller.post("/projects/{project_id}/nodes/{node_id}/files/hello\\nested".format(project_id=project.id, node_id=node.id), body=b"hello", raw=True)
response = await controller_api.post("/projects/{project_id}/nodes/{node_id}/files/hello\\nested".format(project_id=project.id, node_id=node.id), body=b"hello", raw=True)
assert response.status == 201
compute.http_query.assert_called_with("POST", "/projects/{project_id}/files/project-files/vpcs/{node_id}/hello/nested".format(project_id=project.id, node_id=node.id), data=b'hello', timeout=None, raw=True)

@ -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
@ -15,202 +15,206 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
This test suite check /project endpoint
"""
import uuid
import os
import asyncio
import aiohttp
import pytest
import zipfile
import json
from unittest.mock import patch, MagicMock
from tests.utils import asyncio_patch
from gns3server.handlers.api.controller.project_handler import ProjectHandler
from gns3server.controller import Controller
@pytest.fixture
def project(http_controller, controller):
async def project(controller_api, controller):
u = str(uuid.uuid4())
query = {"name": "test", "project_id": u}
response = http_controller.post("/projects", query)
params = {"name": "test", "project_id": u}
await controller_api.post("/projects", params)
return controller.get_project(u)
def test_create_project_with_path(http_controller, tmpdir):
response = http_controller.post("/projects", {"name": "test", "path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"})
async def test_create_project_with_path(controller_api, tmpdir):
response = await controller_api.post("/projects", {"name": "test", "path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"})
assert response.status == 201
assert response.json["name"] == "test"
assert response.json["project_id"] == "00010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["status"] == "opened"
def test_create_project_without_dir(http_controller):
query = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_controller.post("/projects", query, example=True)
async def test_create_project_without_dir(controller_api):
params = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = await controller_api.post("/projects", params)
assert response.status == 201
assert response.json["project_id"] == "10010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["name"] == "test"
def test_create_project_with_uuid(http_controller):
query = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_controller.post("/projects", query)
async def test_create_project_with_uuid(controller_api):
params = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f"}
response = await controller_api.post("/projects", params)
assert response.status == 201
assert response.json["project_id"] == "30010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["name"] == "test"
def test_create_project_with_variables(http_controller):
async def test_create_project_with_variables(controller_api):
variables = [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
]
query = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f", "variables": variables}
response = http_controller.post("/projects", query)
params = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f", "variables": variables}
response = await controller_api.post("/projects", params)
assert response.status == 201
assert response.json["variables"] == [
assert response.json["variables"] == [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
]
def test_create_project_with_supplier(http_controller):
async def test_create_project_with_supplier(controller_api):
supplier = {
'logo': 'logo.png',
'url': 'http://example.com'
}
query = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f", "supplier": supplier}
response = http_controller.post("/projects", query)
params = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f", "supplier": supplier}
response = await controller_api.post("/projects", params)
assert response.status == 201
assert response.json["supplier"] == supplier
def test_update_project(http_controller):
query = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = http_controller.post("/projects", query)
async def test_update_project(controller_api):
params = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = await controller_api.post("/projects", params)
assert response.status == 201
assert response.json["project_id"] == "10010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json["name"] == "test"
query = {"name": "test2"}
response = http_controller.put("/projects/10010203-0405-0607-0809-0a0b0c0d0e0f", query, example=True)
params = {"name": "test2"}
response = await controller_api.put("/projects/10010203-0405-0607-0809-0a0b0c0d0e0f", params)
assert response.status == 200
assert response.json["name"] == "test2"
def test_update_project_with_variables(http_controller):
async def test_update_project_with_variables(controller_api):
variables = [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
]
query = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f", "variables": variables}
response = http_controller.post("/projects", query)
params = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f", "variables": variables}
response = await controller_api.post("/projects", params)
assert response.status == 201
query = {"name": "test2"}
response = http_controller.put("/projects/10010203-0405-0607-0809-0a0b0c0d0e0f", query, example=True)
params = {"name": "test2"}
response = await controller_api.put("/projects/10010203-0405-0607-0809-0a0b0c0d0e0f", params)
assert response.status == 200
assert response.json["variables"] == variables
def test_list_projects(http_controller, tmpdir):
http_controller.post("/projects", {"name": "test", "path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"})
response = http_controller.get("/projects", example=True)
async def test_list_projects(controller_api, tmpdir):
await controller_api.post("/projects", {"name": "test", "path": str(tmpdir), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"})
response = await controller_api.get("/projects")
assert response.status == 200
projects = response.json
assert projects[0]["name"] == "test"
def test_get_project(http_controller, project):
response = http_controller.get("/projects/{project_id}".format(project_id=project.id), example=True)
async def test_get_project(controller_api, project):
response = await controller_api.get("/projects/{project_id}".format(project_id=project.id))
assert response.status == 200
assert response.json["name"] == "test"
def test_delete_project(http_controller, project):
async def test_delete_project(controller_api, project, controller):
with asyncio_patch("gns3server.controller.project.Project.delete", return_value=True) as mock:
response = http_controller.delete("/projects/{project_id}".format(project_id=project.id), example=True)
response = await controller_api.delete("/projects/{project_id}".format(project_id=project.id))
assert response.status == 204
assert mock.called
assert project not in Controller.instance().projects
assert project not in controller.projects
async def test_delete_project_invalid_uuid(controller_api):
def test_delete_project_invalid_uuid(http_controller):
response = http_controller.delete("/projects/{project_id}".format(project_id=uuid.uuid4()))
response = await controller_api.delete("/projects/{project_id}".format(project_id=uuid.uuid4()))
assert response.status == 404
def test_close_project(http_controller, project):
async def test_close_project(controller_api, project):
with asyncio_patch("gns3server.controller.project.Project.close", return_value=True) as mock:
response = http_controller.post("/projects/{project_id}/close".format(project_id=project.id), example=True)
response = await controller_api.post("/projects/{project_id}/close".format(project_id=project.id))
assert response.status == 204
assert mock.called
def test_open_project(http_controller, project):
async def test_open_project(controller_api, project):
with asyncio_patch("gns3server.controller.project.Project.open", return_value=True) as mock:
response = http_controller.post("/projects/{project_id}/open".format(project_id=project.id), example=True)
response = await controller_api.post("/projects/{project_id}/open".format(project_id=project.id))
assert response.status == 201
assert mock.called
def test_load_project(http_controller, project, config):
async def test_load_project(controller_api, project, config):
config.set("Server", "local", "true")
with asyncio_patch("gns3server.controller.Controller.load_project", return_value=project) as mock:
response = http_controller.post("/projects/load".format(project_id=project.id), {"path": "/tmp/test.gns3"}, example=True)
response = await controller_api.post("/projects/load".format(project_id=project.id), {"path": "/tmp/test.gns3"})
assert response.status == 201
mock.assert_called_with("/tmp/test.gns3")
assert response.json["project_id"] == project.id
def test_notification(http_controller, project, controller, loop, async_run):
async def test_notification(controller_api, http_client, project, controller):
async def go():
connector = aiohttp.TCPConnector()
async with aiohttp.request("GET", http_controller.get_url("/projects/{project_id}/notifications".format(project_id=project.id)), connector=connector) as response:
response.body = await response.content.read(200)
controller.notification.project_emit("node.created", {"a": "b"})
response.body += await response.content.readany()
return response
async with http_client.get(controller_api.get_url("/projects/{project_id}/notifications".format(project_id=project.id))) as response:
response.body = await response.content.read(200)
controller.notification.project_emit("node.created", {"a": "b"})
response.body += await response.content.readany()
assert response.status == 200
assert b'"action": "ping"' in response.body
assert b'"cpu_usage_percent"' in response.body
assert b'{"action": "node.created", "event": {"a": "b"}}\n' in response.body
assert project.status == "opened"
response = async_run(asyncio.ensure_future(go()))
assert response.status == 200
assert b'"action": "ping"' in response.body
assert b'"cpu_usage_percent"' in response.body
assert b'{"action": "node.created", "event": {"a": "b"}}\n' in response.body
assert project.status == "opened"
async def test_notification_invalid_id(controller_api):
def test_notification_invalid_id(http_controller):
response = http_controller.get("/projects/{project_id}/notifications".format(project_id=uuid.uuid4()))
response = await controller_api.get("/projects/{project_id}/notifications".format(project_id=uuid.uuid4()))
assert response.status == 404
def test_notification_ws(http_controller, controller, project, async_run):
ws = http_controller.websocket("/projects/{project_id}/notifications/ws".format(project_id=project.id))
answer = async_run(ws.receive())
async def test_notification_ws(controller_api, http_client, controller, project):
ws = await http_client.ws_connect(controller_api.get_url("/projects/{project_id}/notifications/ws".format(project_id=project.id)))
answer = await ws.receive()
answer = json.loads(answer.data)
assert answer["action"] == "ping"
controller.notification.project_emit("test", {})
answer = async_run(ws.receive())
answer = await ws.receive()
answer = json.loads(answer.data)
assert answer["action"] == "test"
async_run(http_controller.close())
async_run(ws.close())
if not ws.closed:
await ws.close()
assert project.status == "opened"
def test_export_with_images(http_controller, tmpdir, loop, project):
project.dump = MagicMock()
async def test_export_with_images(controller_api, tmpdir, project):
project.dump = MagicMock()
os.makedirs(project.path, exist_ok=True)
with open(os.path.join(project.path, 'a'), 'w+') as f:
f.write('hello')
@ -234,8 +238,8 @@ def test_export_with_images(http_controller, tmpdir, loop, project):
with open(os.path.join(project.path, "test.gns3"), 'w+') as f:
json.dump(topology, f)
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
response = http_controller.get("/projects/{project_id}/export?include_images=yes".format(project_id=project.id), raw=True)
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS")):
response = await controller_api.get("/projects/{project_id}/export?include_images=yes".format(project_id=project.id))
assert response.status == 200
assert response.headers['CONTENT-TYPE'] == 'application/gns3project'
assert response.headers['CONTENT-DISPOSITION'] == 'attachment; filename="{}.gns3project"'.format(project.name)
@ -250,9 +254,9 @@ def test_export_with_images(http_controller, tmpdir, loop, project):
myzip.getinfo("images/IOS/test.image")
def test_export_without_images(http_controller, tmpdir, loop, project):
project.dump = MagicMock()
async def test_export_without_images(controller_api, tmpdir, project):
project.dump = MagicMock()
os.makedirs(project.path, exist_ok=True)
with open(os.path.join(project.path, 'a'), 'w+') as f:
f.write('hello')
@ -277,7 +281,7 @@ def test_export_without_images(http_controller, tmpdir, loop, project):
json.dump(topology, f)
with patch("gns3server.compute.Dynamips.get_images_directory", return_value=str(tmpdir / "IOS"),):
response = http_controller.get("/projects/{project_id}/export?include_images=0".format(project_id=project.id), raw=True)
response = await controller_api.get("/projects/{project_id}/export?include_images=0".format(project_id=project.id))
assert response.status == 200
assert response.headers['CONTENT-TYPE'] == 'application/gns3project'
assert response.headers['CONTENT-DISPOSITION'] == 'attachment; filename="{}.gns3project"'.format(project.name)
@ -294,52 +298,54 @@ def test_export_without_images(http_controller, tmpdir, loop, project):
myzip.getinfo("images/IOS/test.image")
def test_get_file(http_controller, tmpdir, loop, project):
async def test_get_file(controller_api, project):
os.makedirs(project.path, exist_ok=True)
with open(os.path.join(project.path, 'hello'), 'w+') as f:
f.write('world')
response = http_controller.get("/projects/{project_id}/files/hello".format(project_id=project.id), raw=True)
response = await controller_api.get("/projects/{project_id}/files/hello".format(project_id=project.id))
assert response.status == 200
assert response.body == b"world"
response = http_controller.get("/projects/{project_id}/files/false".format(project_id=project.id), raw=True)
response = await controller_api.get("/projects/{project_id}/files/false".format(project_id=project.id))
assert response.status == 404
response = http_controller.get("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
response = await controller_api.get("/projects/{project_id}/files/../hello".format(project_id=project.id))
assert response.status == 404
def test_write_file(http_controller, tmpdir, project):
response = http_controller.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True)
async def test_write_file(controller_api, project):
response = await controller_api.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True)
assert response.status == 200
with open(os.path.join(project.path, "hello")) as f:
assert f.read() == "world"
response = http_controller.post("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
response = await controller_api.post("/projects/{project_id}/files/../hello".format(project_id=project.id), raw=True)
assert response.status == 404
def test_write_and_get_file_with_leading_slashes_in_filename(http_controller, tmpdir, loop, project):
response = http_controller.post("/projects/{project_id}/files//hello".format(project_id=project.id), body="world", raw=True)
async def test_write_and_get_file_with_leading_slashes_in_filename(controller_api, project):
response = await controller_api.post("/projects/{project_id}/files//hello".format(project_id=project.id), body="world", raw=True)
assert response.status == 200
response = http_controller.get("/projects/{project_id}/files//hello".format(project_id=project.id), raw=True)
response = await controller_api.get("/projects/{project_id}/files//hello".format(project_id=project.id), raw=True)
assert response.status == 200
assert response.body == b"world"
def test_import(http_controller, tmpdir, controller):
async def test_import(controller_api, tmpdir, controller):
with zipfile.ZipFile(str(tmpdir / "test.zip"), 'w') as myzip:
myzip.writestr("project.gns3", b'{"project_id": "c6992992-ac72-47dc-833b-54aa334bcd05", "version": "2.0.0", "name": "test"}')
myzip.writestr("demo", b"hello")
project_id = str(uuid.uuid4())
with open(str(tmpdir / "test.zip"), "rb") as f:
response = http_controller.post("/projects/{project_id}/import".format(project_id=project_id), body=f.read(), raw=True)
response = await controller_api.post("/projects/{project_id}/import".format(project_id=project_id), body=f.read(), raw=True)
assert response.status == 201
project = controller.get_project(project_id)
@ -348,8 +354,8 @@ def test_import(http_controller, tmpdir, controller):
assert content == "hello"
def test_duplicate(http_controller, tmpdir, loop, project):
async def test_duplicate(controller_api, project):
response = http_controller.post("/projects/{project_id}/duplicate".format(project_id=project.id), {"name": "hello"}, example=True)
response = await controller_api.post("/projects/{project_id}/duplicate".format(project_id=project.id), {"name": "hello"})
assert response.status == 201
assert response.json["name"] == "hello"

@ -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
@ -17,61 +17,60 @@
import os
import pytest
import asyncio
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock
from gns3server.web.web_server import WebServer
@pytest.yield_fixture
@pytest.fixture
def web_server():
WebServer._instance = MagicMock()
yield WebServer._instance
WebServer._instance = None
def test_shutdown_local(http_controller, web_server, config):
async def test_shutdown_local(controller_api, web_server, config):
async def hello():
return 0
web_server.shutdown_server.return_value = hello()
config.set("Server", "local", True)
response = http_controller.post('/shutdown', example=True)
response = await controller_api.post('/shutdown')
assert response.status == 201
assert web_server.shutdown_server.called
def test_shutdown_non_local(http_controller, web_server, config):
"""
Disallow shutdown of a non local GNS3 server
"""
async def test_shutdown_non_local(controller_api, web_server, config):
WebServer._instance = MagicMock()
config.set("Server", "local", False)
response = http_controller.post('/shutdown')
response = await controller_api.post('/shutdown')
assert response.status == 403
assert not web_server.shutdown_server.called
def test_debug(http_controller, config, tmpdir):
config._main_config_file = str(tmpdir / "test.conf")
async def test_debug(controller_api, config, tmpdir):
config._main_config_file = str(tmpdir / "test.conf")
config.set("Server", "local", True)
response = http_controller.post('/debug')
response = await controller_api.post('/debug')
assert response.status == 201
debug_dir = os.path.join(config.config_dir, "debug")
assert os.path.exists(debug_dir)
assert os.path.exists(os.path.join(debug_dir, "controller.txt"))
def test_debug_non_local(http_controller, config, tmpdir):
config._main_config_file = str(tmpdir / "test.conf")
async def test_debug_non_local(controller_api, config, tmpdir):
config._main_config_file = str(tmpdir / "test.conf")
config.set("Server", "local", False)
response = http_controller.post('/debug')
response = await controller_api.post('/debug')
assert response.status == 403
def test_statistics_output(http_controller):
response = http_controller.get('/statistics')
async def test_statistics_output(controller_api):
response = await controller_api.get('/statistics')
assert response.status == 200

@ -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
@ -21,40 +21,46 @@ import pytest
@pytest.fixture
def project(http_controller, controller):
async def project(controller_api, controller):
u = str(uuid.uuid4())
query = {"name": "test", "project_id": u}
response = http_controller.post("/projects", query)
params = {"name": "test", "project_id": u}
await controller_api.post("/projects", params)
project = controller.get_project(u)
return project
@pytest.fixture
def snapshot(project, async_run):
snapshot = async_run(project.snapshot("test"))
async def snapshot(project):
snapshot = await project.snapshot("test")
return snapshot
def test_list_snapshots(http_controller, project, snapshot):
response = http_controller.get("/projects/{}/snapshots".format(project.id), example=True)
async def test_list_snapshots(controller_api, project, snapshot):
assert snapshot.name == "test"
response = await controller_api.get("/projects/{}/snapshots".format(project.id))
assert response.status == 200
assert len(response.json) == 1
def test_delete_snapshot(http_controller, project, snapshot):
response = http_controller.delete("/projects/{}/snapshots/{}".format(project.id, snapshot.id), example=True)
async def test_delete_snapshot(controller_api, project, snapshot):
response = await controller_api.delete("/projects/{}/snapshots/{}".format(project.id, snapshot.id))
assert response.status == 204
assert not os.path.exists(snapshot.path)
def test_restore_snapshot(http_controller, project, snapshot):
response = http_controller.post("/projects/{}/snapshots/{}/restore".format(project.id, snapshot.id), example=True)
async def test_restore_snapshot(controller_api, project, snapshot):
response = await controller_api.post("/projects/{}/snapshots/{}/restore".format(project.id, snapshot.id))
assert response.status == 201
assert response.json["name"] == project.name
def test_create_snapshot(http_controller, project):
response = http_controller.post("/projects/{}/snapshots".format(project.id), {"name": "snap1"}, example=True)
async def test_create_snapshot(controller_api, project):
response = await controller_api.post("/projects/{}/snapshots".format(project.id), {"name": "snap1"})
assert response.status == 201
assert len(os.listdir(os.path.join(project.path, "snapshots"))) == 1

@ -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,14 +16,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import urllib.parse
from gns3server.config import Config
async def test_symbols(controller_api):
response = await controller_api.get('/symbols')
def test_symbols(http_controller):
response = http_controller.get('/symbols', example=True)
assert response.status == 200
assert {
'symbol_id': ':/symbols/classic/firewall.svg',
@ -33,25 +32,27 @@ def test_symbols(http_controller):
} in response.json
def test_get(http_controller, controller):
async def test_get(controller_api, controller):
controller.symbols.theme = "Classic"
response = http_controller.get('/symbols/' + urllib.parse.quote(':/symbols/classic/firewall.svg') + '/raw')
response = await controller_api.get('/symbols/' + urllib.parse.quote(':/symbols/classic/firewall.svg') + '/raw')
assert response.status == 200
assert response.headers['CONTENT-TYPE'] == 'image/svg+xml'
assert response.headers['CONTENT-LENGTH'] == '9381'
assert '</svg>' in response.html
# Reply by the default symbol
response = http_controller.get('/symbols/404.png/raw')
# Reply with the default symbol
response = await controller_api.get('/symbols/404.png/raw')
assert response.status == 200
def test_upload(http_controller, symbols_dir):
response = http_controller.post("/symbols/test2/raw", body="TEST", raw=True)
async def test_upload(controller_api, symbols_dir):
response = await controller_api.post("/symbols/test2/raw", body="TEST", raw=True)
assert response.status == 204
with open(os.path.join(symbols_dir, "test2")) as f:
assert f.read() == "TEST"
response = http_controller.get('/symbols/test2/raw')
response = await controller_api.get('/symbols/test2/raw')
assert response.status == 200

@ -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
@ -17,15 +17,13 @@
import uuid
import pytest
from unittest.mock import MagicMock
from tests.utils import asyncio_patch
from gns3server.controller import Controller
from gns3server.controller.template import Template
def test_template_list(http_controller, controller):
async def test_template_list(controller_api, controller):
id = str(uuid.uuid4())
controller.template_manager.load_templates()
@ -37,13 +35,13 @@ def test_template_list(http_controller, controller):
"default_name_format": "{name}-{0}",
"compute_id": "local"
})
response = http_controller.get("/templates", example=True)
response = await controller_api.get("/templates")
assert response.status == 200
assert response.route == "/templates"
assert len(response.json) > 0
def test_template_create_without_id(http_controller, controller):
async def test_template_create_without_id(controller_api, controller):
params = {"base_script_file": "vpcs_base_config.txt",
"category": "guest",
@ -55,14 +53,14 @@ def test_template_create_without_id(http_controller, controller):
"symbol": ":/symbols/vpcs_guest.svg",
"template_type": "vpcs"}
response = http_controller.post("/templates", params, example=True)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.route == "/templates"
assert response.json["template_id"] is not None
assert len(controller.template_manager._templates) == 1
assert len(controller.template_manager.templates) == 1
def test_template_create_with_id(http_controller, controller):
async def test_template_create_with_id(controller_api, controller):
params = {"template_id": str(uuid.uuid4()),
"base_script_file": "vpcs_base_config.txt",
@ -75,14 +73,14 @@ def test_template_create_with_id(http_controller, controller):
"symbol": ":/symbols/vpcs_guest.svg",
"template_type": "vpcs"}
response = http_controller.post("/templates", params, example=True)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.route == "/templates"
assert response.json["template_id"] is not None
assert len(controller.template_manager._templates) == 1
assert len(controller.template_manager.templates) == 1
def test_template_create_wrong_type(http_controller, controller):
async def test_template_create_wrong_type(controller_api, controller):
params = {"template_id": str(uuid.uuid4()),
"base_script_file": "vpcs_base_config.txt",
@ -95,12 +93,12 @@ def test_template_create_wrong_type(http_controller, controller):
"symbol": ":/symbols/vpcs_guest.svg",
"template_type": "invalid_template_type"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 400
assert len(controller.template_manager._templates) == 0
assert len(controller.template_manager.templates) == 0
def test_template_get(http_controller, controller):
async def test_template_get(controller_api):
template_id = str(uuid.uuid4())
params = {"template_id": template_id,
@ -114,15 +112,15 @@ def test_template_get(http_controller, controller):
"symbol": ":/symbols/vpcs_guest.svg",
"template_type": "vpcs"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
response = http_controller.get("/templates/{}".format(template_id), example=True)
response = await controller_api.get("/templates/{}".format(template_id))
assert response.status == 200
assert response.json["template_id"] == template_id
def test_template_update(http_controller, controller):
async def test_template_update(controller_api):
template_id = str(uuid.uuid4())
params = {"template_id": template_id,
@ -136,21 +134,21 @@ def test_template_update(http_controller, controller):
"symbol": ":/symbols/vpcs_guest.svg",
"template_type": "vpcs"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
response = http_controller.get("/templates/{}".format(template_id))
response = await controller_api.get("/templates/{}".format(template_id))
assert response.status == 200
assert response.json["template_id"] == template_id
params["name"] = "VPCS_TEST_RENAMED"
response = http_controller.put("/templates/{}".format(template_id), params, example=True)
response = await controller_api.put("/templates/{}".format(template_id), params)
assert response.status == 200
assert response.json["name"] == "VPCS_TEST_RENAMED"
def test_template_delete(http_controller, controller):
async def test_template_delete(controller_api, controller):
template_id = str(uuid.uuid4())
params = {"template_id": template_id,
@ -164,22 +162,22 @@ def test_template_delete(http_controller, controller):
"symbol": ":/symbols/vpcs_guest.svg",
"template_type": "vpcs"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
response = http_controller.get("/templates")
response = await controller_api.get("/templates")
assert len(response.json) == 1
assert len(controller.template_manager._templates) == 1
response = http_controller.delete("/templates/{}".format(template_id), example=True)
response = await controller_api.delete("/templates/{}".format(template_id))
assert response.status == 204
response = http_controller.get("/templates")
response = await controller_api.get("/templates")
assert len(response.json) == 0
assert len(controller.template_manager._templates) == 0
assert len(controller.template_manager.templates) == 0
def test_template_duplicate(http_controller, controller):
async def test_template_duplicate(controller_api, controller):
template_id = str(uuid.uuid4())
params = {"template_id": template_id,
@ -193,22 +191,22 @@ def test_template_duplicate(http_controller, controller):
"symbol": ":/symbols/vpcs_guest.svg",
"template_type": "vpcs"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
response = http_controller.post("/templates/{}/duplicate".format(template_id), example=True)
response = await controller_api.post("/templates/{}/duplicate".format(template_id))
assert response.status == 201
assert response.json["template_id"] != template_id
params.pop("template_id")
for param, value in params.items():
assert response.json[param] == value
response = http_controller.get("/templates")
response = await controller_api.get("/templates")
assert len(response.json) == 2
assert len(controller.template_manager._templates) == 2
assert len(controller.template_manager.templates) == 2
def test_c7200_dynamips_template_create(http_controller):
async def test_c7200_dynamips_template_create(controller_api):
params = {"name": "Cisco c7200 template",
"platform": "c7200",
@ -216,7 +214,7 @@ def test_c7200_dynamips_template_create(http_controller):
"image": "c7200-adventerprisek9-mz.124-24.T5.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -253,7 +251,7 @@ def test_c7200_dynamips_template_create(http_controller):
assert response.json.get(item) == value
def test_c3745_dynamips_template_create(http_controller):
async def test_c3745_dynamips_template_create(controller_api):
params = {"name": "Cisco c3745 template",
"platform": "c3745",
@ -261,7 +259,7 @@ def test_c3745_dynamips_template_create(http_controller):
"image": "c3745-adventerprisek9-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -297,7 +295,7 @@ def test_c3745_dynamips_template_create(http_controller):
assert response.json.get(item) == value
def test_c3725_dynamips_template_create(http_controller):
async def test_c3725_dynamips_template_create(controller_api):
params = {"name": "Cisco c3725 template",
"platform": "c3725",
@ -305,7 +303,7 @@ def test_c3725_dynamips_template_create(http_controller):
"image": "c3725-adventerprisek9-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -341,7 +339,7 @@ def test_c3725_dynamips_template_create(http_controller):
assert response.json.get(item) == value
def test_c3600_dynamips_template_create(http_controller):
async def test_c3600_dynamips_template_create(controller_api):
params = {"name": "Cisco c3600 template",
"platform": "c3600",
@ -350,7 +348,7 @@ def test_c3600_dynamips_template_create(http_controller):
"image": "c3660-a3jk9s-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -387,7 +385,7 @@ def test_c3600_dynamips_template_create(http_controller):
assert response.json.get(item) == value
def test_c3600_dynamips_template_create_wrong_chassis(http_controller):
async def test_c3600_dynamips_template_create_wrong_chassis(controller_api):
params = {"name": "Cisco c3600 template",
"platform": "c3600",
@ -396,11 +394,11 @@ def test_c3600_dynamips_template_create_wrong_chassis(http_controller):
"image": "c3660-a3jk9s-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 400
def test_c2691_dynamips_template_create(http_controller):
async def test_c2691_dynamips_template_create(controller_api):
params = {"name": "Cisco c2691 template",
"platform": "c2691",
@ -408,7 +406,7 @@ def test_c2691_dynamips_template_create(http_controller):
"image": "c2691-adventerprisek9-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -444,7 +442,7 @@ def test_c2691_dynamips_template_create(http_controller):
assert response.json.get(item) == value
def test_c2600_dynamips_template_create(http_controller):
async def test_c2600_dynamips_template_create(controller_api):
params = {"name": "Cisco c2600 template",
"platform": "c2600",
@ -453,7 +451,7 @@ def test_c2600_dynamips_template_create(http_controller):
"image": "c2600-adventerprisek9-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -490,7 +488,7 @@ def test_c2600_dynamips_template_create(http_controller):
assert response.json.get(item) == value
def test_c2600_dynamips_template_create_wrong_chassis(http_controller):
async def test_c2600_dynamips_template_create_wrong_chassis(controller_api):
params = {"name": "Cisco c2600 template",
"platform": "c2600",
@ -499,11 +497,11 @@ def test_c2600_dynamips_template_create_wrong_chassis(http_controller):
"image": "c2600-adventerprisek9-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 400
def test_c1700_dynamips_template_create(http_controller):
async def test_c1700_dynamips_template_create(controller_api):
params = {"name": "Cisco c1700 template",
"platform": "c1700",
@ -512,7 +510,7 @@ def test_c1700_dynamips_template_create(http_controller):
"image": "c1700-adventerprisek9-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -549,7 +547,7 @@ def test_c1700_dynamips_template_create(http_controller):
assert response.json.get(item) == value
def test_c1700_dynamips_template_create_wrong_chassis(http_controller):
async def test_c1700_dynamips_template_create_wrong_chassis(controller_api):
params = {"name": "Cisco c1700 template",
"platform": "c1700",
@ -558,11 +556,11 @@ def test_c1700_dynamips_template_create_wrong_chassis(http_controller):
"image": "c1700-adventerprisek9-mz.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 400
def test_dynamips_template_create_wrong_platform(http_controller):
async def test_dynamips_template_create_wrong_platform(controller_api):
params = {"name": "Cisco c3900 template",
"platform": "c3900",
@ -570,18 +568,18 @@ def test_dynamips_template_create_wrong_platform(http_controller):
"image": "c3900-test.124-25d.image",
"template_type": "dynamips"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 400
def test_iou_template_create(http_controller):
async def test_iou_template_create(controller_api):
params = {"name": "IOU template",
"compute_id": "local",
"path": "/path/to/i86bi_linux-ipbase-ms-12.4.bin",
"template_type": "iou"}
response = http_controller.post("/templates", params, example=True)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -608,14 +606,14 @@ def test_iou_template_create(http_controller):
assert response.json.get(item) == value
def test_docker_template_create(http_controller):
async def test_docker_template_create(controller_api):
params = {"name": "Docker template",
"compute_id": "local",
"image": "gns3/endhost:latest",
"template_type": "docker"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -642,7 +640,7 @@ def test_docker_template_create(http_controller):
assert response.json.get(item) == value
def test_qemu_template_create(http_controller):
async def test_qemu_template_create(controller_api):
params = {"name": "Qemu template",
"compute_id": "local",
@ -651,7 +649,7 @@ def test_qemu_template_create(http_controller):
"ram": 512,
"template_type": "qemu"}
response = http_controller.post("/templates", params, example=True)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -701,14 +699,14 @@ def test_qemu_template_create(http_controller):
assert response.json.get(item) == value
def test_vmware_template_create(http_controller):
async def test_vmware_template_create(controller_api):
params = {"name": "VMware template",
"compute_id": "local",
"template_type": "vmware",
"vmx_path": "/path/to/vm.vmx"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -737,14 +735,14 @@ def test_vmware_template_create(http_controller):
assert response.json.get(item) == value
def test_virtualbox_template_create(http_controller):
async def test_virtualbox_template_create(controller_api):
params = {"name": "VirtualBox template",
"compute_id": "local",
"template_type": "virtualbox",
"vmname": "My VirtualBox VM"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -773,13 +771,14 @@ def test_virtualbox_template_create(http_controller):
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_vpcs_template_create(http_controller):
async def test_vpcs_template_create(controller_api):
params = {"name": "VPCS template",
"compute_id": "local",
"template_type": "vpcs"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -797,13 +796,14 @@ def test_vpcs_template_create(http_controller):
for item, value in expected_response.items():
assert response.json.get(item) == value
def test_ethernet_switch_template_create(http_controller):
async def test_ethernet_switch_template_create(controller_api):
params = {"name": "Ethernet switch template",
"compute_id": "local",
"template_type": "ethernet_switch"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -868,13 +868,13 @@ def test_ethernet_switch_template_create(http_controller):
assert response.json.get(item) == value
def test_cloud_template_create(http_controller):
async def test_cloud_template_create(controller_api):
params = {"name": "Cloud template",
"compute_id": "local",
"template_type": "cloud"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -890,13 +890,13 @@ def test_cloud_template_create(http_controller):
assert response.json.get(item) == value
def test_ethernet_hub_template_create(http_controller):
async def test_ethernet_hub_template_create(controller_api):
params = {"name": "Ethernet hub template",
"compute_id": "local",
"template_type": "ethernet_hub"}
response = http_controller.post("/templates", params)
response = await controller_api.post("/templates", params)
assert response.status == 201
assert response.json["template_id"] is not None
@ -936,21 +936,7 @@ def test_ethernet_hub_template_create(http_controller):
assert response.json.get(item) == value
@pytest.fixture
def compute(http_controller, async_run):
compute = MagicMock()
compute.id = "example.com"
compute.host = "example.org"
Controller.instance()._computes = {"example.com": compute}
return compute
@pytest.fixture
def project(http_controller, async_run):
return async_run(Controller.instance().add_project(name="Test"))
def test_create_node_from_template(http_controller, controller, project, compute):
async def test_create_node_from_template(controller_api, controller, project):
id = str(uuid.uuid4())
controller.template_manager._templates = {id: Template(id, {
@ -962,7 +948,7 @@ def test_create_node_from_template(http_controller, controller, project, compute
"compute_id": "example.com"
})}
with asyncio_patch("gns3server.controller.project.Project.add_node_from_template", return_value={"name": "test", "node_type": "qemu", "compute_id": "example.com"}) as mock:
response = http_controller.post("/projects/{}/templates/{}".format(project.id, id), {
response = await controller_api.post("/projects/{}/templates/{}".format(project.id, id), {
"x": 42,
"y": 12
})

@ -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
@ -15,48 +15,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/>.
"""
This test suite check /version endpoint
It's also used for unittest the HTTP implementation.
"""
from gns3server.config import Config
from gns3server.version import __version__
def test_version_output(http_controller):
config = Config.instance()
config.set("Server", "local", "true")
async def test_version_output(controller_api, config):
response = http_controller.get('/version', example=True)
config.set("Server", "local", "true")
response = await controller_api.get('/version')
assert response.status == 200
assert response.json == {'local': True, 'version': __version__}
def test_version_input(http_controller):
query = {'version': __version__}
response = http_controller.post('/version', query, example=True)
async def test_version_input(controller_api):
params = {'version': __version__}
response = await controller_api.post('/version', params)
assert response.status == 200
assert response.json == {'version': __version__}
def test_version_invalid_input(http_controller):
query = {'version': "0.4.2"}
response = http_controller.post('/version', query)
assert response.status == 409
async def test_version_invalid_input(controller_api):
params = {'version': "0.4.2"}
response = await controller_api.post('/version', params)
assert response.status == 409
assert response.json == {'message': 'Client version 0.4.2 is not the same as server version {}'.format(__version__),
'status': 409}
def test_version_invalid_input_schema(http_controller):
query = {'version': "0.4.2", "bla": "blu"}
response = http_controller.post('/version', query)
async def test_version_invalid_input_schema(controller_api):
params = {'version': "0.4.2", "bla": "blu"}
response = await controller_api.post('/version', params)
assert response.status == 400
def test_version_invalid_json(http_controller):
query = "BOUM"
response = http_controller.post('/version', query, raw=True)
async def test_version_invalid_json(controller_api):
params = "BOUM"
response = await controller_api.post('/version', params, raw=True)
assert response.status == 400

@ -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,60 +25,68 @@ from gns3server.utils.get_resource import get_resource
def get_static(filename):
current_dir = os.path.dirname(os.path.abspath(__file__))
return os.path.join(os.path.abspath(os.path.join(current_dir, '..', '..', 'gns3server', 'static')), filename)
def test_debug(http_root):
response = http_root.get('/debug')
async def test_debug(http_client):
response = await http_client.get('/debug')
assert response.status == 200
html = response.html
html = await response.text()
assert "Website" in html
assert __version__ in html
def test_controller(http_root, async_run):
project = async_run(Controller.instance().add_project(name="test"))
response = http_root.get('/controller')
assert "test" in response.html
async def test_controller(http_client, controller):
await controller.add_project(name="test")
response = await http_client.get('/controller')
assert "test" in await response.text()
assert response.status == 200
def test_compute(http_root):
response = http_root.get('/compute')
async def test_compute(http_client):
response = await http_client.get('/compute')
assert response.status == 200
def test_project(http_root, async_run):
project = async_run(Controller.instance().add_project(name="test"))
response = http_root.get('/projects/{}'.format(project.id))
async def test_project(http_client, controller):
project = await controller.add_project(name="test")
response = await http_client.get('/projects/{}'.format(project.id))
assert response.status == 200
def test_web_ui(http_root, tmpdir):
async def test_web_ui(http_client, tmpdir):
with patch('gns3server.utils.get_resource.get_resource') as mock:
mock.return_value = str(tmpdir)
os.makedirs(str(tmpdir / 'web-ui'))
tmpfile = get_static('web-ui/testing.txt')
with open(tmpfile, 'w+') as f:
f.write('world')
response = http_root.get('/static/web-ui/testing.txt')
response = await http_client.get('/static/web-ui/testing.txt')
assert response.status == 200
os.remove(get_static('web-ui/testing.txt'))
def test_web_ui_not_found(http_root, tmpdir):
async def test_web_ui_not_found(http_client, tmpdir):
with patch('gns3server.utils.get_resource.get_resource') as mock:
mock.return_value = str(tmpdir)
response = http_root.get('/static/web-ui/not-found.txt')
response = await http_client.get('/static/web-ui/not-found.txt')
# should serve web-ui/index.html
assert response.status == 200
def test_v1(http_root):
async def test_v1(http_client):
"""
The old api v1 raise a 429
The old API v1 raises a 429
"""
response = http_root.get('/v1/version')
response = await http_client.get('/v1/version')
assert response.status == 200

@ -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,8 +17,6 @@
import configparser
import time
import os
from gns3server.config import Config
@ -73,6 +71,7 @@ def test_set_section_config(tmpdir):
"local": "false"
}
})
assert dict(config.get_section_config("Server")) == {"host": "127.0.0.1", "local": "false"}
config.set_section_config("Server", {"host": "192.168.1.1", "local": True})
assert dict(config.get_section_config("Server")) == {"host": "192.168.1.1", "local": "true"}
@ -85,6 +84,7 @@ def test_set(tmpdir):
"host": "127.0.0.1"
}
})
assert dict(config.get_section_config("Server")) == {"host": "127.0.0.1"}
config.set("Server", "host", "192.168.1.1")
assert dict(config.get_section_config("Server")) == {"host": "192.168.1.1"}
@ -97,12 +97,12 @@ def test_reload(tmpdir):
"host": "127.0.0.1"
}
})
assert dict(config.get_section_config("Server")) == {"host": "127.0.0.1"}
assert dict(config.get_section_config("Server")) == {"host": "127.0.0.1"}
config.set_section_config("Server", {"host": "192.168.1.1"})
assert dict(config.get_section_config("Server")) == {"host": "192.168.1.1"}
path = write_config(tmpdir, {
write_config(tmpdir, {
"Server": {
"host": "192.168.1.2"
}

@ -15,7 +15,6 @@
# 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 sys
from gns3server.utils import *
@ -23,8 +22,8 @@ def test_force_unix_path():
assert force_unix_path("a/b") == "a/b"
assert force_unix_path("a\\b") == "a/b"
assert force_unix_path("a\\b\\..\\c") == "a/c"
assert force_unix_path("C:\Temp") == "C:/Temp"
assert force_unix_path(force_unix_path("C:\Temp")) == "C:/Temp"
assert force_unix_path(r"C:\Temp") == r"C:/Temp"
assert force_unix_path(force_unix_path(r"C:\Temp")) == r"C:/Temp"
assert force_unix_path("a//b") == "a/b"

@ -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
@ -34,13 +34,13 @@ class _asyncio_patch:
"""
def __init__(self, function, *args, **kwargs):
self.function = function
self.args = args
self.kwargs = kwargs
self._function = function
self._aync_magic_mock = AsyncioMagicMock(*args, **kwargs)
def __enter__(self):
"""Used when enter in the with block"""
self._patcher = unittest.mock.patch(self.function, return_value=self._fake_anwser())
self._patcher = unittest.mock.patch(self._function, new=self._aync_magic_mock)
mock_class = self._patcher.start()
return mock_class
@ -48,19 +48,6 @@ class _asyncio_patch:
"""Used when leaving the with block"""
self._patcher.stop()
def _fake_anwser(self):
future = asyncio.Future()
if "return_value" in self.kwargs:
future.set_result(self.kwargs["return_value"])
elif "side_effect" in self.kwargs:
if isinstance(self.kwargs["side_effect"], Exception):
future.set_exception(self.kwargs["side_effect"])
else:
raise NotImplementedError
else:
future.set_result(True)
return future
def asyncio_patch(function, *args, **kwargs):
return _asyncio_patch(function, *args, **kwargs)
@ -77,12 +64,13 @@ class AsyncioMagicMock(unittest.mock.MagicMock):
"""
Magic mock returning coroutine
"""
try:
__class__ = types.CoroutineType
except AttributeError: # Not supported with Python 3.4
__class__ = types.GeneratorType
def __init__(self, return_value=None, return_values=None, **kwargs):
def __init__(self, return_value=None, **kwargs):
"""
:return_values: Array of return value at each call will return the next
"""

@ -25,53 +25,33 @@ from gns3server.utils.asyncio import wait_run_in_executor, subprocess_check_outp
from tests.utils import AsyncioMagicMock
def test_wait_run_in_executor(loop):
async def test_wait_run_in_executor():
def change_var(param):
return param
exec = wait_run_in_executor(change_var, "test")
result = loop.run_until_complete(asyncio.ensure_future(exec))
result = await wait_run_in_executor(change_var, "test")
assert result == "test"
def test_exception_wait_run_in_executor(loop):
async def test_exception_wait_run_in_executor():
def raise_exception():
raise Exception("test")
exec = wait_run_in_executor(raise_exception)
with pytest.raises(Exception):
result = loop.run_until_complete(asyncio.ensure_future(exec))
await wait_run_in_executor(raise_exception)
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_subprocess_check_output(loop, tmpdir, restore_original_path):
async def test_subprocess_check_output(loop, tmpdir):
path = str(tmpdir / "test")
exec = subprocess_check_output("echo", "-n", path)
result = loop.run_until_complete(asyncio.ensure_future(exec))
result = await subprocess_check_output("echo", "-n", path)
assert result == path
def test_wait_for_process_termination(loop):
if sys.version_info >= (3, 5):
# No need for test we use native version
return
process = MagicMock()
process.returncode = 0
exec = wait_for_process_termination(process)
loop.run_until_complete(asyncio.ensure_future(exec))
process = MagicMock()
process.returncode = None
exec = wait_for_process_termination(process, timeout=0.5)
with pytest.raises(asyncio.TimeoutError):
loop.run_until_complete(asyncio.ensure_future(exec))
def test_lock_decorator(loop):
async def test_lock_decorator():
"""
The test check if the the second call to method_to_lock wait for the
first call to finish
@ -84,11 +64,11 @@ def test_lock_decorator(loop):
@locking
async def method_to_lock(self):
res = self._test_val
result = self._test_val
await asyncio.sleep(0.1)
self._test_val += 1
return res
return result
i = TestLock()
res = set(loop.run_until_complete(asyncio.gather(i.method_to_lock(), i.method_to_lock())))
res = set(await asyncio.gather(i.method_to_lock(), i.method_to_lock()))
assert res == set((0, 1,)) # We use a set to test this to avoid order issue

@ -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,41 +24,42 @@ from gns3server.utils.file_watcher import FileWatcher
@pytest.mark.parametrize("strategy", ['mtime', 'hash'])
def test_file_watcher(async_run, tmpdir, strategy):
async def test_file_watcher(tmpdir, strategy):
file = tmpdir / "test"
file.write("a")
callback = MagicMock()
fw = FileWatcher(file, callback, delay=0.5, strategy=strategy)
async_run(asyncio.sleep(1))
FileWatcher(file, callback, delay=0.1, strategy=strategy)
await asyncio.sleep(0.5)
assert not callback.called
file.write("b")
async_run(asyncio.sleep(1.5))
await asyncio.sleep(0.5)
callback.assert_called_with(str(file))
@pytest.mark.parametrize("strategy", ['mtime', 'hash'])
def test_file_watcher_not_existing(async_run, tmpdir, strategy):
async def test_file_watcher_not_existing(tmpdir, strategy):
file = tmpdir / "test"
callback = MagicMock()
fw = FileWatcher(file, callback, delay=0.5, strategy=strategy)
async_run(asyncio.sleep(1))
FileWatcher(file, callback, delay=0.1, strategy=strategy)
await asyncio.sleep(0.5)
assert not callback.called
file.write("b")
async_run(asyncio.sleep(1.5))
await asyncio.sleep(0.5)
callback.assert_called_with(str(file))
@pytest.mark.parametrize("strategy", ['mtime', 'hash'])
def test_file_watcher_list(async_run, tmpdir, strategy):
async def test_file_watcher_list(tmpdir, strategy):
file = tmpdir / "test"
file.write("a")
file2 = tmpdir / "test2"
callback = MagicMock()
fw = FileWatcher([file, file2], callback, delay=0.5, strategy=strategy)
async_run(asyncio.sleep(1))
FileWatcher([file, file2], callback, delay=0.1, strategy=strategy)
await asyncio.sleep(0.5)
assert not callback.called
file2.write("b")
async_run(asyncio.sleep(1.5))
await asyncio.sleep(0.5)
callback.assert_called_with(str(file2))

@ -26,6 +26,7 @@ from gns3server.utils.images import md5sum, remove_checksum, images_directories,
def test_images_directories(tmpdir):
path1 = tmpdir / "images1" / "QEMU" / "test1.bin"
path1.write("1", ensure=True)
path1 = force_unix_path(str(path1))
@ -48,6 +49,7 @@ def test_images_directories(tmpdir):
def test_md5sum(tmpdir):
fake_img = str(tmpdir / 'hello载')
with open(fake_img, 'w+') as f:
@ -59,6 +61,7 @@ def test_md5sum(tmpdir):
def test_md5sum_stopped_event(tmpdir):
fake_img = str(tmpdir / 'hello_stopped')
with open(fake_img, 'w+') as f:
f.write('hello')
@ -71,6 +74,7 @@ def test_md5sum_stopped_event(tmpdir):
def test_md5sum_existing_digest(tmpdir):
fake_img = str(tmpdir / 'hello')
with open(fake_img, 'w+') as f:
@ -83,6 +87,7 @@ def test_md5sum_existing_digest(tmpdir):
def test_md5sum_existing_digest_but_missing_image(tmpdir):
fake_img = str(tmpdir / 'hello')
with open(str(tmpdir / 'hello.md5sum'), 'w+') as f:
@ -92,6 +97,7 @@ def test_md5sum_existing_digest_but_missing_image(tmpdir):
def test_md5sum_none(tmpdir):
assert md5sum(None) is None
@ -107,6 +113,7 @@ def test_remove_checksum(tmpdir):
def test_list_images(tmpdir):
path1 = tmpdir / "images1" / "IOS" / "test1.image"
path1.write(b'\x7fELF\x01\x02\x01', ensure=True)
path1 = force_unix_path(str(path1))

@ -21,6 +21,7 @@ from gns3server.utils.interfaces import interfaces, is_interface_up, has_netmask
def test_interfaces():
# This test should pass on all platforms without crash
interface_list = interfaces()
assert isinstance(interface_list, list)
@ -39,6 +40,7 @@ def test_interfaces():
def test_has_netmask():
if sys.platform.startswith("win"):
# No loopback
pass
@ -49,6 +51,7 @@ def test_has_netmask():
def test_is_interface_up():
if sys.platform.startswith("win"):
# is_interface_up() always returns True on Windows
pass

@ -24,6 +24,7 @@ from gns3server.utils.path import check_path_allowed, get_default_project_direct
def test_check_path_allowed(config, tmpdir):
config.set("Server", "local", False)
config.set("Server", "projects_path", str(tmpdir))
with pytest.raises(aiohttp.web.HTTPForbidden):
@ -37,7 +38,6 @@ def test_check_path_allowed(config, tmpdir):
def test_get_default_project_directory(config):
config.clear()
path = os.path.normpath(os.path.expanduser("~/GNS3/projects"))
assert get_default_project_directory() == path
assert os.path.exists(path)

@ -20,6 +20,7 @@ from gns3server.utils.picture import get_size
def test_get_size():
with open("tests/resources/nvram_iou", "rb") as f:
res = get_size(f.read(), default_width=100, default_height=50)
assert res == (100, 50, None)

@ -1,42 +0,0 @@
# -*- 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 os
from gns3server.web.documentation import Documentation
from gns3server.handlers import *
from gns3server.web.route import Route
def test_documentation_write(tmpdir):
os.makedirs(str(tmpdir / "api/examples"))
with open(str(tmpdir / "api/examples/compute_post_projectsprojectidvirtualboxnodes.txt"), "w+") as f:
f.write("curl test")
Documentation(Route, str(tmpdir)).write()
assert os.path.exists(str(tmpdir / "api"))
assert os.path.exists(str(tmpdir / "api" / "v2" / "compute"))
assert os.path.exists(str(tmpdir / "api" / "v2" / "compute" / "virtualbox.rst"))
assert os.path.exists(str(tmpdir / "api" / "v2" / "compute" / "virtualbox"))
assert os.path.exists(str(tmpdir / "api" / "v2" / "compute" / "virtualbox" / "virtualboxvms.rst"))
with open(str(tmpdir / "api" / "v2" / "compute" / "virtualbox" / "projectsprojectidvirtualboxnodes.rst")) as f:
content = f.read()
assert "Sample session" in content
assert "literalinclude:: ../../../examples/compute_post_projectsprojectidvirtualboxnodes.txt" in content
assert os.path.exists(str(tmpdir / "api" / "v2" / "controller" / "compute.rst"))

@ -17,7 +17,7 @@
import pytest
from unittest.mock import MagicMock
from tests.utils import AsyncioMagicMock
from aiohttp.web import HTTPNotFound
from gns3server.web.response import Response
@ -25,20 +25,22 @@ from gns3server.web.response import Response
@pytest.fixture()
def response():
request = MagicMock()
request = AsyncioMagicMock()
return Response(request=request)
def test_response_file(async_run, tmpdir, response):
async def test_response_file(tmpdir, response):
filename = str(tmpdir / 'hello')
with open(filename, 'w+') as f:
f.write('world')
async_run(response.stream_file(filename))
await response.stream_file(filename)
assert response.status == 200
def test_response_file_not_found(async_run, tmpdir, response):
filename = str(tmpdir / 'hello-not-found')
async def test_response_file_not_found(loop, tmpdir, response):
pytest.raises(HTTPNotFound, lambda: async_run(response.stream_file(filename)))
filename = str(tmpdir / 'hello-not-found')
with pytest.raises(HTTPNotFound):
await response.stream_file(filename)

Loading…
Cancel
Save