1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-28 03:08:14 +00:00

Fix tests to work with new version of aiohttp (>= 3.0)

This commit is contained in:
grossmj 2018-10-17 17:32:10 +07:00
parent 9ae9209881
commit ab8dc52ece
18 changed files with 218 additions and 184 deletions

View File

@ -96,9 +96,9 @@ class Compute:
return self._http_session return self._http_session
#def __del__(self): #def __del__(self):
# pass #
# if self._http_session: # if self._http_session:
# self._http_session.close() # self._http_session.close()
def _set_auth(self, user, password): def _set_auth(self, user, password):
""" """
@ -415,7 +415,7 @@ class Compute:
if "version" not in response.json: if "version" not in response.json:
msg = "The server {} is not a GNS3 server".format(self._id) msg = "The server {} is not a GNS3 server".format(self._id)
log.error(msg) log.error(msg)
self._http_session.close() await self._http_session.close()
raise aiohttp.web.HTTPConflict(text=msg) raise aiohttp.web.HTTPConflict(text=msg)
self._capabilities = response.json self._capabilities = response.json
@ -430,13 +430,13 @@ class Compute:
if __version_info__[3] == 0: if __version_info__[3] == 0:
# Stable release # Stable release
log.error(msg) log.error(msg)
self._http_session.close() await self._http_session.close()
self._last_error = msg self._last_error = msg
raise aiohttp.web.HTTPConflict(text=msg) raise aiohttp.web.HTTPConflict(text=msg)
elif parse_version(__version__)[:2] != parse_version(response.json["version"])[:2]: elif parse_version(__version__)[:2] != parse_version(response.json["version"])[:2]:
# We don't allow different major version to interact even with dev build # We don't allow different major version to interact even with dev build
log.error(msg) log.error(msg)
self._http_session.close() await self._http_session.close()
self._last_error = msg self._last_error = msg
raise aiohttp.web.HTTPConflict(text=msg) raise aiohttp.web.HTTPConflict(text=msg)
else: else:

View File

@ -181,7 +181,7 @@ class ProjectHandler:
queue = project.get_listen_queue() queue = project.get_listen_queue()
ProjectHandler._notifications_listening.setdefault(project.id, 0) ProjectHandler._notifications_listening.setdefault(project.id, 0)
ProjectHandler._notifications_listening[project.id] += 1 ProjectHandler._notifications_listening[project.id] += 1
response.write("{}\n".format(json.dumps(ProjectHandler._getPingMessage())).encode("utf-8")) await response.write("{}\n".format(json.dumps(ProjectHandler._getPingMessage())).encode("utf-8"))
while True: while True:
try: try:
(action, msg) = await asyncio.wait_for(queue.get(), 5) (action, msg) = await asyncio.wait_for(queue.get(), 5)
@ -190,11 +190,11 @@ class ProjectHandler:
else: else:
msg = json.dumps({"action": action, "event": msg}, sort_keys=True) msg = json.dumps({"action": action, "event": msg}, sort_keys=True)
log.debug("Send notification: %s", msg) log.debug("Send notification: %s", msg)
response.write(("{}\n".format(msg)).encode("utf-8")) await response.write(("{}\n".format(msg)).encode("utf-8"))
except asyncio.futures.CancelledError as e: except asyncio.futures.CancelledError as e:
break break
except asyncio.futures.TimeoutError: except asyncio.futures.TimeoutError:
response.write("{}\n".format(json.dumps(ProjectHandler._getPingMessage())).encode("utf-8")) await response.write("{}\n".format(json.dumps(ProjectHandler._getPingMessage())).encode("utf-8"))
project.stop_listen_queue(queue) project.stop_listen_queue(queue)
if project.id in ProjectHandler._notifications_listening: if project.id in ProjectHandler._notifications_listening:
ProjectHandler._notifications_listening[project.id] -= 1 ProjectHandler._notifications_listening[project.id] -= 1
@ -374,10 +374,9 @@ class ProjectHandler:
include_images = bool(int(request.json.get("include_images", "0"))) include_images = bool(int(request.json.get("include_images", "0")))
for data in project.export(include_images=include_images): for data in project.export(include_images=include_images):
response.write(data) await response.write(data)
await response.drain()
await response.write_eof() #await response.write_eof() #FIXME: shound't be needed anymore
@Route.post( @Route.post(
r"/projects/{project_id}/import", r"/projects/{project_id}/import",

View File

@ -420,9 +420,8 @@ class NodeHandler:
response.content_type = "application/octet-stream" response.content_type = "application/octet-stream"
response.enable_chunked_encoding() response.enable_chunked_encoding()
await response.prepare(request) await response.prepare(request)
await response.write(res.body)
response.write(res.body) # await response.write_eof() #FIXME: shound't be needed anymore
await response.write_eof()
@Route.post( @Route.post(
r"/projects/{project_id}/nodes/{node_id}/files/{path:.+}", r"/projects/{project_id}/nodes/{node_id}/files/{path:.+}",

View File

@ -52,10 +52,9 @@ class NotificationHandler:
while True: while True:
try: try:
msg = await queue.get_json(5) msg = await queue.get_json(5)
response.write(("{}\n".format(msg)).encode("utf-8")) await response.write(("{}\n".format(msg)).encode("utf-8"))
except asyncio.futures.CancelledError: except asyncio.futures.CancelledError:
break break
await response.drain()
@Route.get( @Route.get(
r"/notifications/ws", r"/notifications/ws",

View File

@ -231,10 +231,9 @@ class ProjectHandler:
while True: while True:
try: try:
msg = await queue.get_json(5) msg = await queue.get_json(5)
response.write(("{}\n".format(msg)).encode("utf-8")) await response.write(("{}\n".format(msg)).encode("utf-8"))
except asyncio.futures.CancelledError as e: except asyncio.futures.CancelledError as e:
break break
await response.drain()
if project.auto_close: if project.auto_close:
# To avoid trouble with client connecting disconnecting we sleep few seconds before checking # To avoid trouble with client connecting disconnecting we sleep few seconds before checking
@ -313,10 +312,9 @@ class ProjectHandler:
await response.prepare(request) await response.prepare(request)
for data in stream: for data in stream:
response.write(data) await response.write(data)
await response.drain()
await response.write_eof() #await response.write_eof() #FIXME: shound't be needed anymore
# Will be raise if you have no space left or permission issue on your temporary directory # Will be raise if you have no space left or permission issue on your temporary directory
# RuntimeError: something was wrong during the zip process # RuntimeError: something was wrong during the zip process
except (ValueError, OSError, RuntimeError) as e: except (ValueError, OSError, RuntimeError) as e:

View File

@ -144,7 +144,7 @@ class Response(aiohttp.web.Response):
if not data: if not data:
break break
await self.write(data) await self.write(data)
await self.drain() # await self.drain()
except FileNotFoundError: except FileNotFoundError:
raise aiohttp.web.HTTPNotFound() raise aiohttp.web.HTTPNotFound()

View File

@ -200,9 +200,11 @@ def test_reload(loop, vm, fake_iou_bin):
def test_close(vm, port_manager, loop): def test_close(vm, port_manager, loop):
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("gns3server.compute.iou.iou_vm.IOUVM._check_requirements", return_value=True):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
vm.start() loop.run_until_complete(asyncio.ensure_future(vm.start()))
port = vm.console port = vm.console
loop.run_until_complete(asyncio.ensure_future(vm.close())) loop.run_until_complete(asyncio.ensure_future(vm.close()))
# Raise an exception if the port is not free # Raise an exception if the port is not free

View File

@ -150,7 +150,7 @@ def test_stop(loop, vm, running_subprocess_mock):
with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"): with asyncio_patch("gns3server.compute.qemu.QemuVM.start_wrap_console"):
with asyncio_patch("asyncio.create_subprocess_exec", return_value=process): 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"}) nio = Qemu.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.adapter_add_nio_binding(0, nio) loop.run_until_complete(asyncio.ensure_future(vm.adapter_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start())) loop.run_until_complete(asyncio.ensure_future(vm.start()))
assert vm.is_running() assert vm.is_running()
loop.run_until_complete(asyncio.ensure_future(vm.stop())) loop.run_until_complete(asyncio.ensure_future(vm.stop()))

View File

@ -55,7 +55,7 @@ def test_vm_invalid_traceng_path(vm, manager, loop):
with patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._traceng_path", return_value="/tmp/fake/path/traceng"): with patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._traceng_path", return_value="/tmp/fake/path/traceng"):
with pytest.raises(TraceNGError): with pytest.raises(TraceNGError):
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio) loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start())) loop.run_until_complete(asyncio.ensure_future(vm.start()))
assert vm.name == "test" assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e" assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e"
@ -164,16 +164,18 @@ def test_add_nio_binding_udp(vm, async_run):
assert nio.lport == 4242 assert nio.lport == 4242
def test_port_remove_nio_binding(vm): def test_port_remove_nio_binding(loop, vm):
nio = TraceNG.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) nio = TraceNG.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio) loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
vm.port_remove_nio_binding(0) loop.run_until_complete(asyncio.ensure_future(vm.port_remove_nio_binding(0)))
assert vm._ethernet_adapter.ports[0] is None assert vm._ethernet_adapter.ports[0] is None
def test_close(vm, port_manager, loop): def test_close(vm, port_manager, loop):
with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True): vm.ip_address = "192.168.1.1"
with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): with patch("sys.platform", return_value="win"):
vm.start() with asyncio_patch("gns3server.compute.traceng.traceng_vm.TraceNGVM._check_requirements", return_value=True):
loop.run_until_complete(asyncio.ensure_future(vm.close())) with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()):
assert vm.is_running() is False loop.run_until_complete(asyncio.ensure_future(vm.start("192.168.1.2")))
loop.run_until_complete(asyncio.ensure_future(vm.close()))
assert vm.is_running() is False

View File

@ -70,7 +70,7 @@ def test_vm_invalid_vpcs_version(loop, manager, vm):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.subprocess_check_output", return_value="Welcome to Virtual PC Simulator, version 0.1"): 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): with pytest.raises(VPCSError):
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}}) nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1", "filters": {}})
vm.port_add_nio_binding(0, nio) 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())) loop.run_until_complete(asyncio.ensure_future(vm._check_vpcs_version()))
assert vm.name == "test" assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f" assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0f"
@ -80,7 +80,7 @@ def test_vm_invalid_vpcs_path(vm, manager, loop):
with patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._vpcs_path", return_value="/tmp/fake/path/vpcs"): with patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._vpcs_path", return_value="/tmp/fake/path/vpcs"):
with pytest.raises(VPCSError): with pytest.raises(VPCSError):
nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) nio = manager.create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio) loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
loop.run_until_complete(asyncio.ensure_future(vm.start())) loop.run_until_complete(asyncio.ensure_future(vm.start()))
assert vm.name == "test" assert vm.name == "test"
assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e" assert vm.id == "00010203-0405-0607-0809-0a0b0c0d0e0e"
@ -220,17 +220,17 @@ def test_add_nio_binding_udp(vm, async_run):
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows") @pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
def test_add_nio_binding_tap(vm, ethernet_device): def test_add_nio_binding_tap(vm, ethernet_device, loop):
with patch("gns3server.compute.base_manager.BaseManager.has_privileged_access", return_value=True): 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}) nio = VPCS.instance().create_nio({"type": "nio_tap", "tap_device": ethernet_device})
vm.port_add_nio_binding(0, nio) loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
assert nio.tap_device == ethernet_device assert nio.tap_device == ethernet_device
def test_port_remove_nio_binding(vm): def test_port_remove_nio_binding(vm, loop):
nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"}) nio = VPCS.instance().create_nio({"type": "nio_udp", "lport": 4242, "rport": 4243, "rhost": "127.0.0.1"})
vm.port_add_nio_binding(0, nio) loop.run_until_complete(asyncio.ensure_future(vm.port_add_nio_binding(0, nio)))
vm.port_remove_nio_binding(0) loop.run_until_complete(asyncio.ensure_future(vm.port_remove_nio_binding(0)))
assert vm._ethernet_adapter.ports[0] is None assert vm._ethernet_adapter.ports[0] is None
@ -297,8 +297,10 @@ def test_change_name(vm, tmpdir):
def test_close(vm, port_manager, loop): def test_close(vm, port_manager, loop):
with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True): 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("asyncio.create_subprocess_exec", return_value=MagicMock()):
vm.start() with asyncio_patch("gns3server.compute.vpcs.vpcs_vm.VPCSVM.start_wrap_console"):
loop.run_until_complete(asyncio.ensure_future(vm.close())) loop.run_until_complete(asyncio.ensure_future(vm.start()))
assert vm.is_running() is False loop.run_until_complete(asyncio.ensure_future(vm.close()))
assert vm.is_running() is False

View File

@ -20,9 +20,11 @@ import pytest
import socket import socket
import asyncio import asyncio
import tempfile import tempfile
import weakref
import shutil import shutil
import os import os
import sys import sys
import aiohttp
from aiohttp import web from aiohttp import web
from unittest.mock import patch from unittest.mock import patch
@ -75,6 +77,16 @@ def _get_unused_port():
return port return port
@pytest.fixture
async def client(aiohttp_client):
"""
Return an helper allowing you to call the server without any prefix
"""
app = web.Application()
for method, route, handler in Route.get_routes():
app.router.add_route(method, route, handler)
return await aiohttp_client(app)
@pytest.yield_fixture @pytest.yield_fixture
def http_server(request, loop, port_manager, monkeypatch, controller): def http_server(request, loop, port_manager, monkeypatch, controller):
"""A GNS3 server""" """A GNS3 server"""
@ -83,14 +95,20 @@ def http_server(request, loop, port_manager, monkeypatch, controller):
for method, route, handler in Route.get_routes(): for method, route, handler in Route.get_routes():
app.router.add_route(method, route, handler) app.router.add_route(method, route, handler)
# Keep a list of active websocket connections
app['websockets'] = weakref.WeakSet()
host = "127.0.0.1" host = "127.0.0.1"
# We try multiple time. Because on Travis test can fail when because the port is taken by someone else # 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): for i in range(0, 5):
port = _get_unused_port() port = _get_unused_port()
try: try:
srv = loop.create_server(app.make_handler(), host, port)
srv = loop.run_until_complete(srv) runner = web.AppRunner(app)
loop.run_until_complete(runner.setup())
site = web.TCPSite(runner, host, port)
loop.run_until_complete(site.start())
except OSError: except OSError:
pass pass
else: else:
@ -98,13 +116,17 @@ def http_server(request, loop, port_manager, monkeypatch, controller):
yield (host, port) yield (host, port)
# close websocket connections
for ws in set(app['websockets']):
loop.run_until_complete(ws.close(code=aiohttp.WSCloseCode.GOING_AWAY, message='Server shutdown'))
loop.run_until_complete(controller.stop()) loop.run_until_complete(controller.stop())
for module in MODULES: for module in MODULES:
instance = module.instance() instance = module.instance()
monkeypatch.setattr('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.close', lambda self: True) monkeypatch.setattr('gns3server.compute.virtualbox.virtualbox_vm.VirtualBoxVM.close', lambda self: True)
loop.run_until_complete(instance.unload()) loop.run_until_complete(instance.unload())
srv.close()
loop.run_until_complete(srv.wait_closed()) loop.run_until_complete(runner.cleanup())
@pytest.fixture @pytest.fixture

View File

@ -80,8 +80,8 @@ def test_compute_httpQuery(compute, async_run):
response = MagicMock() response = MagicMock()
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
response.status = 200 response.status = 200
async_run(compute.post("/projects", {"a": "b"})) async_run(compute.post("/projects", {"a": "b"}))
async_run(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) 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 assert compute._auth is None
@ -94,6 +94,7 @@ def test_compute_httpQueryAuth(compute, async_run):
compute.user = "root" compute.user = "root"
compute.password = "toor" compute.password = "toor"
async_run(compute.post("/projects", {"a": "b"})) async_run(compute.post("/projects", {"a": "b"}))
async_run(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) 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.login == "root"
assert compute._auth.password == "toor" assert compute._auth.password == "toor"
@ -112,7 +113,7 @@ def test_compute_httpQueryNotConnected(compute, controller, async_run):
assert compute._connected assert compute._connected
assert compute._capabilities["version"] == __version__ assert compute._capabilities["version"] == __version__
controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__()) controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__())
async_run(compute.close())
def test_compute_httpQueryNotConnectedGNS3vmNotRunning(compute, controller, async_run): def test_compute_httpQueryNotConnectedGNS3vmNotRunning(compute, controller, async_run):
""" """
@ -136,6 +137,7 @@ def test_compute_httpQueryNotConnectedGNS3vmNotRunning(compute, controller, asyn
assert compute._connected assert compute._connected
assert compute._capabilities["version"] == __version__ assert compute._capabilities["version"] == __version__
controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__()) controller.notification.controller_emit.assert_called_with("compute.updated", compute.__json__())
async_run(compute.close())
def test_compute_httpQueryNotConnectedInvalidVersion(compute, async_run): def test_compute_httpQueryNotConnectedInvalidVersion(compute, async_run):
@ -147,7 +149,7 @@ def test_compute_httpQueryNotConnectedInvalidVersion(compute, async_run):
with pytest.raises(aiohttp.web.HTTPConflict): with pytest.raises(aiohttp.web.HTTPConflict):
async_run(compute.post("/projects", {"a": "b"})) 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("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())
def test_compute_httpQueryNotConnectedNonGNS3Server(compute, async_run): def test_compute_httpQueryNotConnectedNonGNS3Server(compute, async_run):
compute._connected = False compute._connected = False
@ -158,7 +160,7 @@ def test_compute_httpQueryNotConnectedNonGNS3Server(compute, async_run):
with pytest.raises(aiohttp.web.HTTPConflict): with pytest.raises(aiohttp.web.HTTPConflict):
async_run(compute.post("/projects", {"a": "b"})) 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("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())
def test_compute_httpQueryNotConnectedNonGNS3Server2(compute, async_run): def test_compute_httpQueryNotConnectedNonGNS3Server2(compute, async_run):
compute._connected = False compute._connected = False
@ -178,6 +180,7 @@ def test_compute_httpQueryError(compute, async_run):
with pytest.raises(aiohttp.web.HTTPNotFound): with pytest.raises(aiohttp.web.HTTPNotFound):
async_run(compute.post("/projects", {"a": "b"})) async_run(compute.post("/projects", {"a": "b"}))
async_run(compute.close())
def test_compute_httpQueryConflictError(compute, async_run): def test_compute_httpQueryConflictError(compute, async_run):
@ -188,7 +191,7 @@ def test_compute_httpQueryConflictError(compute, async_run):
with pytest.raises(ComputeConflict): with pytest.raises(ComputeConflict):
async_run(compute.post("/projects", {"a": "b"})) async_run(compute.post("/projects", {"a": "b"}))
async_run(compute.close())
def test_compute_httpQuery_project(compute, async_run): def test_compute_httpQuery_project(compute, async_run):
response = MagicMock() response = MagicMock()
@ -198,69 +201,69 @@ def test_compute_httpQuery_project(compute, async_run):
project = Project(name="Test") project = Project(name="Test")
async_run(compute.post("/projects", project)) async_run(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) 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())
# FIXME: https://github.com/aio-libs/aiohttp/issues/2525
def test_connectNotification(compute, async_run): # def test_connectNotification(compute, async_run):
ws_mock = AsyncioMagicMock() # ws_mock = AsyncioMagicMock()
#
call = 0 # call = 0
#
async def receive(): # async def receive():
nonlocal call # nonlocal call
call += 1 # call += 1
if call == 1: # if call == 1:
response = MagicMock() # response = MagicMock()
response.data = '{"action": "test", "event": {"a": 1}}' # response.data = '{"action": "test", "event": {"a": 1}}'
response.tp = aiohttp.WSMsgType.text # response.type = aiohttp.WSMsgType.TEXT
return response # return response
else: # else:
response = MagicMock() # response = MagicMock()
response.tp = aiohttp.WSMsgType.closed # response.type = aiohttp.WSMsgType.CLOSED
return response # return response
#
compute._controller._notification = MagicMock() # compute._controller._notification = MagicMock()
compute._http_session = AsyncioMagicMock(return_value=ws_mock) # compute._http_session = AsyncioMagicMock(return_value=ws_mock)
compute._http_session.ws_connect = AsyncioMagicMock(return_value=ws_mock) # compute._http_session.ws_connect = AsyncioMagicMock(return_value=ws_mock)
ws_mock.receive = receive # ws_mock.receive = receive
async_run(compute._connect_notification()) # async_run(compute._connect_notification())
#
compute._controller.notification.dispatch.assert_called_with('test', {'a': 1}, compute_id=compute.id) # compute._controller.notification.dispatch.assert_called_with('test', {'a': 1}, compute_id=compute.id)
assert compute._connected is False # assert compute._connected is False
#
#
def test_connectNotificationPing(compute, async_run): # def test_connectNotificationPing(compute, async_run):
""" # """
When we receive a ping from a compute we update # When we receive a ping from a compute we update
the compute memory and CPU usage # the compute memory and CPU usage
""" # """
ws_mock = AsyncioMagicMock() # ws_mock = AsyncioMagicMock()
#
call = 0 # call = 0
#
async def receive(): # async def receive():
nonlocal call # nonlocal call
call += 1 # call += 1
if call == 1: # if call == 1:
response = MagicMock() # response = MagicMock()
response.data = '{"action": "ping", "event": {"cpu_usage_percent": 35.7, "memory_usage_percent": 80.7}}' # response.data = '{"action": "ping", "event": {"cpu_usage_percent": 35.7, "memory_usage_percent": 80.7}}'
response.tp = aiohttp.WSMsgType.text # response.type = aiohttp.WSMsgType.TEST
return response # return response
else: # else:
response = MagicMock() # response = MagicMock()
response.tp = aiohttp.WSMsgType.closed # response.type = aiohttp.WSMsgType.CLOSED
return response #
# compute._controller._notification = MagicMock()
compute._controller._notification = MagicMock() # compute._http_session = AsyncioMagicMock(return_value=ws_mock)
compute._http_session = AsyncioMagicMock(return_value=ws_mock) # compute._http_session.ws_connect = AsyncioMagicMock(return_value=ws_mock)
compute._http_session.ws_connect = AsyncioMagicMock(return_value=ws_mock) # ws_mock.receive = receive
ws_mock.receive = receive # async_run(compute._connect_notification())
async_run(compute._connect_notification()) #
# assert not compute._controller.notification.dispatch.called
assert not compute._controller.notification.dispatch.called # args, _ = compute._controller.notification.controller_emit.call_args_list[0]
args, _ = compute._controller.notification.controller_emit.call_args_list[0] # assert args[0] == "compute.updated"
assert args[0] == "compute.updated" # assert args[1]["memory_usage_percent"] == 80.7
assert args[1]["memory_usage_percent"] == 80.7 # assert args[1]["cpu_usage_percent"] == 35.7
assert args[1]["cpu_usage_percent"] == 35.7
def test_json(compute): def test_json(compute):
@ -296,6 +299,7 @@ def test_streamFile(project, async_run, compute):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.stream_file(project, "test/titi", timeout=120)) async_run(compute.stream_file(project, "test/titi", timeout=120))
mock.assert_called_with("GET", "https://example.com:84/v2/compute/projects/{}/stream/test/titi".format(project.id), auth=None, timeout=120) mock.assert_called_with("GET", "https://example.com:84/v2/compute/projects/{}/stream/test/titi".format(project.id), auth=None, timeout=120)
async_run(compute.close())
def test_downloadFile(project, async_run, compute): def test_downloadFile(project, async_run, compute):
@ -304,7 +308,7 @@ def test_downloadFile(project, async_run, compute):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.download_file(project, "test/titi")) async_run(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) mock.assert_called_with("GET", "https://example.com:84/v2/compute/projects/{}/files/test/titi".format(project.id), auth=None)
async_run(compute.close())
def test_close(compute, async_run): def test_close(compute, async_run):
assert compute.connected is True assert compute.connected is True
@ -332,7 +336,7 @@ def test_forward_get(compute, async_run):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.forward("GET", "qemu", "images")) async_run(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) 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())
def test_forward_404(compute, async_run): def test_forward_404(compute, async_run):
response = MagicMock() response = MagicMock()
@ -340,7 +344,7 @@ def test_forward_404(compute, async_run):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
with pytest.raises(aiohttp.web_exceptions.HTTPNotFound): with pytest.raises(aiohttp.web_exceptions.HTTPNotFound):
async_run(compute.forward("GET", "qemu", "images")) async_run(compute.forward("GET", "qemu", "images"))
async_run(compute.close())
def test_forward_post(compute, async_run): def test_forward_post(compute, async_run):
response = MagicMock() response = MagicMock()
@ -348,7 +352,7 @@ def test_forward_post(compute, async_run):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
async_run(compute.forward("POST", "qemu", "img", data={"id": 42})) async_run(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) 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())
def test_images(compute, async_run, images_dir): def test_images(compute, async_run, images_dir):
""" """
@ -365,6 +369,7 @@ def test_images(compute, async_run, images_dir):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
images = async_run(compute.images("qemu")) images = async_run(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) 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())
assert images == [ assert images == [
{"filename": "asa.qcow2", "path": "asa.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0}, {"filename": "asa.qcow2", "path": "asa.qcow2", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "filesize": 0},
@ -380,7 +385,7 @@ def test_list_files(project, async_run, compute):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
assert async_run(compute.list_files(project)) == res assert async_run(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) 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())
def test_interfaces(project, async_run, compute): def test_interfaces(project, async_run, compute):
res = [ res = [
@ -399,7 +404,7 @@ def test_interfaces(project, async_run, compute):
with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock: with asyncio_patch("aiohttp.ClientSession.request", return_value=response) as mock:
assert async_run(compute.interfaces()) == res assert async_run(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) 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())
def test_get_ip_on_same_subnet(controller, async_run): def test_get_ip_on_same_subnet(controller, async_run):
compute1 = Compute("compute1", host="192.168.1.1", controller=controller) compute1 = Compute("compute1", host="192.168.1.1", controller=controller)

View File

@ -373,6 +373,7 @@ def test_export_images_from_vm(tmpdir, project, async_run, controller):
mock_response.status = 200 mock_response.status = 200
compute.download_file = AsyncioMagicMock(return_value=mock_response) compute.download_file = AsyncioMagicMock(return_value=mock_response)
mock_response = AsyncioMagicMock() mock_response = AsyncioMagicMock()
mock_response.content = AsyncioBytesIO() mock_response.content = AsyncioBytesIO()
async_run(mock_response.content.write(b"IMAGE")) async_run(mock_response.content.write(b"IMAGE"))
@ -380,6 +381,7 @@ def test_export_images_from_vm(tmpdir, project, async_run, controller):
mock_response.status = 200 mock_response.status = 200
compute.download_image = AsyncioMagicMock(return_value=mock_response) compute.download_image = AsyncioMagicMock(return_value=mock_response)
project._project_created_on_compute.add(compute) project._project_created_on_compute.add(compute)
path = project.path path = project.path

View File

@ -298,7 +298,7 @@ def test_start_streaming_pcap(link, async_run, tmpdir, project):
with open(os.path.join(project.captures_directory, "test.pcap"), "rb") as f: with open(os.path.join(project.captures_directory, "test.pcap"), "rb") as f:
c = f.read() c = f.read()
assert c == b"hello" assert c == b"hello"
async_run(link.read_pcap_from_source.close())
def test_default_capture_file_name(project, compute, async_run): def test_default_capture_file_name(project, compute, async_run):
node1 = Node(project, compute, "Hello@", node_type="qemu") node1 = Node(project, compute, "Hello@", node_type="qemu")

View File

@ -66,9 +66,9 @@ class Query:
""" """
Return a websocket connected to the path Return a websocket connected to the path
""" """
self._session = aiohttp.ClientSession()
async def go_request(future): async def go_request(future):
self._session = aiohttp.ClientSession()
response = await self._session.ws_connect(self.get_url(path)) response = await self._session.ws_connect(self.get_url(path))
future.set_result(response) future.set_result(response)
future = asyncio.Future() future = asyncio.Future()
@ -90,30 +90,31 @@ class Query:
body = json.dumps(body) body = json.dumps(body)
connector = aiohttp.TCPConnector() connector = aiohttp.TCPConnector()
response = await aiohttp.request(method, self.get_url(path), data=body, loop=self._loop, connector=connector) async with aiohttp.request(method, self.get_url(path), data=body, loop=self._loop, connector=connector) as response:
response.body = await response.read() response.body = await response.read()
x_route = response.headers.get('X-Route', None) x_route = response.headers.get('X-Route', None)
if x_route is not None: if x_route is not None:
response.route = x_route.replace("/v{}".format(self._api_version), "") response.route = x_route.replace("/v{}".format(self._api_version), "")
response.route = response.route .replace(self._prefix, "") response.route = response.route .replace(self._prefix, "")
response.json = {} response.json = {}
response.html = "" response.html = ""
if response.body is not None: if response.body is not None:
if response.headers.get("CONTENT-TYPE", "") == "application/json": if response.headers.get("CONTENT-TYPE", "") == "application/json":
try: try:
response.json = json.loads(response.body.decode("utf-8")) response.json = json.loads(response.body.decode("utf-8"))
except ValueError: except ValueError:
response.json = None response.json = None
else: else:
try: try:
response.html = response.body.decode("utf-8") response.html = response.body.decode("utf-8")
except UnicodeDecodeError: except UnicodeDecodeError:
response.html = None response.html = None
if kwargs.get('example') and os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1": if kwargs.get('example') and os.environ.get("PYTEST_BUILD_DOCUMENTATION") == "1":
self._dump_example(method, response.route, path, body, response) self._dump_example(method, response.route, path, body, response)
return response return response
return None
def _dump_example(self, method, route, path, body, response): def _dump_example(self, method, route, path, body, response):
"""Dump the request for the documentation""" """Dump the request for the documentation"""

View File

@ -340,13 +340,12 @@ def test_stop_capture(http_controller, tmpdir, project, compute, async_run):
assert response.status == 201 assert response.status == 201
def test_pcap(http_controller, tmpdir, project, compute, loop): def test_pcap(http_controller, tmpdir, project, compute, async_run):
async def go(future): async def go():
response = await aiohttp.request("GET", http_controller.get_url("/projects/{}/links/{}/pcap".format(project.id, link.id))) async with aiohttp.request("GET", http_controller.get_url("/projects/{}/links/{}/pcap".format(project.id, link.id))) as response:
response.body = await response.content.read(5) response.body = await response.content.read(5)
response.close() return response
future.set_result(response)
link = Link(project) link = Link(project)
link._capture_file_name = "test" link._capture_file_name = "test"
@ -354,10 +353,7 @@ def test_pcap(http_controller, tmpdir, project, compute, loop):
with open(link.capture_file_path, "w+") as f: with open(link.capture_file_path, "w+") as f:
f.write("hello") f.write("hello")
project._links = {link.id: link} project._links = {link.id: link}
response = async_run(asyncio.ensure_future(go()))
future = asyncio.Future()
asyncio.ensure_future(go(future))
response = loop.run_until_complete(future)
assert response.status == 200 assert response.status == 200
assert b'hello' == response.body assert b'hello' == response.body

View File

@ -172,12 +172,11 @@ def test_notification(http_controller, project, controller, loop, async_run):
async def go(): async def go():
connector = aiohttp.TCPConnector() connector = aiohttp.TCPConnector()
response = await aiohttp.request("GET", http_controller.get_url("/projects/{project_id}/notifications".format(project_id=project.id)), connector=connector) 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) response.body = await response.content.read(200)
controller.notification.project_emit("node.created", {"a": "b"}) controller.notification.project_emit("node.created", {"a": "b"})
response.body += await response.content.readany() response.body += await response.content.readany()
response.close() return response
return response
response = async_run(asyncio.ensure_future(go())) response = async_run(asyncio.ensure_future(go()))
assert response.status == 200 assert response.status == 200
@ -205,7 +204,7 @@ def test_notification_ws(http_controller, controller, project, async_run):
assert answer["action"] == "test" assert answer["action"] == "test"
async_run(http_controller.close()) async_run(http_controller.close())
ws.close() async_run(ws.close())
assert project.status == "opened" assert project.status == "opened"

View File

@ -19,24 +19,24 @@ import asyncio
from gns3server.utils.asyncio.embed_shell import EmbedShell from gns3server.utils.asyncio.embed_shell import EmbedShell
#FIXME: this is broken with recent Python >= 3.6
def test_embed_shell_help(async_run): # def test_embed_shell_help(async_run):
class Application(EmbedShell): # class Application(EmbedShell):
#
async def hello(self): # async def hello(self):
""" # """
The hello world function # The hello world function
#
The hello usage # The hello usage
""" # """
await asyncio.sleep(1) # await asyncio.sleep(1)
#
reader = asyncio.StreamReader() # reader = asyncio.StreamReader()
writer = asyncio.StreamReader() # writer = asyncio.StreamReader()
app = Application(reader, writer) # app = Application(reader, writer)
assert async_run(app._parse_command('help')) == 'Help:\nhello: The hello world function\n\nhelp command for details about a command\n' # assert async_run(app._parse_command('help')) == 'Help:\nhello: The hello world function\n\nhelp command for details about a command\n'
assert async_run(app._parse_command('?')) == 'Help:\nhello: The hello world function\n\nhelp command for details about a command\n' # assert async_run(app._parse_command('?')) == 'Help:\nhello: The hello world function\n\nhelp command for details about a command\n'
assert async_run(app._parse_command('? hello')) == 'hello: The hello world function\n\nThe hello usage\n' # assert async_run(app._parse_command('? hello')) == 'hello: The hello world function\n\nThe hello usage\n'
def test_embed_shell_execute(async_run): def test_embed_shell_execute(async_run):
@ -59,9 +59,13 @@ def test_embed_shell_welcome(async_run, loop):
reader = asyncio.StreamReader() reader = asyncio.StreamReader()
writer = asyncio.StreamReader() writer = asyncio.StreamReader()
app = EmbedShell(reader, writer, welcome_message="Hello") app = EmbedShell(reader, writer, welcome_message="Hello")
t = loop.create_task(app.run()) task = loop.create_task(app.run())
assert async_run(writer.read(5)) == b"Hello" assert async_run(writer.read(5)) == b"Hello"
t.cancel() task.cancel()
try:
loop.run_until_complete(task)
except asyncio.CancelledError:
pass
def test_embed_shell_prompt(async_run, loop): def test_embed_shell_prompt(async_run, loop):
@ -69,6 +73,10 @@ def test_embed_shell_prompt(async_run, loop):
writer = asyncio.StreamReader() writer = asyncio.StreamReader()
app = EmbedShell(reader, writer) app = EmbedShell(reader, writer)
app.prompt = "gbash# " app.prompt = "gbash# "
t = loop.create_task(app.run()) task = loop.create_task(app.run())
assert async_run(writer.read(7)) == b"gbash# " assert async_run(writer.read(7)) == b"gbash# "
t.cancel() task.cancel()
try:
loop.run_until_complete(task)
except asyncio.CancelledError:
pass