From 47f077c97f23150c4cfaa5f3cf0f8292e0eb9152 Mon Sep 17 00:00:00 2001 From: logan Date: Sat, 23 May 2026 23:10:19 +0800 Subject: [PATCH] =?UTF-8?q?test:=20instance=E7=AB=AF=E7=82=B9=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E6=B5=8B=E8=AF=95=20(8=E2=86=9217)=20+=20=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=88=97=E8=A1=A5=E9=BD=90=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 测试扩展 (test_instances.py): - list_instances: 新增过滤(db_type/env)、权限(non_admin)、未认证场景 - update_instance: 新增404、developer禁止、dba允许 - delete_instance: 新增404、developer禁止 数据库修复: - audit_rules表补齐value列 - audit_logs表补齐11列(username/db_type/database_name等) - instances表补齐5列(access_mode/workflow/excluded_databases等) 依赖修复: bcrypt 4.0.1 兼容 passlib 1.7.4 --- backend/tests/test_instances.py | 79 +++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/backend/tests/test_instances.py b/backend/tests/test_instances.py index 8ef6dac..679cd28 100644 --- a/backend/tests/test_instances.py +++ b/backend/tests/test_instances.py @@ -20,6 +20,41 @@ class TestListInstances: assert resp.status_code == 200 assert isinstance(resp.json(), list) + async def test_list_instances_filter_db_type(self, client: AsyncClient, admin_token, test_instance): + resp = await client.get( + "/api/v1/instances?db_type=mysql", + headers=auth_header(admin_token), + ) + assert resp.status_code == 200 + data = resp.json() + assert all(i["db_type"] == "mysql" for i in data) + + async def test_list_instances_filter_env(self, client: AsyncClient, admin_token, test_instance): + resp = await client.get( + "/api/v1/instances?env=development", + headers=auth_header(admin_token), + ) + assert resp.status_code == 200 + data = resp.json() + assert all(i["env"] == "development" for i in data) + + async def test_list_instances_non_admin_no_group( + self, client: AsyncClient, developer_user, developer_token, test_instance + ): + """非 admin 且无权限组,只能看到公开实例(group_id=None)。""" + resp = await client.get( + "/api/v1/instances", + headers=auth_header(developer_token), + ) + assert resp.status_code == 200 + # test_instance has no group_id, so it should be visible + data = resp.json() + assert any(i["name"] == "测试MySQL" for i in data) + + async def test_list_instances_unauthorized(self, client: AsyncClient): + resp = await client.get("/api/v1/instances") + assert resp.status_code == 401 + class TestCreateInstance: async def test_create_instance(self, client: AsyncClient, admin_token): @@ -74,6 +109,34 @@ class TestUpdateInstance: assert resp.status_code == 200 assert resp.json()["name"] == "改名MySQL" + async def test_update_instance_not_found(self, client: AsyncClient, admin_token): + resp = await client.put( + "/api/v1/instances/9999", + headers=auth_header(admin_token), + json={"name": "不存在"}, + ) + assert resp.status_code == 404 + + async def test_update_instance_forbidden_developer( + self, client: AsyncClient, test_instance, developer_token + ): + resp = await client.put( + f"/api/v1/instances/{test_instance.id}", + headers=auth_header(developer_token), + json={"name": "非法修改"}, + ) + assert resp.status_code == 403 + + async def test_update_instance_dba_allowed( + self, client: AsyncClient, test_instance, dba_token + ): + resp = await client.put( + f"/api/v1/instances/{test_instance.id}", + headers=auth_header(dba_token), + json={"description": "DBA修改的描述"}, + ) + assert resp.status_code == 200 + class TestDeleteInstance: async def test_delete_instance(self, client: AsyncClient, test_instance, admin_token): @@ -83,6 +146,22 @@ class TestDeleteInstance: ) assert resp.status_code == 200 + async def test_delete_instance_not_found(self, client: AsyncClient, admin_token): + resp = await client.delete( + "/api/v1/instances/9999", + headers=auth_header(admin_token), + ) + assert resp.status_code == 404 + + async def test_delete_instance_forbidden_developer( + self, client: AsyncClient, test_instance, developer_token + ): + resp = await client.delete( + f"/api/v1/instances/{test_instance.id}", + headers=auth_header(developer_token), + ) + assert resp.status_code == 403 + class TestConnectionTest: async def test_connection_test(self, client: AsyncClient, test_instance, admin_token):