"""数据隔离测试 — 覆盖角色间数据可见性边界。 测试用例: - ISO-001: 业务员订单隔离(sales01 vs sales02) - ISO-002: 司机任务隔离(driver01 vs driver02) - ISO-003: 业务员客户隔离 - ISO-004: 管理员看全部数据 - ISO-005: 经理看全部数据 """ from __future__ import annotations import pytest @pytest.mark.p0 class TestOrderIsolation: """ISO-001: 业务员订单数据隔离。""" def test_salesman_only_see_own_orders(self, client, salesman_headers, salesman2_headers, make_order): """sales01 创建的订单, sales02 看不到。""" order = make_order(salesman_id=2) # sales01 # sales01 能看到 resp1 = client.get("/api/orders", headers=salesman_headers) ids1 = [o["order_id"] for o in resp1.json()["data"]["list"]] assert order.id in ids1 # sales02 看不到 resp2 = client.get("/api/orders", headers=salesman2_headers) ids2 = [o["order_id"] for o in resp2.json()["data"]["list"]] assert order.id not in ids2 def test_admin_see_all_orders(self, client, admin_headers, salesman_headers, make_order): """管理员能看到所有业务员的订单。""" order = make_order(salesman_id=2) resp = client.get("/api/orders", headers=admin_headers) ids = [o["order_id"] for o in resp.json()["data"]["list"]] assert order.id in ids def test_manager_see_all_orders(self, client, manager_headers, make_order): """经理能看到所有订单。""" order = make_order(salesman_id=2) resp = client.get("/api/orders", headers=manager_headers) ids = [o["order_id"] for o in resp.json()["data"]["list"]] assert order.id in ids @pytest.mark.p0 class TestTaskIsolation: """ISO-002: 司机任务数据隔离。""" def test_driver_only_see_own_tasks(self, client, driver_headers, driver2_headers, make_task): """driver01 的任务, driver02 看不到。""" task = make_task(driver_id=5) # driver01 # driver01 能看到 resp1 = client.get("/api/driver/tasks", headers=driver_headers) ids1 = [t["task_id"] for t in resp1.json()["data"]["list"]] assert task.id in ids1 # driver02 看不到 resp2 = client.get("/api/driver/tasks", headers=driver2_headers) ids2 = [t["task_id"] for t in resp2.json()["data"]["list"]] assert task.id not in ids2 def test_admin_see_all_tasks(self, client, admin_headers, make_task): """管理员能看到所有物流任务。""" task = make_task(driver_id=5) resp = client.get("/api/logistics/tasks", headers=admin_headers) assert resp.status_code == 200 @pytest.mark.p0 class TestCustomerIsolation: """ISO-003: 业务员客户数据隔离。""" def test_salesman_only_see_own_customers(self, client, salesman_headers, salesman2_headers, make_customer): """sales01 创建的客户, sales02 看不到。""" customer = make_customer(salesman_id=2) resp1 = client.get("/api/customers", headers=salesman_headers) ids1 = [c["customer_id"] for c in resp1.json()["data"]["list"]] assert customer.id in ids1 resp2 = client.get("/api/customers", headers=salesman2_headers) ids2 = [c["customer_id"] for c in resp2.json()["data"]["list"]] assert customer.id not in ids2 def test_admin_see_all_customers(self, client, admin_headers, make_customer): """管理员能看到所有客户。""" customer = make_customer(salesman_id=2) resp = client.get("/api/customers", headers=admin_headers) ids = [c["customer_id"] for c in resp.json()["data"]["list"]] assert customer.id in ids def test_manager_see_all_customers(self, client, manager_headers, make_customer): """经理能看到所有客户。""" customer = make_customer(salesman_id=2) resp = client.get("/api/customers", headers=manager_headers) ids = [c["customer_id"] for c in resp.json()["data"]["list"]] assert customer.id in ids @pytest.mark.p0 class TestOrderDetailIsolation: """订单详情字段级权限隔离。""" def test_salesman_detail_hides_finance(self, client, salesman_headers, make_order): """业务员看订单详情, 隐藏成本和利润字段。""" order = make_order(salesman_id=2) resp = client.get(f"/api/orders/{order.id}", headers=salesman_headers) data = resp.json()["data"] # 业务员不应看到成本价和利润率 assert data.get("cost_price_total") is None or data.get("cost_price_total") == 0 def test_manager_detail_shows_finance(self, client, manager_headers, make_order): """经理看订单详情, 显示成本和利润字段。""" order = make_order(salesman_id=2) resp = client.get(f"/api/orders/{order.id}", headers=manager_headers) data = resp.json()["data"] # 经理应能看到利润信息 assert "profit_total" in data or "profit_rate" in data def test_driver_detail_hides_finance(self, client, driver_headers, make_task): """司机看任务详情, 隐藏财务信息。""" task = make_task(driver_id=5) resp = client.get(f"/api/driver/tasks/{task.id}", headers=driver_headers) data = resp.json()["data"] # 司机不应看到价格信息 assert data.get("sale_price") is None assert data.get("cost_price") is None @pytest.mark.p0 class TestPermissionBoundary: """权限边界测试 — 各角色不能越权操作。""" def test_salesman_cannot_approve(self, client, salesman_headers, make_order): """业务员不能审批订单。""" order = make_order(order_status="pending_approve", salesman_id=2) resp = client.post(f"/api/orders/{order.id}/approve", headers=salesman_headers, json={ "approve_result": "pass", }) assert resp.status_code == 403 def test_salesman_cannot_create_logistics_task(self, client, salesman_headers, make_order): """业务员不能创建物流任务。""" order = make_order(order_status="approved", salesman_id=2) resp = client.post("/api/logistics/tasks", headers=salesman_headers, json={ "order_id": order.id, "driver_id": 5, "pickup_address": "工厂", "delivery_address": "仓库", }) assert resp.status_code == 403 def test_driver_cannot_approve(self, client, driver_headers, make_order): """司机不能审批订单。""" order = make_order(order_status="pending_approve") resp = client.post(f"/api/orders/{order.id}/approve", headers=driver_headers, json={ "approve_result": "pass", }) assert resp.status_code == 403 def test_driver_cannot_view_reports(self, client, driver_headers): """司机不能查看报表。""" resp = client.get("/api/reports/performance", headers=driver_headers) assert resp.status_code == 403 def test_salesman_cannot_manage_system(self, client, salesman_headers): """业务员不能访问系统管理。""" resp = client.get("/api/system/users", headers=salesman_headers) assert resp.status_code == 403 def test_manager_cannot_manage_users(self, client, manager_headers): """经理不能管理用户。""" resp = client.post("/api/system/users", headers=manager_headers, json={ "username": "test", "password": "test123", "role_id": 2, }) assert resp.status_code == 403