mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
The ui suite has never gotten past globalSetup on stage. It logs in as five roles, and four of them are password users that only ever existed because run_e2e.sh and CircleCI piped fixtures/seed.sql into a database they had direct access to. The packaged e2e image has no such access, so on stage only the master-key admin could log in; the second role sat on /ui/login until waitForURL hit its 30s timeout and the whole run died before a single test. Confirmed against the stage gateway: POST /login as admin returns 303, as adminviewer@test.local returns 401, and /user/info 404s for every seeded id. Create the same budget, organization, users, teams and keys through the management endpoints in globalSetup instead, so the suite seeds whatever deployment it can reach rather than whatever database it can open. seed.sql is gone and the psql steps go with it; the API path is also the more faithful fixture, since seed.sql hand-wrote team rows no product code path produces (populated admins/members arrays, unhashed key tokens). Two behaviors the seeder has to work around, both verified live: /team/new auto-adds the caller as an admin, which would have made the proxy admin a member of the team the suite needs it to be a stranger to, so that membership is removed after each team; and /team/delete and /user/delete are all-or-nothing, so one unknown id in a batch deletes nothing, which means each id gets its own request for the cleanup to survive a partial state. Verified end to end against the stage gateway: seeding runs in ~6s, all five role logins return 303, the four teams come back with exactly their seeded members and no stray admin, all five keys resolve to the right owner and team, and re-running after deleting a seeded team and key restores both.
68 lines
3.5 KiB
TypeScript
68 lines
3.5 KiB
TypeScript
import * as path from "path";
|
|
|
|
export const UI_BASE_URL = (
|
|
process.env.E2E_UI_BASE_URL ||
|
|
process.env.LITELLM_PROXY_URL ||
|
|
"http://localhost:4000"
|
|
).replace(/\/+$/, "");
|
|
|
|
// Directory every artifact this suite writes must land in: storage states,
|
|
// failure screenshots, playwright output. A local `./run_e2e.sh` run has a
|
|
// writable cwd, so it keeps the historical behavior of writing beside the
|
|
// suite. In the packaged e2e image the suite ships on a read-only filesystem
|
|
// (/app/e2e/ui), so bare relative paths raise EROFS/ENOENT and the run dies in
|
|
// globalSetup before a single test executes. Point E2E_UI_ARTIFACT_DIR at a
|
|
// writable path (the image runner already exports TMPDIR) to relocate them.
|
|
export const ARTIFACT_DIR = process.env.E2E_UI_ARTIFACT_DIR || ".";
|
|
|
|
const storagePath = (name: string): string => path.join(ARTIFACT_DIR, name);
|
|
|
|
// Storage state paths for each role
|
|
export const ADMIN_STORAGE_PATH = storagePath("admin.storageState.json");
|
|
export const ADMIN_VIEWER_STORAGE_PATH = storagePath("adminViewer.storageState.json");
|
|
export const INTERNAL_USER_STORAGE_PATH = storagePath("internalUser.storageState.json");
|
|
export const INTERNAL_VIEWER_STORAGE_PATH = storagePath("internalViewer.storageState.json");
|
|
export const TEAM_ADMIN_STORAGE_PATH = storagePath("teamAdmin.storageState.json");
|
|
|
|
// Seeded user identities (match fixtures/seed.ts)
|
|
export const E2E_PROXY_ADMIN_USER_ID = "e2e-proxy-admin";
|
|
export const E2E_PROXY_ADMIN_EMAIL = "admin@test.local";
|
|
export const E2E_ADMIN_VIEWER_USER_ID = "e2e-admin-viewer";
|
|
export const E2E_ADMIN_VIEWER_EMAIL = "adminviewer@test.local";
|
|
export const E2E_INTERNAL_USER_ID = "e2e-internal-user";
|
|
export const E2E_INTERNAL_USER_EMAIL = "internal@test.local";
|
|
export const E2E_INTERNAL_VIEWER_USER_ID = "e2e-internal-viewer";
|
|
export const E2E_INTERNAL_VIEWER_EMAIL = "viewer@test.local";
|
|
export const E2E_TEAM_ADMIN_USER_ID = "e2e-team-admin";
|
|
export const E2E_TEAM_ADMIN_EMAIL = "teamadmin@test.local";
|
|
export const E2E_INVITABLE_USER_ID = "e2e-invitable-user";
|
|
export const E2E_INVITABLE_USER_EMAIL = "invitable@test.local";
|
|
export const E2E_INTERNAL_NOTEAM_USER_ID = "e2e-internal-noteam";
|
|
export const E2E_INTERNAL_NOTEAM_EMAIL = "noteam@test.local";
|
|
export const E2E_INVITABLE_BY_TEAM_ADMIN_USER_ID = "e2e-invitable-by-team-admin";
|
|
export const E2E_INVITABLE_BY_TEAM_ADMIN_EMAIL = "invitable-team@test.local";
|
|
export const E2E_REMOVABLE_MEMBER_USER_ID = "e2e-removable-member";
|
|
export const E2E_REMOVABLE_MEMBER_EMAIL = "removable@test.local";
|
|
export const E2E_USER_PASSWORD = "test";
|
|
|
|
// Organization and its budget (match fixtures/seed.ts)
|
|
export const E2E_ORG_ID = "e2e-org-main";
|
|
export const E2E_ORG_ALIAS = "E2E Organization";
|
|
export const E2E_ORG_BUDGET_ID = "e2e-budget-org";
|
|
|
|
// Key aliases for seeded test keys (match fixtures/seed.ts)
|
|
export const E2E_UPDATE_LIMITS_KEY_ALIAS = "e2eUpdateLimitsKey";
|
|
export const E2E_DELETE_KEY_ALIAS = "e2eDeleteKey";
|
|
export const E2E_REGENERATE_KEY_ALIAS = "e2eRegenerateKey";
|
|
export const E2E_INTERNAL_USER_KEY_ALIAS = "e2eInternalUserKey";
|
|
export const E2E_VIEWER_KEY_ALIAS = "e2eViewerKey";
|
|
|
|
// Team identifiers (match fixtures/seed.ts)
|
|
export const E2E_TEAM_CRUD_ID = "e2e-team-crud";
|
|
export const E2E_TEAM_CRUD_ALIAS = "E2E Team CRUD";
|
|
export const E2E_TEAM_DELETE_ID = "e2e-team-delete";
|
|
export const E2E_TEAM_DELETE_ALIAS = "E2E Team Delete";
|
|
export const E2E_TEAM_ORG_ID = "e2e-team-org";
|
|
export const E2E_TEAM_ORG_ALIAS = "E2E Team In Org";
|
|
export const E2E_TEAM_NO_ADMIN_ID = "e2e-team-no-admin";
|
|
export const E2E_TEAM_NO_ADMIN_ALIAS = "E2E Team No Admin";
|