Merge branch '3.1' into fix/duplicate-device-configs-merge

This commit is contained in:
Guobin Yue authored and GitHub committed 2026-10-07 23:59:30 +08:00
commit 5238bd3b39
18 files changed
+190 -13

No files matched your search

+5
View File
@@ -161,3 +161,8 @@ class TestACLRoutes:
# the ACE should have been deleted after deleting the project
assert not await rbac_repo.get_ace_by_path(path)
async def test_get_endpoints(self, app: FastAPI, client: AsyncClient) -> None:
response = await client.get(app.url_path_for("endpoints"))
assert response.status_code == status.HTTP_200_OK
@@ -68,6 +68,31 @@ class TestComputeRoutes:
assert response.status_code == status.HTTP_200_OK
assert len(response.json()) > 0
async def test_compute_list_filter_by_name(self, app: FastAPI, client: AsyncClient) -> None:
for name, port in (("compute-a", 85), ("compute-b", 86)):
params = {
"name": name,
"protocol": "http",
"host": "localhost",
"port": port,
"user": "julien",
"password": "secure",
}
response = await client.post(app.url_path_for("create_compute"), json=params)
assert response.status_code == status.HTTP_201_CREATED
response = await client.get(app.url_path_for("get_computes"), params={"name": "compute-a"})
assert response.status_code == status.HTTP_200_OK
assert [c["name"] for c in response.json()] == ["compute-a"]
response = await client.get(app.url_path_for("get_computes"), params={"name": "COMPUTE-A"})
assert response.status_code == status.HTTP_200_OK
assert response.json() == []
response = await client.get(app.url_path_for("get_computes"))
assert len(response.json()) >= 2
async def test_compute_get(self, app: FastAPI, client: AsyncClient, test_compute: Compute) -> None:
response = await client.get(app.url_path_for("get_compute", compute_id=test_compute.compute_id))
@@ -70,3 +70,10 @@ class TestControllerRoutes:
response = await client.get(app.url_path_for("statistics"))
assert response.status_code == status.HTTP_200_OK
async def test_update_iou_license(self, app: FastAPI, client: AsyncClient) -> None:
license_settings = {"iourc_content": "[license]\ngns3vm = 1234567890abcdef;", "license_check": False}
response = await client.put(app.url_path_for("update_iou_license"), json=license_settings)
assert response.status_code == status.HTTP_200_OK
assert response.json() == license_settings
@@ -168,6 +168,21 @@ class TestImageRoutes:
assert response.status_code == status.HTTP_200_OK
assert len(response.json()) == 5 # 4 valid images uploaded before + 1 created
async def test_image_list_filter_by_name(self, app: FastAPI, client: AsyncClient, qcow2_image: str) -> None:
image_name = os.path.basename(qcow2_image)
response = await client.get(app.url_path_for("get_images"), params={"name": image_name})
assert response.status_code == status.HTTP_200_OK
assert [i["filename"] for i in response.json()] == [image_name]
response = await client.get(app.url_path_for("get_images"), params={"name": image_name.upper()})
assert response.status_code == status.HTTP_200_OK
assert response.json() == []
response = await client.get(app.url_path_for("get_images"), params={"name": image_name, "image_type": "iou"})
assert response.status_code == status.HTTP_200_OK
assert response.json() == []
async def test_image_get(self, app: FastAPI, client: AsyncClient, qcow2_image: str) -> None:
image_name = os.path.basename(qcow2_image)
+48
View File
@@ -156,6 +156,54 @@ class TestNodeRoutes:
else:
assert len(response.json()) == 0
@pytest.mark.parametrize(
"name, tags, expected_names",
(
(None, None, ["test", "test2"]),
("test", None, ["test"]),
("test2", None, ["test2"]),
("TEST", None, []),
("missing", None, []),
("test", ["tag1"], ["test"]),
("test", ["tag3"], []),
("test2", ["tag3", "tag4"], ["test2"]),
),
)
async def test_list_nodes_filter_by_name(
self,
app: FastAPI,
client: AsyncClient,
project: Project,
compute: Compute,
name: Optional[str],
tags: Optional[list],
expected_names: list,
) -> None:
response = MagicMock()
response.json = {"console": 2048}
compute.post = AsyncioMagicMock(return_value=response)
for node_name, node_tags in (("test", ["tag1", "tag2"]), ("test2", ["tag3", "tag4"])):
await client.post(
app.url_path_for("create_node", project_id=project.id),
json={
"name": node_name,
"node_type": "vpcs",
"compute_id": "example.com",
"tags": node_tags,
"properties": {"startup_script": "echo test"},
},
)
params = {}
if name is not None:
params["name"] = name
if tags is not None:
params["tags"] = tags
response = await client.get(app.url_path_for("get_nodes", project_id=project.id), params=params)
assert response.status_code == status.HTTP_200_OK
assert sorted(n["name"] for n in response.json()) == expected_names
async def test_get_node(self, app: FastAPI, client: AsyncClient, project: Project, compute: Compute) -> None:
response = MagicMock()
+21 -1
View File
@@ -164,6 +164,26 @@ class TestControllerProjectRoutes:
projects = response.json()
assert projects[0]["name"] == "test"
async def test_list_projects_filter_by_name(
self, app: FastAPI, client: AsyncClient, controller: Controller
) -> None:
for name in ("test", "other"):
params = {"name": name, "project_id": str(uuid.uuid4())}
response = await client.post(app.url_path_for("create_project"), json=params)
assert response.status_code == status.HTTP_201_CREATED
response = await client.get(app.url_path_for("get_projects"), params={"name": "test"})
assert response.status_code == status.HTTP_200_OK
assert [p["name"] for p in response.json()] == ["test"]
response = await client.get(app.url_path_for("get_projects"), params={"name": "TEST"})
assert response.status_code == status.HTTP_200_OK
assert response.json() == []
response = await client.get(app.url_path_for("get_projects"))
assert len(response.json()) == 2
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))
@@ -196,7 +216,7 @@ class TestControllerProjectRoutes:
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 response.status_code == status.HTTP_200_OK
assert mock.called
async def test_load_project(self, app: FastAPI, client: AsyncClient, project: Project, config) -> None:
@@ -72,7 +72,7 @@ class TestSnapshotRoutes:
response = await client.post(
app.url_path_for("restore_snapshot", project_id=project.id, snapshot_id=snapshot.id)
)
assert response.status_code == status.HTTP_201_CREATED
assert response.status_code == status.HTTP_200_OK
assert response.json()["name"] == project.name
async def test_create_snapshot(self, app: FastAPI, client: AsyncClient, project: Project) -> None:
@@ -20,6 +20,7 @@ import os
import unittest.mock
import uuid
from pathlib import Path
from typing import Optional
import pytest
from fastapi import FastAPI, status
@@ -89,6 +90,27 @@ class TestTemplateRoutes:
else:
assert len(response.json()) == 0
@pytest.mark.parametrize(
"name, tags, expected_names",
(
("VPCS_TEST", None, ["VPCS_TEST"]),
("vpcs_test", None, []),
("missing", None, []),
("VPCS_TEST", ["tag1"], ["VPCS_TEST"]),
("VPCS_TEST", ["tag42"], []),
),
)
async def test_template_list_filter_by_name(
self, app: FastAPI, client: AsyncClient, name: str, tags: Optional[list], expected_names: list
) -> None:
params = {"name": name}
if tags is not None:
params["tags"] = tags
response = await client.get(app.url_path_for("get_templates"), params=params)
assert response.status_code == status.HTTP_200_OK
assert [t["name"] for t in response.json()] == expected_names
async def test_template_get(self, app: FastAPI, client: AsyncClient) -> None:
template_id = str(uuid.uuid4())