Files
danyang-match/tests/e2e/sql/seed_e2e_operators.sql
WorkBuddy 730dddde30 test(e2e): Phase 23B — rebuild E2E infrastructure; fix 6 real prod defects it exposed
Phase 23 closed as PARTIAL: fake coverage was gone, but the E2E layer itself
was still empty — no conftest.py anywhere, ~15 fixtures that never existed,
6 files crashing at import on os.environ["E2E_PASSWORD"], and CI never ran E2E.
STATUS's "10 E2E files / ~80+ cases ✅" described files that had never executed.

Infrastructure delivered:
- tests/e2e/conftest.py: ApiClient (trust_env=False — a host http_proxy turns
  localhost calls into 502), operator_token(username) / new_user / admin_token
  fixtures, and a session probe that calls pytest.exit(4) when the stack is
  unreachable. NOT skip: skip would launder "did not run" into "passed".
- pytest.ini, tests/e2e/requirements.txt, and tests/e2e/sql/
  seed_e2e_operators.sql — migrations contain NO operator seed at all, so a
  fresh database has zero logins; the seed creates 6 e2e accounts with role
  bindings, idempotent, password injected via `psql -v pwd`.
- CI job `e2e`: compose up -> poll /health/live (timeout = fail) -> seed ->
  pytest -> always teardown. Gate D-23-D is now closed.
- 8 E2E files migrated off import-time env reads; tautological assertions
  (`x == t or not x`), a counselor token standing in for content_editor, and a
  bare `status_code == 200` claiming to prove INV-020 were replaced with real
  permission/behavior assertions.

Six real production defects found only by running against real PostgreSQL
(H2 has zero coverage for all of them):
- D-23B-A (Critical): stale V042__add_appointment_operator_register_permission.sql
  left in target/classes; src had replaced it with V042__add_service_location_
  announcements.sql. Packing without clean put two V042 in the jar -> Flyway
  "Found more than one migration with version 042" -> app would not start.
  Guard added: testBuildOutputHasNoDuplicateMigrationVersions scans build output
  (src is clean, so only this catches it).
- D-23B-B (High): non-UUID path variable reached the DB -> 500 + leaked
  `invalid input syntax for type uuid`. Now rejected at the controller.
- D-23B-C (High): 6 E2E files raised KeyError at import -> never collected.
- D-23B-E (Critical): permissions = 48, role_permissions for super_admin = 18,
  matchmaker = 0. V015's "grant all to super_admin" was a point-in-time snapshot;
  the 30 permissions added later were never granted. On a fresh stack an admin
  cannot create a service station and matchmakers can do nothing. V044 restores
  super_admin to its documented definition (not an expansion); the matchmaker
  permission set needs a product decision and is left as a residual.
- D-23B-I (Medium): IllegalArgumentException (e.g. invalid activity type) was
  unmapped -> 500. Now BAD_REQUEST.
- D-23B-J (High): `operator does not exist: uuid = character varying` — Java
  ids are String, columns are uuid, PostgreSQL does not implicitly cast in
  comparisons. Fixed at the source with JDBC `stringtype=unspecified` (docker
  profile); production datasource comes from deploy env and needs the same.

One judgement retracted: an initial read suggested service_appointment.register
was missing. It is not — the endpoint uses service.assisted_registration, seeded
in V029, and the code deliberately avoids a duplicate permission. Nothing was
changed on that basis.

Verification: 33 E2E passed against a live stack; unreachable stack and a
missing operator password both exit 4 (never skip/pass); backend regression
656 / 0 failures / 0 errors / 3 skipped (baseline 655, +1 guard, negatively
validated by injecting a duplicate V042 -> exactly one test turned red).
2026-09-18 13:50:19 +08:00

42 lines
2.6 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================
-- E2E 测试运营账号 seed(幂等,CI 与本机通用)
--
-- 为什么需要:
-- 迁移里只有 roles / permissions 的种子,**没有任何 operator 账号**。
-- 全新库起栈后一个运营账号都没有,E2E 无法登录,operator 侧链路
-- (权限矩阵、代登记、审核队列)全部无法验证。本脚本把"可自举"
-- 做成基建的一部分,而不是依赖某台机器上手工创建的遗留账号。
--
-- 用法(密码由环境变量注入,不入库明文、不进版本库):
-- psql -v pwd="$E2E_OPERATOR_PASSWORD" -f seed_e2e_operators.sql
--
-- 幂等:全部走 ON CONFLICT DO NOTHING,可重复执行。
-- ============================================================
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- 账号:密码相同($pwd),角色不同,用于验证权限隔离(INV-012/013/019 等)
INSERT INTO operators (id, name, username, password_hash, status) VALUES
('e2e00000-0000-0000-0000-000000000001', 'E2E 超级管理员', 'e2e_admin', crypt(:'pwd', gen_salt('bf', 8)), 'active'),
('e2e00000-0000-0000-0000-000000000002', 'E2E 平台管理员', 'e2e_platform', crypt(:'pwd', gen_salt('bf', 8)), 'active'),
('e2e00000-0000-0000-0000-000000000003', 'E2E 婚恋咨询师', 'e2e_counselor', crypt(:'pwd', gen_salt('bf', 8)), 'active'),
('e2e00000-0000-0000-0000-000000000004', 'E2E 服务站运营', 'e2e_station', crypt(:'pwd', gen_salt('bf', 8)), 'active'),
('e2e00000-0000-0000-0000-000000000005', 'E2E 公益红娘', 'e2e_matchmaker', crypt(:'pwd', gen_salt('bf', 8)), 'active'),
('e2e00000-0000-0000-0000-000000000006', 'E2E 内容编辑', 'e2e_content', crypt(:'pwd', gen_salt('bf', 8)), 'active')
ON CONFLICT (username) DO NOTHING;
-- 角色绑定(role id 取自 V015 seed)
-- super_admin / platform_admin
INSERT INTO operator_roles (operator_id, role_id) VALUES
('e2e00000-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000001'),
('e2e00000-0000-0000-0000-000000000002', '00000000-0000-0000-0000-000000000002'),
-- counselor
('e2e00000-0000-0000-0000-000000000003', '00000000-0000-0000-0000-000000000011'),
-- service_station_operator
('e2e00000-0000-0000-0000-000000000004', '00000000-0000-0000-0000-000000000010'),
-- matchmaker
('e2e00000-0000-0000-0000-000000000005', '00000000-0000-0000-0000-000000000005'),
-- content_editor
('e2e00000-0000-0000-0000-000000000006', '00000000-0000-0000-0000-000000000013')
ON CONFLICT (operator_id, role_id) DO NOTHING;