101 lines
5.2 KiB
Python
101 lines
5.2 KiB
Python
"""现场派车日历菜单迁移:仅现场角色可获得只读入口,保留管理员撤权。"""
|
|
from pathlib import Path
|
|
import re
|
|
import sqlite3
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
MIGRATION = ROOT / 'docs/sql/migrations/2026-10-30-mini-site-dispatch-calendar-menu.sql'
|
|
PERM = 'mini:pl:site-dispatch-calendar:list'
|
|
|
|
|
|
def database():
|
|
db = sqlite3.connect(':memory:')
|
|
db.create_function('UUID', 0, lambda: str(uuid4()))
|
|
db.create_function('NOW', 0, lambda: '2026-10-30 12:00:00')
|
|
common = "tenant_no TEXT DEFAULT 'shanxia2.0', order_num INT, remark TEXT, create_by TEXT, create_dept_id TEXT, create_time TEXT, update_time TEXT, del_flag INT DEFAULT 0"
|
|
db.execute(f"CREATE TABLE sys_menu (id TEXT PRIMARY KEY, menu_name TEXT, parent_id TEXT DEFAULT '0', menu_type TEXT, path TEXT, component TEXT, perms TEXT, is_frame INT, visible TEXT DEFAULT '1', status TEXT DEFAULT '1', {common})")
|
|
db.execute(f"CREATE TABLE sys_role (id TEXT PRIMARY KEY, role_name TEXT, status TEXT DEFAULT '1', {common})")
|
|
db.execute(f"CREATE TABLE sys_role_menu (id TEXT PRIMARY KEY, role_id TEXT, menu_id TEXT, {common})")
|
|
db.execute("INSERT INTO sys_menu (id,path) VALUES ('mini-root','/mini')")
|
|
db.execute("INSERT INTO sys_menu (id,parent_id,path) VALUES ('MINI_PL_ROOT','mini-root','/mini/pl')")
|
|
for role_id, name, tenant, status, deleted in [
|
|
('site', '现场人员', 'shanxia2.0', '1', 0),
|
|
('site2', '现场人员', 'shanxia2.0', '1', 0),
|
|
('driver', '司机', 'shanxia2.0', '1', 0),
|
|
('admin', '管理员', 'shanxia2.0', '1', 0),
|
|
('similar', '现场人员管理', 'shanxia2.0', '1', 0),
|
|
('foreign', '现场人员', 'other', '1', 0),
|
|
('disabled', '现场人员', 'shanxia2.0', '0', 0),
|
|
('deleted', '现场人员', 'shanxia2.0', '1', 1),
|
|
]:
|
|
db.execute('INSERT INTO sys_role (id,role_name,tenant_no,status,del_flag) VALUES (?,?,?,?,?)',
|
|
(role_id, name, tenant, status, deleted))
|
|
return db
|
|
|
|
|
|
def migrate(db):
|
|
assert MIGRATION.exists(), '现场派车日历迁移尚未创建'
|
|
for sql in re.findall(r'INSERT INTO sys_(?:menu|role_menu)\s*\(.*?;', MIGRATION.read_text(), re.S):
|
|
db.execute(sql)
|
|
|
|
|
|
def test_only_active_exact_site_roles_get_leaf_and_ancestors_once():
|
|
with database() as db:
|
|
migrate(db)
|
|
migrate(db)
|
|
leaf = db.execute('SELECT id FROM sys_menu WHERE perms=?', (PERM,)).fetchone()[0]
|
|
assert set(db.execute('SELECT role_id,menu_id FROM sys_role_menu')) == {
|
|
(role, menu) for role in ['site', 'site2'] for menu in [leaf, 'MINI_PL_ROOT', 'mini-root']
|
|
}
|
|
assert db.execute('SELECT COUNT(*) FROM sys_role_menu').fetchone()[0] == 6
|
|
assert list(db.execute('SELECT perms FROM sys_menu WHERE perms IS NOT NULL')) == [(PERM,)]
|
|
|
|
|
|
@pytest.mark.parametrize('part', ['leaf', 'MINI_PL_ROOT', 'mini-root'])
|
|
def test_deleted_grants_are_never_restored(part):
|
|
with database() as db:
|
|
migrate(db)
|
|
if part == 'leaf':
|
|
part = db.execute('SELECT id FROM sys_menu WHERE perms=?', (PERM,)).fetchone()[0]
|
|
db.execute('UPDATE sys_role_menu SET del_flag=1 WHERE role_id=? AND menu_id=?', ('site', part))
|
|
migrate(db)
|
|
assert list(db.execute('SELECT del_flag FROM sys_role_menu WHERE role_id=? AND menu_id=?', ('site', part))) == [(1,)]
|
|
|
|
|
|
@pytest.mark.parametrize('field,value', [('del_flag', 1), ('status', '0'), ('visible', '0')])
|
|
@pytest.mark.parametrize('part', ['leaf', 'MINI_PL_ROOT', 'mini-root'])
|
|
def test_inactive_menus_do_not_create_new_grants(field, value, part):
|
|
with database() as db:
|
|
migrate(db)
|
|
if part == 'leaf':
|
|
part = db.execute('SELECT id FROM sys_menu WHERE perms=?', (PERM,)).fetchone()[0]
|
|
db.execute(f'UPDATE sys_menu SET {field}=? WHERE id=?', (value, part))
|
|
db.execute("INSERT INTO sys_role (id,role_name) VALUES ('new-site','现场人员')")
|
|
migrate(db)
|
|
assert db.execute("SELECT COUNT(*) FROM sys_role_menu WHERE role_id='new-site'").fetchone()[0] == 0
|
|
assert db.execute('SELECT COUNT(*) FROM sys_menu WHERE perms=?', (PERM,)).fetchone()[0] == 1
|
|
|
|
|
|
@pytest.mark.parametrize('change', [
|
|
"UPDATE sys_menu SET path='/web' WHERE id='mini-root'",
|
|
"UPDATE sys_menu SET parent_id='not-root' WHERE id='mini-root'",
|
|
"UPDATE sys_menu SET tenant_no='other'",
|
|
"UPDATE sys_menu SET del_flag=1 WHERE id='MINI_PL_ROOT'",
|
|
])
|
|
def test_wrong_tree_or_tenant_does_not_create_menu(change):
|
|
with database() as db:
|
|
db.execute(change)
|
|
migrate(db)
|
|
assert db.execute('SELECT COUNT(*) FROM sys_menu WHERE perms=?', (PERM,)).fetchone()[0] == 0
|
|
assert db.execute('SELECT COUNT(*) FROM sys_role_menu').fetchone()[0] == 0
|
|
|
|
|
|
def test_mini_entry_uses_dedicated_permission_and_h5_path():
|
|
menu = (ROOT / 'miniprogram/config/workbench-menus.js').read_text()
|
|
route = (ROOT / 'miniprogram/config/api.js').read_text()
|
|
assert re.search(r"name: '现场派车日历'.*?code: 'pl-site-dispatch-calendar-webview'.*?perms: '" + PERM + "'", menu, re.S)
|
|
assert "'pl-site-dispatch-calendar-webview': PAGE_PATHS.mpWebview + '?path=' + encodeURIComponent('/m/pl/site-dispatch-calendar')" in route
|