175 lines
7.5 KiB
Python
175 lines
7.5 KiB
Python
"""数据隔离测试 — 覆盖角色间数据可见性边界。
|
||
|
||
测试用例:
|
||
- 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
|