mirror of
https://github.com/GNS3/gns3-server.git
synced 2024-11-16 16:54:51 +02:00
Add project.created, project.opened and project.deleted controller notification stream.
Move project.updated and project.closed from project notification to controller notification stream.
This commit is contained in:
parent
d466c85385
commit
e3493870b2
@ -130,16 +130,27 @@ class Project:
|
|||||||
self._iou_id_lock = asyncio.Lock()
|
self._iou_id_lock = asyncio.Lock()
|
||||||
|
|
||||||
log.debug('Project "{name}" [{id}] loaded'.format(name=self.name, id=self._id))
|
log.debug('Project "{name}" [{id}] loaded'.format(name=self.name, id=self._id))
|
||||||
|
self.emit_controller_notification("project.created", self.__json__())
|
||||||
|
|
||||||
def emit_notification(self, action, event):
|
def emit_notification(self, action, event):
|
||||||
"""
|
"""
|
||||||
Emit a notification to all clients using this project.
|
Emit a project notification to all clients using this project.
|
||||||
|
|
||||||
:param action: Action name
|
:param action: Action name
|
||||||
:param event: Event to send
|
:param event: Event to send
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.controller.notification.project_emit(action, event, project_id=self.id)
|
self._controller.notification.project_emit(action, event, project_id=self.id)
|
||||||
|
|
||||||
|
def emit_controller_notification(self, action, event):
|
||||||
|
"""
|
||||||
|
Emit a controller notification, all clients will see it.
|
||||||
|
|
||||||
|
:param action: Action name
|
||||||
|
:param event: Event to send
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._controller.notification.controller_emit(action, event)
|
||||||
|
|
||||||
async def update(self, **kwargs):
|
async def update(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -154,7 +165,7 @@ class Project:
|
|||||||
|
|
||||||
# We send notif only if object has changed
|
# We send notif only if object has changed
|
||||||
if old_json != self.__json__():
|
if old_json != self.__json__():
|
||||||
self.emit_notification("project.updated", self.__json__())
|
self.emit_controller_notification("project.updated", self.__json__())
|
||||||
self.dump()
|
self.dump()
|
||||||
|
|
||||||
# update on computes
|
# update on computes
|
||||||
@ -803,7 +814,8 @@ class Project:
|
|||||||
self._clean_pictures()
|
self._clean_pictures()
|
||||||
self._status = "closed"
|
self._status = "closed"
|
||||||
if not ignore_notification:
|
if not ignore_notification:
|
||||||
self.emit_notification("project.closed", self.__json__())
|
self.emit_controller_notification("project.closed", self.__json__())
|
||||||
|
|
||||||
self.reset()
|
self.reset()
|
||||||
self._closing = False
|
self._closing = False
|
||||||
|
|
||||||
@ -857,6 +869,7 @@ class Project:
|
|||||||
shutil.rmtree(self.path)
|
shutil.rmtree(self.path)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise aiohttp.web.HTTPConflict(text="Cannot delete project directory {}: {}".format(self.path, str(e)))
|
raise aiohttp.web.HTTPConflict(text="Cannot delete project directory {}: {}".format(self.path, str(e)))
|
||||||
|
self.emit_controller_notification("project.deleted", self.__json__())
|
||||||
|
|
||||||
async def delete_on_computes(self):
|
async def delete_on_computes(self):
|
||||||
"""
|
"""
|
||||||
@ -976,7 +989,7 @@ class Project:
|
|||||||
await self.add_drawing(dump=False, **drawing_data)
|
await self.add_drawing(dump=False, **drawing_data)
|
||||||
|
|
||||||
self.dump()
|
self.dump()
|
||||||
# We catch all error to be able to rollback the .gns3 to the previous state
|
# We catch all error to be able to roll back the .gns3 to the previous state
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
for compute in list(self._project_created_on_compute):
|
for compute in list(self._project_created_on_compute):
|
||||||
try:
|
try:
|
||||||
@ -1001,6 +1014,7 @@ class Project:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
self._loading = False
|
self._loading = False
|
||||||
|
self.emit_controller_notification("project.opened", self.__json__())
|
||||||
# Should we start the nodes when project is open
|
# Should we start the nodes when project is open
|
||||||
if self._auto_start:
|
if self._auto_start:
|
||||||
# Start all in the background without waiting for completion
|
# Start all in the background without waiting for completion
|
||||||
|
@ -213,7 +213,9 @@ async def test_compute_httpQuery_project(compute):
|
|||||||
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
|
||||||
project = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
|
project = Project(name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
await 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)
|
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)
|
||||||
await compute.close()
|
await compute.close()
|
||||||
|
@ -47,15 +47,19 @@ async def node(controller, project):
|
|||||||
|
|
||||||
async def test_affect_uuid():
|
async def test_affect_uuid():
|
||||||
|
|
||||||
p = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
assert len(p.id) == 36
|
p = Project(name="Test")
|
||||||
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test 2")
|
mock_notification.assert_called()
|
||||||
assert p.id == '00010203-0405-0607-0809-0a0b0c0d0e0f'
|
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'
|
||||||
|
|
||||||
|
|
||||||
async def test_json():
|
async def test_json():
|
||||||
|
|
||||||
p = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
|
p = Project(name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
|
|
||||||
assert p.__json__() == {
|
assert p.__json__() == {
|
||||||
"name": "Test",
|
"name": "Test",
|
||||||
@ -83,11 +87,11 @@ async def test_json():
|
|||||||
async def test_update(controller):
|
async def test_update(controller):
|
||||||
|
|
||||||
project = Project(controller=controller, name="Hello")
|
project = Project(controller=controller, name="Hello")
|
||||||
project.emit_notification = MagicMock()
|
project.emit_controller_notification = MagicMock()
|
||||||
assert project.name == "Hello"
|
assert project.name == "Hello"
|
||||||
await project.update(name="World")
|
await project.update(name="World")
|
||||||
assert project.name == "World"
|
assert project.name == "World"
|
||||||
project.emit_notification.assert_any_call("project.updated", project.__json__())
|
project.emit_controller_notification.assert_any_call("project.updated", project.__json__())
|
||||||
|
|
||||||
|
|
||||||
async def test_update_on_compute(controller):
|
async def test_update_on_compute(controller):
|
||||||
@ -106,7 +110,9 @@ async def test_path(projects_dir):
|
|||||||
|
|
||||||
directory = projects_dir
|
directory = projects_dir
|
||||||
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
||||||
p = Project(project_id=str(uuid4()), name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
|
p = Project(project_id=str(uuid4()), name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
assert p.path == os.path.join(directory, p.id)
|
assert p.path == os.path.join(directory, p.id)
|
||||||
assert os.path.exists(os.path.join(directory, p.id))
|
assert os.path.exists(os.path.join(directory, p.id))
|
||||||
|
|
||||||
@ -124,23 +130,27 @@ def test_path_exist(tmpdir):
|
|||||||
|
|
||||||
async def test_init_path(tmpdir):
|
async def test_init_path(tmpdir):
|
||||||
|
|
||||||
p = Project(path=str(tmpdir), project_id=str(uuid4()), name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification') as mock_notification:
|
||||||
assert p.path == str(tmpdir)
|
p = Project(path=str(tmpdir), project_id=str(uuid4()), name="Test")
|
||||||
|
mock_notification.assert_called()
|
||||||
|
assert p.path == str(tmpdir)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
|
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
|
||||||
async 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):
|
with pytest.raises(aiohttp.web.HTTPForbidden):
|
||||||
p = Project(project_id=str(uuid4()), name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
p.path = str(tmpdir / "project\"53")
|
p = Project(project_id=str(uuid4()), name="Test")
|
||||||
|
p.path = str(tmpdir / "project\"53")
|
||||||
|
|
||||||
|
|
||||||
async def test_captures_directory(tmpdir):
|
async def test_captures_directory(tmpdir):
|
||||||
|
|
||||||
p = Project(path=str(tmpdir / "capturestest"), name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
assert p.captures_directory == str(tmpdir / "capturestest" / "project-files" / "captures")
|
p = Project(path=str(tmpdir / "capturestest"), name="Test")
|
||||||
assert os.path.exists(p.captures_directory)
|
assert p.captures_directory == str(tmpdir / "capturestest" / "project-files" / "captures")
|
||||||
|
assert os.path.exists(p.captures_directory)
|
||||||
|
|
||||||
|
|
||||||
async def test_add_node_local(controller):
|
async def test_add_node_local(controller):
|
||||||
@ -649,36 +659,39 @@ async def test_dump(projects_dir):
|
|||||||
|
|
||||||
directory = projects_dir
|
directory = projects_dir
|
||||||
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
with patch("gns3server.utils.path.get_default_project_directory", return_value=directory):
|
||||||
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
p.dump()
|
p = Project(project_id='00010203-0405-0607-0809-0a0b0c0d0e0f', name="Test")
|
||||||
with open(os.path.join(directory, p.id, "Test.gns3")) as f:
|
p.dump()
|
||||||
content = f.read()
|
with open(os.path.join(directory, p.id, "Test.gns3")) as f:
|
||||||
assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
|
content = f.read()
|
||||||
|
assert "00010203-0405-0607-0809-0a0b0c0d0e0f" in content
|
||||||
|
|
||||||
|
|
||||||
async def test_open_close(controller):
|
async def test_open_close(controller):
|
||||||
|
|
||||||
project = Project(controller=controller, name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
assert project.status == "opened"
|
project = Project(controller=controller, name="Test")
|
||||||
await project.close()
|
assert project.status == "opened"
|
||||||
project.start_all = AsyncioMagicMock()
|
await project.close()
|
||||||
await project.open()
|
project.start_all = AsyncioMagicMock()
|
||||||
assert not project.start_all.called
|
await project.open()
|
||||||
assert project.status == "opened"
|
assert not project.start_all.called
|
||||||
project.emit_notification = MagicMock()
|
assert project.status == "opened"
|
||||||
await project.close()
|
project.emit_controller_notification = MagicMock()
|
||||||
assert project.status == "closed"
|
await project.close()
|
||||||
project.emit_notification.assert_any_call("project.closed", project.__json__())
|
assert project.status == "closed"
|
||||||
|
project.emit_controller_notification.assert_any_call("project.closed", project.__json__())
|
||||||
|
|
||||||
|
|
||||||
async def test_open_auto_start(controller):
|
async def test_open_auto_start(controller):
|
||||||
|
|
||||||
project = Project(controller=controller, name="Test", auto_start=True)
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
assert project.status == "opened"
|
project = Project(controller=controller, name="Test", auto_start=True)
|
||||||
await project.close()
|
assert project.status == "opened"
|
||||||
project.start_all = AsyncioMagicMock()
|
await project.close()
|
||||||
await project.open()
|
project.start_all = AsyncioMagicMock()
|
||||||
assert project.start_all.called
|
await project.open()
|
||||||
|
assert project.start_all.called
|
||||||
|
|
||||||
|
|
||||||
def test_is_running(project, node):
|
def test_is_running(project, node):
|
||||||
|
@ -19,7 +19,7 @@ import json
|
|||||||
import uuid
|
import uuid
|
||||||
import pytest
|
import pytest
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock, patch
|
||||||
from tests.utils import asyncio_patch
|
from tests.utils import asyncio_patch
|
||||||
|
|
||||||
from gns3server.controller.project import Project
|
from gns3server.controller.project import Project
|
||||||
@ -30,35 +30,36 @@ from gns3server.version import __version__
|
|||||||
|
|
||||||
async def test_project_to_topology_empty(tmpdir):
|
async def test_project_to_topology_empty(tmpdir):
|
||||||
|
|
||||||
project = Project(name="Test")
|
with patch('gns3server.controller.project.Project.emit_controller_notification'):
|
||||||
topo = project_to_topology(project)
|
project = Project(name="Test")
|
||||||
assert topo == {
|
topo = project_to_topology(project)
|
||||||
"project_id": project.id,
|
assert topo == {
|
||||||
"name": "Test",
|
"project_id": project.id,
|
||||||
"auto_start": False,
|
"name": "Test",
|
||||||
"auto_close": True,
|
"auto_start": False,
|
||||||
"auto_open": False,
|
"auto_close": True,
|
||||||
"scene_width": 2000,
|
"auto_open": False,
|
||||||
"scene_height": 1000,
|
"scene_width": 2000,
|
||||||
"revision": GNS3_FILE_FORMAT_REVISION,
|
"scene_height": 1000,
|
||||||
"zoom": 100,
|
"revision": GNS3_FILE_FORMAT_REVISION,
|
||||||
"show_grid": False,
|
"zoom": 100,
|
||||||
"show_interface_labels": False,
|
"show_grid": False,
|
||||||
"show_layers": False,
|
"show_interface_labels": False,
|
||||||
"snap_to_grid": False,
|
"show_layers": False,
|
||||||
"grid_size": 75,
|
"snap_to_grid": False,
|
||||||
"drawing_grid_size": 25,
|
"grid_size": 75,
|
||||||
"topology": {
|
"drawing_grid_size": 25,
|
||||||
"nodes": [],
|
"topology": {
|
||||||
"links": [],
|
"nodes": [],
|
||||||
"computes": [],
|
"links": [],
|
||||||
"drawings": []
|
"computes": [],
|
||||||
},
|
"drawings": []
|
||||||
"type": "topology",
|
},
|
||||||
"supplier": None,
|
"type": "topology",
|
||||||
"variables": None,
|
"supplier": None,
|
||||||
"version": __version__
|
"variables": None,
|
||||||
}
|
"version": __version__
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_basic_topology(controller):
|
async def test_basic_topology(controller):
|
||||||
|
Loading…
Reference in New Issue
Block a user