refactor: ruff autofixes

This commit is contained in:
Mark Paronyan committed 2026-09-27 15:55:10 +03:00
1 parent 2ac637c662
commit a0450b6bce
455 files changed
+12322 -14762

No files matched your search

+217 -291
View File
@@ -35,202 +35,157 @@ pytestmark = pytest.mark.asyncio
class TestControllerProjectRoutes:
@pytest_asyncio.fixture
async def project(self, app: FastAPI, client: AsyncClient, controller: Controller) -> Project:
project_id = str(uuid.uuid4())
params = {"name": "test", "project_id": project_id}
await client.post(app.url_path_for("create_project"), json=params)
return controller.get_project(project_id)
async def test_create_project_with_path(
self,
app: FastAPI,
client: AsyncClient,
controller: Controller,
config
self, app: FastAPI, client: AsyncClient, controller: Controller, config
) -> None:
params = {"name": "test", "path": str(config.settings.Server.projects_path), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"}
params = {
"name": "test",
"path": str(config.settings.Server.projects_path),
"project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f",
}
response = await client.post(app.url_path_for("create_project"), json=params)
# The projects directory itself must never become a project directory
assert response.status_code == status.HTTP_403_FORBIDDEN
params = {"name": "test", "path": os.path.join(str(config.settings.Server.projects_path), "custom"), "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"}
params = {
"name": "test",
"path": os.path.join(str(config.settings.Server.projects_path), "custom"),
"project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f",
}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "test"
assert response.json()["project_id"] == "00010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json()["status"] == "opened"
async def test_create_project_without_dir(
self,
app: FastAPI,
client: AsyncClient,
controller: Controller
) -> None:
async def test_create_project_without_dir(self, app: FastAPI, client: AsyncClient, controller: Controller) -> None:
params = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["project_id"] == "10010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json()["name"] == "test"
async def test_create_project_with_uuid(
self,
app: FastAPI,
client: AsyncClient,
controller: Controller
) -> None:
async def test_create_project_with_uuid(self, app: FastAPI, client: AsyncClient, controller: Controller) -> None:
params = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f"}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == 201
assert response.json()["project_id"] == "30010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json()["name"] == "test"
async def test_create_project_with_variables(
self,
app: FastAPI,
client: AsyncClient,
controller: Controller
self, app: FastAPI, client: AsyncClient, controller: Controller
) -> None:
variables = [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
]
variables = [{"name": "TEST1"}, {"name": "TEST2", "value": "value1"}]
params = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f", "variables": variables}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == 201
assert response.json()["variables"] == [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
]
assert response.json()["variables"] == [{"name": "TEST1"}, {"name": "TEST2", "value": "value1"}]
async def test_create_project_with_supplier(
self,
app: FastAPI,
client: AsyncClient,
controller: Controller
self, app: FastAPI, client: AsyncClient, controller: Controller
) -> None:
supplier = {
'logo': 'logo.png',
'url': 'http://example.com/'
}
supplier = {"logo": "logo.png", "url": "http://example.com/"}
params = {"name": "test", "project_id": "30010203-0405-0607-0809-0a0b0c0d0e0f", "supplier": supplier}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["supplier"] == supplier
async def test_update_project(self, app: FastAPI, client: AsyncClient, controller: Controller) -> None:
params = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f"}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["project_id"] == "10010203-0405-0607-0809-0a0b0c0d0e0f"
assert response.json()["name"] == "test"
params = {"name": "test2"}
response = await client.put(app.url_path_for("update_project", project_id="10010203-0405-0607-0809-0a0b0c0d0e0f"),
json=params)
response = await client.put(
app.url_path_for("update_project", project_id="10010203-0405-0607-0809-0a0b0c0d0e0f"), json=params
)
assert response.status_code == status.HTTP_200_OK
assert response.json()["name"] == "test2"
async def test_update_project_with_variables(
self,
app: FastAPI,
client: AsyncClient,
controller: Controller
self, app: FastAPI, client: AsyncClient, controller: Controller
) -> None:
variables = [
{"name": "TEST1"},
{"name": "TEST2", "value": "value1"}
]
variables = [{"name": "TEST1"}, {"name": "TEST2", "value": "value1"}]
params = {"name": "test", "project_id": "10010203-0405-0607-0809-0a0b0c0d0e0f", "variables": variables}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == status.HTTP_201_CREATED
params = {"name": "test2"}
response = await client.put(app.url_path_for("update_project", project_id="10010203-0405-0607-0809-0a0b0c0d0e0f"),
json=params)
response = await client.put(
app.url_path_for("update_project", project_id="10010203-0405-0607-0809-0a0b0c0d0e0f"), json=params
)
assert response.status_code == status.HTTP_200_OK
assert response.json()["variables"] == variables
async def test_list_projects(self, app: FastAPI, client: AsyncClient, controller: Controller) -> None:
params = {"name": "test", "project_id": "00010203-0405-0607-0809-0a0b0c0d0e0f"}
await client.post(app.url_path_for("create_project"), json=params)
response = await client.get(app.url_path_for("get_projects"))
assert response.status_code == status.HTTP_200_OK
projects = response.json()
assert projects[0]["name"] == "test"
async def test_get_project(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
response = await client.get(app.url_path_for("get_project", project_id=project.id))
assert response.status_code == status.HTTP_200_OK
assert response.json()["name"] == "test"
async def test_delete_project(
self,
app: FastAPI,
client: AsyncClient,
project: Project,
controller: Controller
self, app: FastAPI, client: AsyncClient, project: Project, controller: Controller
) -> None:
with asyncio_patch("gns3server.controller.project.Project.delete", return_value=True) as mock:
response = await client.delete(app.url_path_for("delete_project", project_id=project.id))
assert response.status_code == status.HTTP_204_NO_CONTENT
assert mock.called
assert project not in controller.projects
async def test_delete_project_invalid_uuid(self, app: FastAPI, client: AsyncClient) -> None:
response = await client.delete(app.url_path_for("delete_project", project_id=str(uuid.uuid4())))
assert response.status_code == status.HTTP_404_NOT_FOUND
async def test_close_project(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
with asyncio_patch("gns3server.controller.project.Project.close", return_value=True) as mock:
response = await client.post(app.url_path_for("close_project", project_id=project.id))
assert response.status_code == status.HTTP_204_NO_CONTENT
assert mock.called
async def test_open_project(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
with asyncio_patch("gns3server.controller.project.Project.open", return_value=True) as mock:
response = await client.post(app.url_path_for("open_project", project_id=project.id))
assert response.status_code == status.HTTP_201_CREATED
assert mock.called
async def test_load_project(self, app: FastAPI, client: AsyncClient, project: Project, config) -> None:
with asyncio_patch("gns3server.controller.Controller.load_project", return_value=project) as mock:
response = await client.post(app.url_path_for("load_project"), json={"path": "/tmp/test.gns3"})
assert response.status_code == status.HTTP_201_CREATED
mock.assert_called_with("/tmp/test.gns3")
assert response.json()["project_id"] == project.id
# @pytest.mark.asyncio
# async def test_notification(controller_api, http_client, project, controller):
#
@@ -250,8 +205,7 @@ class TestControllerProjectRoutes:
#
# response = await controller_api.get("/projects/{project_id}/notifications".format(project_id=uuid.uuid4()))
# assert response.status_code == 404
# @pytest.mark.asyncio
# async def test_notification_ws(controller_api, http_client, controller, project):
#
@@ -269,179 +223,155 @@ class TestControllerProjectRoutes:
# await ws.close()
#
# assert project.status_code == "opened"
async def test_export_with_images(
self,
app: FastAPI,
client: AsyncClient,
tmpdir,
project: Project
) -> None:
async def test_export_with_images(self, app: FastAPI, client: AsyncClient, tmpdir, project: Project) -> None:
project.dump = MagicMock()
os.makedirs(project.path, exist_ok=True)
with open(os.path.join(project.path, 'a'), 'w+') as f:
f.write('hello')
with open(os.path.join(project.path, "a"), "w+") as f:
f.write("hello")
os.makedirs(str(tmpdir / "IOS"))
with open(str(tmpdir / "IOS" / "test.image"), "w+") as f:
f.write("AAA")
topology = {
"topology": {
"nodes": [
{
"properties": {
"image": "test.image"
},
"node_type": "dynamips"
}
]
}
}
with open(os.path.join(project.path, "test.gns3"), 'w+') as f:
topology = {"topology": {"nodes": [{"properties": {"image": "test.image"}, "node_type": "dynamips"}]}}
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 = await client.get(app.url_path_for("export_project", project_id=project.id),
params={"include_images": "yes"})
response = await client.get(
app.url_path_for("export_project", project_id=project.id), params={"include_images": "yes"}
)
assert response.status_code == status.HTTP_200_OK
assert response.headers['CONTENT-TYPE'] == 'application/gns3project'
assert response.headers['CONTENT-DISPOSITION'] == 'attachment; filename="{name}.gns3project"; filename*=UTF-8\'\'{name}.gns3project'.format(name=project.name)
with open(str(tmpdir / 'project.zip'), 'wb+') as f:
assert response.headers["CONTENT-TYPE"] == "application/gns3project"
assert response.headers[
"CONTENT-DISPOSITION"
] == "attachment; filename=\"{name}.gns3project\"; filename*=UTF-8''{name}.gns3project".format(
name=project.name
)
with open(str(tmpdir / "project.zip"), "wb+") as f:
f.write(response.content)
with zipfile_zstd.ZipFile(str(tmpdir / 'project.zip')) as myzip:
with zipfile_zstd.ZipFile(str(tmpdir / "project.zip")) as myzip:
with myzip.open("a") as myfile:
content = myfile.read()
assert content == b"hello"
myzip.getinfo("images/IOS/test.image")
async def test_export_without_images(self, app: FastAPI, client: AsyncClient, tmpdir, project: Project) -> None:
project.dump = MagicMock()
os.makedirs(project.path, exist_ok=True)
with open(os.path.join(project.path, 'a'), 'w+') as f:
f.write('hello')
with open(os.path.join(project.path, "a"), "w+") as f:
f.write("hello")
os.makedirs(str(tmpdir / "IOS"))
with open(str(tmpdir / "IOS" / "test.image"), "w+") as f:
f.write("AAA")
topology = {
"topology": {
"nodes": [
{
"properties": {
"image": "test.image"
},
"node_type": "dynamips"
}
]
}
}
with open(os.path.join(project.path, "test.gns3"), 'w+') as f:
topology = {"topology": {"nodes": [{"properties": {"image": "test.image"}, "node_type": "dynamips"}]}}
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 = await client.get(app.url_path_for("export_project", project_id=project.id),
params={"include_images": "0"})
with patch(
"gns3server.compute.Dynamips.get_images_directory",
return_value=str(tmpdir / "IOS"),
):
response = await client.get(
app.url_path_for("export_project", project_id=project.id), params={"include_images": "0"}
)
assert response.status_code == status.HTTP_200_OK
assert response.headers['CONTENT-TYPE'] == 'application/gns3project'
assert response.headers['CONTENT-DISPOSITION'] == 'attachment; filename="{name}.gns3project"; filename*=UTF-8\'\'{name}.gns3project'.format(name=project.name)
with open(str(tmpdir / 'project.zip'), 'wb+') as f:
assert response.headers["CONTENT-TYPE"] == "application/gns3project"
assert response.headers[
"CONTENT-DISPOSITION"
] == "attachment; filename=\"{name}.gns3project\"; filename*=UTF-8''{name}.gns3project".format(
name=project.name
)
with open(str(tmpdir / "project.zip"), "wb+") as f:
f.write(response.content)
with zipfile_zstd.ZipFile(str(tmpdir / 'project.zip')) as myzip:
with zipfile_zstd.ZipFile(str(tmpdir / "project.zip")) as myzip:
with myzip.open("a") as myfile:
content = myfile.read()
assert content == b"hello"
# Image should not exported
with pytest.raises(KeyError):
myzip.getinfo("images/IOS/test.image")
@pytest.mark.parametrize(
"compression, compression_level, status_code",
(
("none", None, status.HTTP_200_OK),
("none", 4, status.HTTP_400_BAD_REQUEST),
("zip", None, status.HTTP_200_OK),
("zip", 1, status.HTTP_200_OK),
("zip", 12, status.HTTP_400_BAD_REQUEST),
("bzip2", None, status.HTTP_200_OK),
("bzip2", 1, status.HTTP_200_OK),
("bzip2", 13, status.HTTP_400_BAD_REQUEST),
("lzma", None, status.HTTP_200_OK),
("lzma", 1, status.HTTP_400_BAD_REQUEST),
("zstd", None, status.HTTP_200_OK),
("zstd", 12, status.HTTP_200_OK),
("zstd", 23, status.HTTP_400_BAD_REQUEST),
)
("none", None, status.HTTP_200_OK),
("none", 4, status.HTTP_400_BAD_REQUEST),
("zip", None, status.HTTP_200_OK),
("zip", 1, status.HTTP_200_OK),
("zip", 12, status.HTTP_400_BAD_REQUEST),
("bzip2", None, status.HTTP_200_OK),
("bzip2", 1, status.HTTP_200_OK),
("bzip2", 13, status.HTTP_400_BAD_REQUEST),
("lzma", None, status.HTTP_200_OK),
("lzma", 1, status.HTTP_400_BAD_REQUEST),
("zstd", None, status.HTTP_200_OK),
("zstd", 12, status.HTTP_200_OK),
("zstd", 23, status.HTTP_400_BAD_REQUEST),
),
)
async def test_export_compression(
self,
app: FastAPI,
client: AsyncClient,
tmpdir,
project: Project,
compression: str,
compression_level: int,
status_code: int
self,
app: FastAPI,
client: AsyncClient,
tmpdir,
project: Project,
compression: str,
compression_level: int,
status_code: int,
) -> None:
project.dump = MagicMock()
os.makedirs(project.path, exist_ok=True)
topology = {
"topology": {
"nodes": [
{
"node_type": "qemu"
}
]
}
}
with open(os.path.join(project.path, "test.gns3"), 'w+') as f:
topology = {"topology": {"nodes": [{"node_type": "qemu"}]}}
with open(os.path.join(project.path, "test.gns3"), "w+") as f:
json.dump(topology, f)
params = {"compression": compression}
if compression_level:
params["compression_level"] = compression_level
response = await client.get(app.url_path_for("export_project", project_id=project.id), params=params)
assert response.status_code == status_code
if response.status_code == status.HTTP_200_OK:
assert response.headers['CONTENT-TYPE'] == 'application/gns3project'
assert response.headers['CONTENT-DISPOSITION'] == 'attachment; filename="{name}.gns3project"; filename*=UTF-8\'\'{name}.gns3project'.format(name=project.name)
with open(str(tmpdir / 'project.zip'), 'wb+') as f:
assert response.headers["CONTENT-TYPE"] == "application/gns3project"
assert response.headers[
"CONTENT-DISPOSITION"
] == "attachment; filename=\"{name}.gns3project\"; filename*=UTF-8''{name}.gns3project".format(
name=project.name
)
with open(str(tmpdir / "project.zip"), "wb+") as f:
f.write(response.content)
with zipfile_zstd.ZipFile(str(tmpdir / 'project.zip')) as myzip:
with zipfile_zstd.ZipFile(str(tmpdir / "project.zip")) as myzip:
with myzip.open("project.gns3") as myfile:
myfile.read()
async def test_get_file(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
os.makedirs(project.path, exist_ok=True)
with open(os.path.join(project.path, 'hello'), 'w+') as f:
f.write('world')
with open(os.path.join(project.path, "hello"), "w+") as f:
f.write("world")
response = await client.get(app.url_path_for("get_file", project_id=project.id, file_path="hello"))
assert response.status_code == status.HTTP_200_OK
assert response.content == b"world"
response = await client.get(app.url_path_for("get_file", project_id=project.id, file_path="false"))
assert response.status_code == status.HTTP_404_NOT_FOUND
response = await client.get(app.url_path_for("get_file", project_id=project.id, file_path="../hello"))
assert response.status_code == status.HTTP_404_NOT_FOUND
async def test_get_project_gns3_file(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
response = await client.get(app.url_path_for("get_project_gns3_file", project_id=project.id))
@@ -451,7 +381,6 @@ class TestControllerProjectRoutes:
assert topology["name"] == "test"
assert "topology" in topology
async def test_get_project_gns3_file_raw_content(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
# the endpoint must serve the raw file content, without the project being opened
@@ -470,145 +399,142 @@ class TestControllerProjectRoutes:
assert response.status_code == status.HTTP_200_OK
assert response.json() == topology
async def test_get_project_gns3_file_project_not_found(self, app: FastAPI, client: AsyncClient) -> None:
response = await client.get(app.url_path_for("get_project_gns3_file", project_id=str(uuid.uuid4())))
assert response.status_code == status.HTTP_404_NOT_FOUND
async def test_get_file_forbidden_location(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
file_path = "foo/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd"
response = await client.get(app.url_path_for("get_file", project_id=project.id, file_path=file_path))
assert response.status_code == status.HTTP_403_FORBIDDEN
async def test_write_file(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
response = await client.post(app.url_path_for("write_file", project_id=project.id, file_path="hello"),
content=b"world")
response = await client.post(
app.url_path_for("write_file", project_id=project.id, file_path="hello"), content=b"world"
)
assert response.status_code == status.HTTP_204_NO_CONTENT
with open(os.path.join(project.path, "hello")) as f:
assert f.read() == "world"
response = await client.post(app.url_path_for("write_file", project_id=project.id, file_path="../hello"))
assert response.status_code == status.HTTP_404_NOT_FOUND
async def test_write_file_forbidden_location(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
file_path = "%2e%2e/hello"
response = await client.post(app.url_path_for("write_file", project_id=project.id, file_path=file_path),
content=b"world")
response = await client.post(
app.url_path_for("write_file", project_id=project.id, file_path=file_path), content=b"world"
)
assert response.status_code == status.HTTP_403_FORBIDDEN
async def test_write_and_get_file_with_leading_slashes_in_filename(
self,
app: FastAPI,
client: AsyncClient,
project: Project) -> None:
response = await client.post(app.url_path_for("write_file", project_id=project.id, file_path="//hello"),
content=b"world")
self, app: FastAPI, client: AsyncClient, project: Project
) -> None:
response = await client.post(
app.url_path_for("write_file", project_id=project.id, file_path="//hello"), content=b"world"
)
assert response.status_code == status.HTTP_403_FORBIDDEN
response = await client.get(app.url_path_for("get_file", project_id=project.id, file_path="//hello"))
assert response.status_code == status.HTTP_403_FORBIDDEN
async def test_import(self, app: FastAPI, client: AsyncClient, tmpdir, controller: Controller) -> None:
with zipfile_zstd.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"}')
with zipfile_zstd.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 = await client.post(app.url_path_for("import_project", project_id=project_id), content=f.read())
assert response.status_code == status.HTTP_201_CREATED
project = controller.get_project(project_id)
with open(os.path.join(project.path, "demo")) as f:
content = f.read()
assert content == "hello"
async def test_import_with_project_name(
self,
app: FastAPI,
client: AsyncClient,
tmpdir,
controller: Controller
self, app: FastAPI, client: AsyncClient, tmpdir, controller: Controller
) -> None:
with zipfile_zstd.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"}')
with zipfile_zstd.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 = await client.post(
app.url_path_for("import_project", project_id=project_id),
content=f.read(),
params={"name": "my-imported-project-name"}
params={"name": "my-imported-project-name"},
)
assert response.status_code == status.HTTP_201_CREATED
project = controller.get_project(project_id)
assert project.name == "my-imported-project-name"
async def test_duplicate(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
response = await client.post(app.url_path_for("duplicate_project", project_id=project.id), json={"name": "hello"})
response = await client.post(
app.url_path_for("duplicate_project", project_id=project.id), json={"name": "hello"}
)
assert response.status_code == status.HTTP_201_CREATED
assert response.json()["name"] == "hello"
async def test_lock_unlock(self, app: FastAPI, client: AsyncClient, project: Project, compute: Compute) -> None:
# add a drawing and node to the 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
"z": 0,
}
response = await client.post(app.url_path_for("create_drawing", project_id=project.id), json=params)
assert response.status_code == status.HTTP_201_CREATED
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
response = await client.post(app.url_path_for("create_node", project_id=project.id), json={
"name": "test",
"node_type": "vpcs",
"compute_id": "example.com",
"properties": {
"startup_script": "echo test"
}
})
response = await client.post(
app.url_path_for("create_node", project_id=project.id),
json={
"name": "test",
"node_type": "vpcs",
"compute_id": "example.com",
"properties": {"startup_script": "echo test"},
},
)
assert response.status_code == status.HTTP_201_CREATED
response = await client.post(app.url_path_for("lock_project", project_id=project.id))
assert response.status_code == status.HTTP_204_NO_CONTENT
for drawing in project.drawings.values():
assert drawing.locked is True
for node in project.nodes.values():
assert node.locked is True
response = await client.get(app.url_path_for("locked_project", project_id=project.id))
assert response.status_code == status.HTTP_200_OK
assert response.json() is True
response = await client.post(app.url_path_for("unlock_project", project_id=project.id))
assert response.status_code == status.HTTP_204_NO_CONTENT
for drawing in project.drawings.values():
assert drawing.locked is False
for node in project.nodes.values():