@fuzdev/fuz_app 0.133.0 → 0.135.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +91 -9
- package/dist/actions/register_action_ws.d.ts +23 -3
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +57 -37
- package/dist/actions/transports.d.ts +23 -0
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +23 -0
- package/dist/actions/transports_ws_backend.d.ts +132 -9
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +236 -33
- package/dist/actions/ws_endpoint_spec.d.ts +9 -0
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/actions/ws_outbound_writer.d.ts +206 -0
- package/dist/actions/ws_outbound_writer.d.ts.map +1 -0
- package/dist/actions/ws_outbound_writer.js +431 -0
- package/dist/auth/CLAUDE.md +2 -2
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +3 -1
- package/dist/auth/cell_actions.js +1 -1
- package/dist/auth/role_schema.d.ts +14 -3
- package/dist/auth/role_schema.d.ts.map +1 -1
- package/dist/auth/role_schema.js +14 -2
- package/dist/db/CLAUDE.md +10 -7
- package/dist/db/create_db.d.ts +8 -6
- package/dist/db/create_db.d.ts.map +1 -1
- package/dist/db/create_db.js +11 -10
- package/dist/db/db.d.ts +9 -7
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +5 -4
- package/dist/db/db_pglet.d.ts +43 -0
- package/dist/db/db_pglet.d.ts.map +1 -0
- package/dist/db/db_pglet.js +55 -0
- package/dist/db/migrate.d.ts +1 -1
- package/dist/db/migrate.js +2 -2
- package/dist/http/CLAUDE.md +2 -1
- package/dist/http/body_limit.d.ts +61 -0
- package/dist/http/body_limit.d.ts.map +1 -0
- package/dist/http/body_limit.js +87 -0
- package/dist/http/db_routes.js +2 -2
- package/dist/http/error_schemas.d.ts +2 -0
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +2 -0
- package/dist/realtime/outbound_budget.d.ts +91 -0
- package/dist/realtime/outbound_budget.d.ts.map +1 -0
- package/dist/realtime/outbound_budget.js +108 -0
- package/dist/realtime/sse.d.ts +36 -3
- package/dist/realtime/sse.d.ts.map +1 -1
- package/dist/realtime/sse.js +58 -6
- package/dist/realtime/sse_constants.d.ts +12 -0
- package/dist/realtime/sse_constants.d.ts.map +1 -1
- package/dist/realtime/sse_constants.js +12 -0
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +3 -6
- package/dist/testing/CLAUDE.md +87 -28
- package/dist/testing/admin_integration.js +1 -1
- package/dist/testing/app_server.d.ts +5 -5
- package/dist/testing/app_server.d.ts.map +1 -1
- package/dist/testing/app_server.js +21 -20
- package/dist/testing/audit_completeness.d.ts +1 -1
- package/dist/testing/audit_completeness.js +1 -1
- package/dist/testing/audit_drift_guard.d.ts +1 -1
- package/dist/testing/audit_drift_guard.js +1 -1
- package/dist/testing/cross_backend/body_size_smuggling.d.ts +9 -9
- package/dist/testing/cross_backend/body_size_smuggling.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size_smuggling.js +110 -60
- package/dist/testing/cross_backend/capabilities.d.ts +18 -15
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +1 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts +5 -5
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +6 -6
- package/dist/testing/cross_backend/in_process_setup.d.ts +2 -2
- package/dist/testing/cross_backend/in_process_setup.js +3 -3
- package/dist/testing/cross_backend/role_grant_role_grammar.d.ts +6 -0
- package/dist/testing/cross_backend/role_grant_role_grammar.d.ts.map +1 -0
- package/dist/testing/cross_backend/role_grant_role_grammar.js +117 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +2 -3
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +2 -3
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +1 -1
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +8 -4
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +84 -4
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +102 -3
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +2 -2
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +9 -7
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts +29 -0
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_outbound_overflow.js +211 -0
- package/dist/testing/db.d.ts +49 -60
- package/dist/testing/db.d.ts.map +1 -1
- package/dist/testing/db.js +104 -101
- package/dist/testing/integration.js +1 -1
- package/dist/testing/rate_limiting.d.ts +2 -1
- package/dist/testing/rate_limiting.d.ts.map +1 -1
- package/dist/testing/rate_limiting.js +2 -2
- package/dist/testing/schema_introspect.d.ts +10 -2
- package/dist/testing/schema_introspect.d.ts.map +1 -1
- package/dist/testing/schema_introspect.js +15 -7
- package/dist/testing/sse_round_trip.d.ts +1 -1
- package/dist/testing/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/sse_round_trip.js +2 -2
- package/dist/testing/stubs.js +1 -1
- package/dist/testing/transports/ws_transport.d.ts +4 -2
- package/dist/testing/transports/ws_transport.d.ts.map +1 -1
- package/dist/testing/transports/ws_transport.js +2 -1
- package/dist/testing/ws_round_trip.d.ts +32 -2
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +26 -4
- package/package.json +6 -1
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -116,24 +116,23 @@ Factory builders for parameterized DB tests. Consumer projects pass their
|
|
|
116
116
|
`init_schema` callback (which calls `run_migrations(db, [auth_migration_ns, ...app_migrations])`);
|
|
117
117
|
factories accept any migration namespace set.
|
|
118
118
|
|
|
119
|
-
- `IS_CI` — `process.env.CI === 'true'`.
|
|
120
119
|
- `DbFactory` — `{name, create, close, skip, skip_reason?}`.
|
|
121
|
-
- `
|
|
122
|
-
- `
|
|
123
|
-
- `
|
|
124
|
-
- `
|
|
120
|
+
- `reset_public_schema(db)` — `DROP SCHEMA public CASCADE; CREATE SCHEMA public`, in plain SQL, so it resets every driver. Every factory calls it per `create()`, so `init_schema` only migrates. Drift-proof — no drop list to maintain.
|
|
121
|
+
- `create_default_db_factory(init_schema)` — the default in-memory factory: pglet-wasm, or the builder `set_default_db_factory` installed before it was built. What fuz_app's own helpers fall back to (`create_test_app_server`, `describe_rate_limiting_tests`, `describe_sse_route_tests`).
|
|
122
|
+
- `create_pglet_wasm_factory(init_schema)` / `create_pglite_factory(init_schema)` — pin pglet-wasm (`@fuzdev/pglet-wasm`, created with `PGLET_COERCION`) or PGlite; each needs its optional peer installed; `skip: false`. See WASM caching below.
|
|
123
|
+
- `set_default_db_factory(create_factory | null)` — install a `DbFactoryBuilder` for `create_default_db_factory`, so suites written against the default run on another driver without being edited (`create_pglite_factory` to run them on PGlite); returns the builder it replaced, so a caller can put it back. Install from a `db`-project `setupFiles` entry, before any factory is built (../../../docs/testing.md §Switching the default driver). Injected rather than selected here: a driver it can wrap may live in test-side code this shipped module can't import (fuz_app's `pglet-server`). fuz_app's own switch is `src/test/db_default.ts` (`FUZ_TEST_DB_DEFAULT`).
|
|
124
|
+
- `create_pg_factory(init_schema, test_url?)` — PostgreSQL; `skip: true` when `test_url` missing. Each `create()` opens a pool and resets the `public` schema before `init_schema`, like every other factory, so a persistent test database carries no stale DDL; a missing database (`3D000`) gets a `createdb` hint. Pool reused + cleaned up across `create()` calls.
|
|
125
125
|
- `auth_truncate_tables` — `['invite', 'api_token', 'auth_session', 'role_grant', 'role_grant_offer', 'actor', 'account']` in FK-safe order. Excludes `audit_log` — unit DB tests don't need to truncate it.
|
|
126
126
|
- `auth_integration_truncate_tables` — `auth_truncate_tables + ['audit_log']` for integration suites that exercise the audit path.
|
|
127
|
-
- `drop_auth_schema(db)` — `DROP SCHEMA public CASCADE; CREATE SCHEMA public`; call at the top of `init_schema` on persistent pg databases that may hold stale DDL from previous fuz_app versions. Drift-proof full-schema reset (despite the name, not auth-scoped) — same mechanism as `reset_pglite`.
|
|
128
127
|
- `create_describe_db(factories, truncate_tables)` — returns `describe_db(name, fn)` running `fn(get_db)` once per factory inside a `describe` with shared `beforeAll(create)` + `beforeEach(TRUNCATE)` + `afterAll(close)`. Skipped factories use `describe.skip`.
|
|
129
128
|
- `log_db_factory_status(factories)` — console summary of enabled / skipped factories.
|
|
130
129
|
- `assert_columns_match_live(db, table, columns)` — the named-projection drift guard: asserts a `*_COLUMNS` const (`ACCOUNT_COLUMNS`, `CELL_COLUMNS`, a consumer's own) names exactly the live `public`-schema columns of `table`, via `query_public_columns(db, {table})`. Per module, or iterated from a table → const registry (fuz_app's own: `src/test/db/column_projections.db.test.ts`).
|
|
131
130
|
|
|
132
|
-
**
|
|
133
|
-
instance in a module-level
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
reset. The `db` vitest project (opted into by the `.db.test.ts` suffix) runs
|
|
131
|
+
**WASM caching.** `create_pglite_factory` and `create_pglet_wasm_factory` each
|
|
132
|
+
share a single instance of their driver, held in a module-level promise, across the
|
|
133
|
+
factories they build. Every `create()` calls `DROP SCHEMA public CASCADE` and
|
|
134
|
+
re-runs its `init_schema` instead of paying the WASM cold start again, so suites
|
|
135
|
+
share state until the next reset. The `db` vitest project (opted into by the `.db.test.ts` suffix) runs
|
|
137
136
|
with `isolate: false` + `fileParallelism: false` to amortize WASM boot across
|
|
138
137
|
every DB test file — which also makes that one instance the whole run's; a
|
|
139
138
|
project that isolates its files gets one per worker instead.
|
|
@@ -152,7 +151,7 @@ Key module-scope values:
|
|
|
152
151
|
- `stub_password_deps` — `PasswordHashDeps` hashing via `stub_hash_${password}` and verifying by equality. Deterministic, no Argon2 cost — use for every test not specifically exercising password hashing.
|
|
153
152
|
- `create_loopback_app_server_options()` — the loopback `create_app_server` options an in-process test server takes (`localhost` origins, the loopback proxy trusted, an empty env schema), fresh per call; `create_test_app` and `create_test_app_for_bootstrap` spread it under their own defaults (`rate_limiters: 'disabled_for_testing'`, `await_pending_effects: true`).
|
|
154
153
|
- `TEST_COOKIE_SECRET` — 64-hex-char deterministic cookie secret. Produces a valid `Keyring` via `create_validated_keyring`. Never used in production — the stub guard plus fixed value is the contract.
|
|
155
|
-
- `
|
|
154
|
+
- `fallback_db_factory` — module-level auth-only default factory (`create_default_db_factory`) `create_test_app_server` uses when no `db` is passed, reusing its driver's WASM cache. When `migration_namespaces` is supplied, a memoized sibling factory (keyed by namespace set) migrating `[auth_migration_ns, ...migration_namespaces]` is used instead — same shared WASM, extra tables.
|
|
156
155
|
|
|
157
156
|
Two helpers share the "insert account + actor + roles + API token + session +
|
|
158
157
|
cookie" flow, split by intent:
|
|
@@ -170,7 +169,7 @@ pre-keeper, lock unflipped), use `create_test_app_for_bootstrap` — pair with
|
|
|
170
169
|
Types:
|
|
171
170
|
|
|
172
171
|
- `TestAppServer extends AppBackend` — adds `account`, `actor`, `api_token`, `session_cookie`, `keyring`, `cleanup()`.
|
|
173
|
-
- `TestAppServerOptions` — `session_options` (required), optional `db`, `db_type`, `migration_namespaces`, `password`, `username`, `password_value`, `roles`, `audit_factory`. `migration_namespaces` runs extra namespaces after auth in the auto-created
|
|
172
|
+
- `TestAppServerOptions` — `session_options` (required), optional `db`, `db_type`, `migration_namespaces`, `password`, `username`, `password_value`, `roles`, `audit_factory`. `migration_namespaces` runs extra namespaces after auth in the auto-created in-memory database (mirrors `create_app_backend`); mutually exclusive with `db` (caller-migrated) — passing both throws. The optional `audit_factory` defaults to `default_audit_factory` (no-listener `create_audit_emitter` over the test backend's `{db, log}`); pass a custom factory to compose `on_audit_event` / `audit_log_config`, instrument `emit` with `emit_decorator`, or otherwise replace the emitter. Mirrors `CreateAppBackendOptions` end-to-end — the previous `on_audit_event` / `audit_log_config` sugar was removed alongside the production rename.
|
|
174
173
|
- `CreateTestAppOptions extends TestAppServerOptions` — adds `create_route_specs` (required), `rpc_endpoints?: RpcEndpointsSuiteOption` (top-level only — single source of truth, symmetric with the suite-level option), `bootstrap?: BootstrapServerOptions` (top-level only — same precedent as `rpc_endpoints`), and `app_options?: SuiteAppOptions` (`Partial<AppServerOptions>` excluding the five fields the helper manages: `backend`, `session_options`, `create_route_specs`, `rpc_endpoints`, `bootstrap`).
|
|
175
174
|
- `TestAccount` — `{account, actor, session_cookie, api_token, create_session_headers, create_bearer_headers}`.
|
|
176
175
|
- `TestApp` — `{app, backend, server, surface_spec, surface, route_specs, create_session_headers, create_bearer_headers, create_daemon_token_headers, create_account, cleanup}`. `server` is the assembled `AppServer`, for what `create_app_server` built beyond the lifted fields — `require_audit_sse(test_app.server)` with `audit_log_sse` in `app_options`, `test_app.server.ws_endpoints[path]` — instead of capturing them from a `create_route_specs` closure.
|
|
@@ -199,7 +198,7 @@ schedule stopped by `cleanup()`, which is the assembled server's `close`.
|
|
|
199
198
|
|
|
200
199
|
A fresh Hono app is created on every call because middleware closures bind
|
|
201
200
|
to the server's deps (db, keyring). Hono assembly is cheap (~10–50ms);
|
|
202
|
-
|
|
201
|
+
the WASM caching in `db.ts` is where the real savings are.
|
|
203
202
|
|
|
204
203
|
### `auth_apps.ts` — adversarial-auth app factories
|
|
205
204
|
|
|
@@ -224,7 +223,7 @@ test-only by construction.
|
|
|
224
223
|
|
|
225
224
|
### `schema_introspect.ts` — `query_schema_snapshot`
|
|
226
225
|
|
|
227
|
-
- `query_schema_snapshot(db, options?)` — introspects a live DB into a deterministic `SchemaSnapshot` via `pg_catalog` + `information_schema`. Captures tables, columns (with `udt_name` to distinguish int4/int8), indexes (`indexdef`), constraints (`pg_get_constraintdef`), sequences, and enum types (`pg_enum` labels in declared `enumsortorder`, so a `cell_visibility` label-set/order drift is gated). The `schema_version` migration tracker is always excluded — it's framework bookkeeping, not domain schema
|
|
226
|
+
- `query_schema_snapshot(db, options?)` — introspects a live DB into a deterministic `SchemaSnapshot` via `pg_catalog` + `information_schema`. Captures tables, columns (with `udt_name` to distinguish int4/int8), indexes (`indexdef`), constraints (`pg_get_constraintdef`), sequences, and enum types (`pg_enum` labels in declared `enumsortorder`, so a `cell_visibility` label-set/order drift is gated). The `schema_version` migration tracker is always excluded — it's framework bookkeeping, not domain schema; twin impls keep it identical (same namespaces, names and partitioning), which `query_migration_tracker` + `assert_migration_trackers_equal` gate separately. Twinned by `fuz_db::query_schema_snapshot` (Rust); the `_testing_schema_snapshot` RPC's wire validator is the shared `SchemaSnapshot`, so the enum field must serialize on both sides.
|
|
228
227
|
- `SchemaSnapshot` — the Zod schema is canonical (co-located in `schema_introspect.ts`; the cross-impl `_testing_schema_snapshot` RPC action reuses it as its wire validator, and the type is `z.infer`'d from it). Fully JSON-serializable; every collection deterministically sorted on capture so structural equality is stable across runs.
|
|
229
228
|
- `query_migration_tracker(db)` / `MigrationTracker` — the migration-_identity_ twin of the snapshot: reads the `schema_version` tracker rows (`[{namespace, name, sequence}]`) the snapshot deliberately _excludes_. `MigrationTracker` is the `_testing_migration_tracker` RPC's wire validator; pairs with `assert_migration_trackers_equal` to gate that the two spines record byte-identical migration identity (the swap-freely invariant), catching a migration-name or namespace-partitioning drift the provenance-agnostic schema snapshot can't see.
|
|
230
229
|
|
|
@@ -236,7 +235,7 @@ test-only by construction.
|
|
|
236
235
|
- `SchemaDiff` — tagged-union per drift kind: `table_only_in`, `column_only_in`, `column_field_differs`, `index_only_in`, `index_definition_differs`, `constraint_only_in`, `constraint_differs`, `sequence_only_in`, `sequence_data_type_differs`, `enum_only_in`, `enum_labels_differ` (enum labels compared positionally — declared order is significant).
|
|
237
236
|
- `diff_migration_trackers(a, b)` / `format_migration_tracker_diffs(diffs, labels?)` / `assert_migration_trackers_equal(a, b, labels?)` — the migration-identity twins of the snapshot diff/format/assert, over two `MigrationTracker`s. `MigrationTrackerDiff` is keyed on `(namespace, name)` (the `schema_version` PK): `tracker_row_only_in` (a migration rename or namespace re-partition) and `tracker_sequence_differs` (a re-order).
|
|
238
237
|
|
|
239
|
-
fuz_app's own spine gates this cross-process via the `cross_backend_parity` project (`schema_parity.cross.test.ts` + the dual-spawn `global_setup_schema_parity.ts`), diffing the TS spine ↔ `testing_spine_stub` full schema — `npm run test:cross:parity`. The forge has its own deno↔rust parity gate.
|
|
238
|
+
fuz_app's own spine gates this cross-process via the `cross_backend_parity` project (`schema_parity.cross.test.ts` + the dual-spawn `global_setup_schema_parity.ts`), diffing the TS spine ↔ `testing_spine_stub` full schema — `npm run test:cross:parity`. Both legs run on PostgreSQL there: index definitions are compared as the engine renders them, and pglet (what `memory://` gives a TS backend) leaves sort direction, `NULLS` placement, operator classes and `NULLS NOT DISTINCT` out of `indexdef`, so a snapshot taken on it differs from a PostgreSQL one with identical DDL. The forge has its own deno↔rust parity gate.
|
|
240
239
|
|
|
241
240
|
## Cross-impl RPC-manifest parity
|
|
242
241
|
|
|
@@ -553,7 +552,7 @@ cover real sockets.
|
|
|
553
552
|
|
|
554
553
|
Three layers:
|
|
555
554
|
|
|
556
|
-
1. **Primitives** — `create_fake_ws()`, `create_fake_hono_context(opts)`, `create_stub_upgrade()`, `MinimalActionEnvironment`, `dispatch_ws_message(on_message, event, ws)`. The fake context sets the keys the production auth middleware sets — `AUTH_SESSION_TOKEN_HASH_KEY` included, as `hash_session_token(auth_session_id)` — because the dispatcher reads the credential through `get_resolved_auth(c)`; a hand-built upgrade context must do the same. `create_stub_upgrade()` stands in for a runtime adapter's `upgradeWebSocket`: it passes a request without `Upgrade: websocket` to `next()`, and records an upgrade request — its real `Context` and the endpoint's events factory — in `upgrades`, answering `200`. So a test can send `app.request('/api/ws', {headers: {upgrade: 'websocket', cookie | authorization, origin, 'x-forwarded-for'}})` through an assembled app's whole middleware chain and build the socket's events from the `Context` that chain produced (`src/test/server/create_app_server_ws_endpoints.dispatch.db.test.ts`); `get_create_events()` still returns the last mounted factory, for a hand-built context.
|
|
555
|
+
1. **Primitives** — `create_fake_ws(options?)` (a real `WSContext` over capture arrays `sends` / `closes`, plus `socket` — the fake runtime socket behind `ws.raw`, shaped like Node's `ws`: a `bufferedAmount` the transport's outbound writer reads for backpressure, `stalled` (start it with `{stalled: true}`) to model a client that stopped reading, and `terminate` / `terminated` for the frameless cut; `readyState` reads open until closed or terminated), `create_fake_hono_context(opts)`, `create_stub_upgrade()`, `MinimalActionEnvironment`, `dispatch_ws_message(on_message, event, ws)`. The fake context sets the keys the production auth middleware sets — `AUTH_SESSION_TOKEN_HASH_KEY` included, as `hash_session_token(auth_session_id)` — because the dispatcher reads the credential through `get_resolved_auth(c)`; a hand-built upgrade context must do the same. `create_stub_upgrade()` stands in for a runtime adapter's `upgradeWebSocket`: it passes a request without `Upgrade: websocket` to `next()`, and records an upgrade request — its real `Context` and the endpoint's events factory — in `upgrades`, answering `200`. So a test can send `app.request('/api/ws', {headers: {upgrade: 'websocket', cookie | authorization, origin, 'x-forwarded-for'}})` through an assembled app's whole middleware chain and build the socket's events from the `Context` that chain produced (`src/test/server/create_app_server_ws_endpoints.dispatch.db.test.ts`); `get_create_events()` still returns the last mounted factory, for a hand-built context.
|
|
557
556
|
2. **Harness** — `create_ws_test_harness({actions, transport?, heartbeat?, log?, on_socket_open?, on_socket_close?})` → `WsTestHarness`. `connect(identity?)` is async and resolves after the connection is admitted and `on_socket_open` completes, so broadcasts sent immediately after `await harness.connect()` reach the client. The harness pre-bakes its `RequestContext` (`TEST_CONTEXT_PRESET_KEY`), which also skips the admission credential re-read — there are no session or token rows behind a harness identity — so tests of the re-read itself drive `register_action_ws` with a real database and no preset (`src/test/actions/register_action_ws.admission.db.test.ts`). The harness threads its own `create_stub_db()` into the dispatcher's `db` slot so handlers declaring `side_effects: true` execute under the same transaction wrap they would in production (the stub's `transaction(fn)` synchronously calls `fn(stub_db)`); domain deps reach handlers via factory closures, the same way HTTP RPC factories already wire them. Audit fan-out runs through whatever `audit` emitter the consumer supplied to its action factory closure (typically `create_test_audit_emitter()` for unit harnesses).
|
|
558
557
|
3. **Round-trip helpers** — predicates + wire-frame types live in `transports/ws_client.ts` (shared with the cross-process `ws_transport.ts` impl): `is_notification(method)`, `is_notification_with<P>(method, match)` (type-guard combinator — narrows `wait_for` return type), `is_response_for(id)`, `JsonrpcNotificationFrame<P>` / `JsonrpcSuccessResponseFrame<R>` / `JsonrpcErrorResponseFrame<D>` (typed wire-frame shapes distinct from the runtime Zod schemas in `http/jsonrpc.ts` — generic over `params` / `result` / `data` so tests narrow without casts).
|
|
559
558
|
|
|
@@ -624,7 +623,7 @@ the spread are ignored by the suite.
|
|
|
624
623
|
|
|
625
624
|
### `integration.ts` — `describe_standard_integration_tests`
|
|
626
625
|
|
|
627
|
-
Exercises the full stack against real
|
|
626
|
+
Exercises the full stack against a real in-memory database + auth middleware + session
|
|
628
627
|
cookies + bearer tokens. The suite has ~19 `describe` blocks grouped under
|
|
629
628
|
these thematic areas:
|
|
630
629
|
|
|
@@ -972,10 +971,13 @@ source of truth for wire-shape conformance.
|
|
|
972
971
|
case — `GET /api/account/status` is bundled into `create_account_route_specs`,
|
|
973
972
|
so every spine serves it (`true`); the gate fails loud if a declaring backend
|
|
974
973
|
doesn't mount it (replacing the old runtime 404-sniff-skip).
|
|
975
|
-
`oversized_reject_closes_connection`
|
|
976
|
-
smuggling probe (`true` Node/Deno/Rust —
|
|
977
|
-
|
|
978
|
-
|
|
974
|
+
`oversized_reject_closes_connection` picks the arm of the body-size
|
|
975
|
+
smuggling probe (`true` Node/Deno/Rust — the connection closes after an
|
|
976
|
+
oversized-body 413, at once on Node and once the declared body has arrived
|
|
977
|
+
on Deno, so the pipelined request goes unanswered; `false` Bun —
|
|
978
|
+
`Bun.serve` keeps the connection and serves the next request, correctly
|
|
979
|
+
framed, so the suite requires no desync there instead: exactly the 413 and
|
|
980
|
+
the reply to the pipelined request, which a backend that closes fails).
|
|
979
981
|
`ws_handshake_pipelining` gates the WS round-trip suite's
|
|
980
982
|
frames-with-the-handshake case (`true` Node/Deno/Rust — frames written in the
|
|
981
983
|
same TCP write as the upgrade request reach the socket; `false` Bun, whose
|
|
@@ -1219,6 +1221,36 @@ ws_path})`. The wire literals are independent copies of the producers'
|
|
|
1219
1221
|
constants, so a value changed on one spine fails here. Cross-process only;
|
|
1220
1222
|
fuz_app's own wiring is `src/test/cross_backend/ws_inbound_dispatch.cross.test.ts`.
|
|
1221
1223
|
|
|
1224
|
+
### `cross_backend/ws_outbound_overflow.ts` — `describe_ws_outbound_overflow_cross_tests`
|
|
1225
|
+
|
|
1226
|
+
Real-upgrade parity for the **per-connection outbound bound** — the byte
|
|
1227
|
+
budget both spines hold a WebSocket's waiting frames to
|
|
1228
|
+
(`BackendWebsocketTransport`'s `outbound_queue_bytes`, the Rust `fuz_realtime`
|
|
1229
|
+
outbound queue; same default, same per-frame charge). The close code and its
|
|
1230
|
+
reason are wire contract — a client reads `WS_CLOSE_OUTBOUND_OVERFLOW` as "you
|
|
1231
|
+
fell behind, reconnect" — so this is the pin that runs on both.
|
|
1232
|
+
`describe_ws_outbound_overflow_cross_tests({setup_test, capabilities, base_url,
|
|
1233
|
+
ws_path, origin?, rpc_path?})` drives `_testing_flood_notifications`, which
|
|
1234
|
+
queues a burst onto the caller's own connection in one synchronous run, so the
|
|
1235
|
+
burst waits at once whether or not the client reads and the overflow is
|
|
1236
|
+
deterministic. Cases: a burst within the budget arrives whole and in order
|
|
1237
|
+
ahead of its response, the socket left open — a small one, and one of a few
|
|
1238
|
+
mebibytes in megabyte frames, most of the default budget, which waits on the backend's write pump where megabyte frames outrun the socket's buffer (Deno; Node and Bun write the burst through); a burst far past it closes the
|
|
1239
|
+
socket with the code and the exact reason, no response for the flooding request
|
|
1240
|
+
arrives, and any flood frames that did arrive are a contiguous prefix of the
|
|
1241
|
+
burst — while a second connection on the same account keeps dispatching; a
|
|
1242
|
+
burst past the action's own size limit is refused `invalid_params` with the
|
|
1243
|
+
socket left open; and, with `rpc_path`, the action over HTTP refuses
|
|
1244
|
+
`invalid_params` with reason `no_connection`. Not asserted, because each
|
|
1245
|
+
implementation decides them: how many frames accepted before the overflow
|
|
1246
|
+
reach the client, and the boundary a burst of tiny frames overflows at. The
|
|
1247
|
+
flood action is daemon-token-gated, so the flooding socket upgrades with the
|
|
1248
|
+
daemon token and no `Origin` (`create_ws_transport`'s `origin: null`). The wire
|
|
1249
|
+
literals are independent copies of the producers' constants. Gated on
|
|
1250
|
+
`capabilities.ws`; cross-process only, and only for a backend that mounts the
|
|
1251
|
+
flood action on its WS endpoint. fuz_app's own wiring is
|
|
1252
|
+
`src/test/cross_backend/ws_outbound_overflow.cross.test.ts`.
|
|
1253
|
+
|
|
1222
1254
|
### `cross_backend/ws_connection_cap.ts` — `describe_ws_connection_cap_cross_tests`
|
|
1223
1255
|
|
|
1224
1256
|
Real-upgrade parity for the **per-account WebSocket connection cap** — the
|
|
@@ -1409,7 +1441,7 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1409
1441
|
request (`{result}` / `{error}` / `undefined` to swallow), the path
|
|
1410
1442
|
`describe_peer_ping_ws_tests` drives. With no `on_request` the seam is inert
|
|
1411
1443
|
(a server-initiated request flows to `messages` as before).
|
|
1412
|
-
- `testing/transports/ws_transport.ts` — `create_ws_transport({base_url, ws_path, cookies, origin?, on_request?, headers?})`
|
|
1444
|
+
- `testing/transports/ws_transport.ts` — `create_ws_transport({base_url, ws_path, cookies, origin?, on_request?, headers?})` (`origin: null` sends no `Origin`, which a daemon-token upgrade needs)
|
|
1413
1445
|
builds a real-upgrade WS client using the `ws` npm package (optional
|
|
1414
1446
|
peerDep; consumers wiring cross-process tests `npm install --save-dev ws`).
|
|
1415
1447
|
Threads the keeper cookie onto the upgrade so per-action auth succeeds on
|
|
@@ -1469,7 +1501,7 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1469
1501
|
passed the **transactional** `Db` the auth wipe ran on, so DB-domain
|
|
1470
1502
|
consumers (e.g. fuz_forge truncating its cell / fact / file tables) reset
|
|
1471
1503
|
on the same connection rather than a separately-pooled one that would
|
|
1472
|
-
deadlock against this open transaction under
|
|
1504
|
+
deadlock against this open transaction under the in-memory drivers. Auth
|
|
1473
1505
|
gates on `credential_types: ['daemon_token']` — effectively keeper-only
|
|
1474
1506
|
without forcing the `actor: 'required'` ⟺ `acting?: ActingActor`
|
|
1475
1507
|
biconditional. No free-form runtime grant action exists — see the
|
|
@@ -1497,6 +1529,17 @@ are `src/test/auth/cell_crud_parity.db.test.ts`
|
|
|
1497
1529
|
emitter, so the shared suite body can call the barrier on every backend
|
|
1498
1530
|
uniformly.
|
|
1499
1531
|
|
|
1532
|
+
Also bundled: `_testing_flood_notifications`
|
|
1533
|
+
(`create_testing_flood_notifications_action()`) — queues `count`
|
|
1534
|
+
notifications of `size` payload bytes each (method `_testing_flood`, params
|
|
1535
|
+
`{index, payload}`) onto the caller's own WebSocket connection in one
|
|
1536
|
+
synchronous run and answers `{queued: count}`, so a suite can push a
|
|
1537
|
+
connection's outbound queue past its byte budget from outside. Refused with
|
|
1538
|
+
`invalid_params` past `TESTING_FLOOD_MAX_COUNT`, `TESTING_FLOOD_MAX_SIZE`, or
|
|
1539
|
+
`TESTING_FLOOD_MAX_TOTAL_BYTES` (`count` × `size`), and over HTTP (reason
|
|
1540
|
+
`no_connection` — there is no connection to queue onto). The Rust mirror is
|
|
1541
|
+
`fuz_testing::create_testing_flood_notifications_action_spec`.
|
|
1542
|
+
|
|
1500
1543
|
Also bundled: `_testing_mint_session` — mints a backdated-expiry
|
|
1501
1544
|
`auth_session` row for an account (via `mint_test_session` in `app_server.ts`)
|
|
1502
1545
|
and returns its signed cookie value (future-dated payload). Backs the
|
|
@@ -1602,6 +1645,22 @@ module's own tests (`account_status.test.ts`, `action_rpc.test.ts`,
|
|
|
1602
1645
|
`serve_fact_route.db.test.ts`); fuz_app's own wiring is
|
|
1603
1646
|
`cross_backend/query_shape.cross.test.ts`.
|
|
1604
1647
|
|
|
1648
|
+
### Grant-verb role grammar parity — `cross_backend/role_grant_role_grammar.ts`
|
|
1649
|
+
|
|
1650
|
+
`describe_role_grant_role_grammar_cross_tests({setup_test, rpc_path?})` — an
|
|
1651
|
+
off-grammar `role` (uppercase, hyphen, digit, leading or trailing underscore,
|
|
1652
|
+
space, empty, or all lowercase and one character past the length cap) on `role_grant_assign` and `role_grant_offer_create` answers
|
|
1653
|
+
`invalid_params` with no `data.reason`, and after the refusals no
|
|
1654
|
+
`role_grant_create` / `role_grant_offer_create` audit row carries one of those
|
|
1655
|
+
strings. The control — an on-grammar role no registry holds, refused past
|
|
1656
|
+
validation with `role_not_web_grantable` — keeps the audit read from being
|
|
1657
|
+
vacuous, and the same refusal for a role exactly at the length cap pins that
|
|
1658
|
+
boundary. Exists because the action-manifest parity gate captures no param
|
|
1659
|
+
schemas while the Rust spine parses params by hand, and the grant verbs write
|
|
1660
|
+
the role they refuse into their failure rows. Ungated; cross-process only (it
|
|
1661
|
+
reads the audit log behind `_testing_drain_effects`). fuz_app's own wiring is
|
|
1662
|
+
`src/test/cross_backend/role_grant_role_grammar.cross.test.ts`.
|
|
1663
|
+
|
|
1605
1664
|
### API-token lifetime parity — `cross_backend/token_lifetime.ts`
|
|
1606
1665
|
|
|
1607
1666
|
`describe_token_lifetime_cross_tests({setup_test, rpc_path?})` — the
|
|
@@ -1646,8 +1705,8 @@ drift-guarded by `src/test/cross_backend/spine_expected_schema.db.test.ts`
|
|
|
1646
1705
|
|
|
1647
1706
|
`describe_testing_backdoor_cross_tests({setup_test, rpc_path?, ws?})` —
|
|
1648
1707
|
the negative-credential parity suite for the `_testing_*` backdoor actions.
|
|
1649
|
-
For each `_testing_*` action except `_testing_drain_effects` (the
|
|
1650
|
-
|
|
1708
|
+
For each `_testing_*` action except `_testing_drain_effects` (the privileged
|
|
1709
|
+
writes, the connection flood, and the introspection reads) it fires three principals over real HTTP: **anonymous** →
|
|
1651
1710
|
401 `unauthenticated`, **session** → 403 `forbidden` `credential_type_required`,
|
|
1652
1711
|
**bearer** → 403 `forbidden` `credential_type_required` — and, when `ws`
|
|
1653
1712
|
(`{base_url, ws_path, origin?}`) is passed, sends each on a socket opened with
|
|
@@ -1857,7 +1916,7 @@ re-roll the serve / daemon-info / WS-attach / drain boilerplate:
|
|
|
1857
1916
|
- `testing/cross_backend/testing_server_bun.ts` — `create_bun_testing_adapter()` (`Bun.serve` + `@hono/bun`'s module-level `getConnInfo`, `upgradeWebSocket`, and `websocket`; `Bun.serve` declared locally so it typechecks under the Node toolchain). Needs the optional `@hono/bun` peer dep (the counterpart to Node's `@hono/node-server` + `@hono/node-ws`; `Bun.serve` is built in), and Bun resolves `.js`→`.ts` natively (no flag, unlike Deno). Reuses `create_node_runtime` (Bun implements the `node:fs`/`node:process` surface). WS is module-level + stateless (like Deno) — the `websocket` handler is threaded into `serve`, where `Bun.serve` wants it, so no post-serve attach. It carries `maxPayloadLength` at twice `max_message_bytes` rather than Bun's 16 MiB default: past its cap Bun drops the socket without a close frame (1006), so the headroom leaves a message just over the limit to the per-message check (`WS_CLOSE_MESSAGE_TOO_BIG`, as on Node), while a grossly oversized one is refused before Bun buffers it whole.
|
|
1858
1917
|
- `testing/cross_backend/default_spine_surface.ts` — the canonical no-domain spine surface (account/admin/audit/signup + bootstrap): `spine_session_options`, `spine_roles`, `create_spine_route_specs`, `spine_rpc_endpoints`, `create_spine_surface_spec`. This is the **declared** surface — the `create_standard_rpc_actions` bundle the spec-derived suites auto-enumerate. It passes `daemon_token: true` (both spine binaries mount the daemon-token layer) and leaves `GET /api/surface` at its default, off — the TS spine binary does too, and the Rust `testing_spine_stub` serves none. Shared by the spine_stub cross test, the TS cross tests, and the binary.
|
|
1859
1918
|
- `testing/cross_backend/full_spine_mount.ts` — `build_full_spine_rpc_actions(deps, options)` — the **full** live RPC mount: the declared bundle **plus** the off-declared-surface families the binary live-mounts (`_testing_*` backdoors, the cell verb set, the opt-in `actor_lookup` / `actor_search` resolvers). `build_full_spine_mount(deps, options)` builds it once for both of the binary's endpoints, returning `FullSpineMount` (`{rpc_actions, ws_actions}`): the WS list is `protocol_actions` plus every RPC action not already among them, twinning the Rust `testing_spine_stub`, which serves one registry on RPC and WS (the one difference is `cancel` — a registered protocol action on TS, owned by the read loop on Rust). Single-sources the mount so the binary and the `spine_method_coverage` reconciliation test build the same list.
|
|
1860
|
-
- `testing/cross_backend/ts_spine_backend_config.ts` — `ts_spine_node_backend_config()` / `ts_spine_deno_backend_config()` / `ts_spine_bun_backend_config()` presets (in-memory
|
|
1919
|
+
- `testing/cross_backend/ts_spine_backend_config.ts` — `ts_spine_node_backend_config()` / `ts_spine_deno_backend_config()` / `ts_spine_bun_backend_config()` presets (in-memory pglet, no external infra), the TS analog of `rust_spine_stub_backend_config()`.
|
|
1861
1920
|
|
|
1862
1921
|
fuz_app's own binary wiring (`src/test/cross_backend/testing_spine_server{,_node,_deno,_bun}.ts`) is the worked example: ~one `build_app` over `create_app_backend` + `create_app_server` (`rate_limiters: 'disabled_for_testing'` plus whichever login / action limiters its env toggles built, `build_full_spine_mount`'s two lists on one `rpc_endpoints` entry and one `ws_endpoints` entry, whose `transport` is also the role-grant-offer `notification_sender`), reusing `default_spine_surface`. `src/test/cross_backend/testing_spine_server.db.test.ts` builds it with the Node adapter in-process and asserts its surface lists `/api/ws` and passes the surface invariants. The `_node`/`_deno`/`_bun` entries differ only in which adapter they wire — `build_spine_app` is runtime-agnostic. It leaves `create_app_server`'s `auth_cleanup` off, as the Rust `testing_spine_stub` leaves its twin unscheduled: a background pass would delete rows and write audit rows under a running suite. A consumer's cross-process test binary may schedule it when nothing its suites seed is already expired (the conformance table's `expired_session` principal seeds a backdated session row); an in-process harness leaves it off.
|
|
1863
1922
|
|
|
@@ -1925,7 +1984,7 @@ fuz_app also ships its **own** `npm run benchmark:cross-impl`
|
|
|
1925
1984
|
(`src/benchmarks/cross_impl.bench.ts`) on the back of its TS spine binary —
|
|
1926
1985
|
ts-node + ts-deno + ts-bun (+ the Rust `spine_stub` when `FUZ_TESTING_RUST_SPINE_STUB_BIN`
|
|
1927
1986
|
is set). The three TS runtimes are apples-to-apples with each other (same
|
|
1928
|
-
|
|
1987
|
+
in-memory pglet driver); TS-vs-Rust carries the pglet-vs-Postgres DB-layer caveat
|
|
1929
1988
|
(documented in the run). The artifact (`*.latest.json`) is gitignored.
|
|
1930
1989
|
|
|
1931
1990
|
- `bench/scenario.ts` — `BenchScenario` (`{name, requires?, run}`) +
|
|
@@ -5,7 +5,7 @@ import './assert_dev_env.js';
|
|
|
5
5
|
* `describe_standard_admin_integration_tests` creates a composable test suite
|
|
6
6
|
* that exercises admin account listing, role_grant grant/revoke (via the RPC
|
|
7
7
|
* surface — see `role_grant_offer_create` / `role_grant_revoke`), session/token
|
|
8
|
-
* management, and audit log routes against a real
|
|
8
|
+
* management, and audit log routes against a real database.
|
|
9
9
|
*
|
|
10
10
|
* Consumers call it with their route factory, session config, role schema,
|
|
11
11
|
* and RPC endpoint specs — all admin route tests come for free.
|
|
@@ -3,7 +3,7 @@ import './assert_dev_env.js';
|
|
|
3
3
|
* Bootstrapped app server factory for integration tests.
|
|
4
4
|
*
|
|
5
5
|
* Creates a keeper account, API token, and signed session cookie on a
|
|
6
|
-
* database. By default uses a cached in-memory
|
|
6
|
+
* database. By default uses a cached in-memory pglet (one shared WASM instance
|
|
7
7
|
* per loaded copy of `testing/db.ts` — once per run under the `db` project's
|
|
8
8
|
* `isolate: false` + `fileParallelism: false`); pass `db` to use
|
|
9
9
|
* an existing database (any driver) instead.
|
|
@@ -168,11 +168,11 @@ export interface TestAppServerOptions {
|
|
|
168
168
|
session_options: SessionOptions<string>;
|
|
169
169
|
/** Existing database — skips internal DB creation when provided. Caller owns the DB lifecycle. */
|
|
170
170
|
db?: Db;
|
|
171
|
-
/** Database driver type — only used when `db` is provided. Default: `'
|
|
171
|
+
/** Database driver type — only used when `db` is provided. Default: `'pglet-memory'`. */
|
|
172
172
|
db_type?: DbType;
|
|
173
173
|
/**
|
|
174
174
|
* Extra migration namespaces run after the builtin auth namespace in the
|
|
175
|
-
* auto-created in-memory
|
|
175
|
+
* auto-created in-memory database, mirroring `create_app_backend`'s
|
|
176
176
|
* `migration_namespaces`. For suites whose backend needs tables beyond
|
|
177
177
|
* auth — the cell parity suite passes `[CELL_MIGRATION_NS]`. The harness
|
|
178
178
|
* builds + caches a fresh-per-test factory migrating
|
|
@@ -209,7 +209,7 @@ export interface TestAppServerOptions {
|
|
|
209
209
|
* Create an app server with a bootstrapped account for testing.
|
|
210
210
|
*
|
|
211
211
|
* Sets up:
|
|
212
|
-
* - Auth tables (via cached
|
|
212
|
+
* - Auth tables (via the cached default factory, or reuses existing `db`)
|
|
213
213
|
* - A keeper account with hashed password
|
|
214
214
|
* - Role role_grants for each role in `options.roles`
|
|
215
215
|
* - An API token for Bearer auth
|
|
@@ -348,7 +348,7 @@ export declare const create_loopback_app_server_options: () => Pick<AppServerOpt
|
|
|
348
348
|
*
|
|
349
349
|
* A fresh Hono app is created each call — middleware closures bind to the
|
|
350
350
|
* server's deps (db, keyring), so reuse across servers is unsafe.
|
|
351
|
-
* The expensive resource (
|
|
351
|
+
* The expensive resource (the WASM database) is cached separately in `testing/db.ts`.
|
|
352
352
|
*
|
|
353
353
|
* @param options - test app configuration
|
|
354
354
|
* @returns a `TestApp` ready for HTTP testing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAGjC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAInD,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAU5D,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC7F,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG3E,OAAO,EAEN,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEN,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAOvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAGhE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,gBAIhC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,QAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"app_server.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/app_server.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ import { create_realtime_closer } from '../actions/connection_closer.js';
|
|
|
16
16
|
import { default_audit_factory } from '../server/app_backend.js';
|
|
17
17
|
import { create_app_server } from '../server/app_server.js';
|
|
18
18
|
import { generate_daemon_token, DAEMON_TOKEN_HEADER } from '../auth/daemon_token.js';
|
|
19
|
-
import {
|
|
19
|
+
import { create_default_db_factory } from './db.js';
|
|
20
20
|
import { token_scope_full } from '../auth/token_scope.js';
|
|
21
21
|
/**
|
|
22
22
|
* Fast password stub for tests that don't exercise login/password flows.
|
|
@@ -31,21 +31,22 @@ export const stub_password_deps = {
|
|
|
31
31
|
};
|
|
32
32
|
/** 64-hex-char test cookie secret — deterministic, never used in production. */
|
|
33
33
|
export const TEST_COOKIE_SECRET = 'a'.repeat(64);
|
|
34
|
-
// Module-level
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
34
|
+
// Module-level default factory (pglet-wasm unless `set_default_db_factory` installed
|
|
35
|
+
// another) for create_test_app_server when no db is provided. Shares the WASM instance
|
|
36
|
+
// cache from `testing/db.ts`, avoiding redundant cold starts within one loaded copy of
|
|
37
|
+
// that module. Schema is reset on each create() call.
|
|
38
|
+
const fallback_db_factory = create_default_db_factory(async (db) => {
|
|
38
39
|
await run_migrations(db, [auth_migration_ns]);
|
|
39
40
|
});
|
|
40
|
-
// Auto-created
|
|
41
|
+
// Auto-created default factories keyed by extra-namespace identity. Suites
|
|
41
42
|
// whose backend needs tables beyond auth (e.g. the cell layer) share one
|
|
42
43
|
// factory per distinct namespace set — and the worker-cached WASM instance —
|
|
43
44
|
// rather than each hand-building its own. The cell parity suite is the first
|
|
44
45
|
// user.
|
|
45
46
|
const fallback_factories_by_namespaces = new Map();
|
|
46
47
|
/**
|
|
47
|
-
* Resolve the no-`db`
|
|
48
|
-
* namespaces. Empty / omitted → the shared auth-only `
|
|
48
|
+
* Resolve the no-`db` default factory for the requested extra migration
|
|
49
|
+
* namespaces. Empty / omitted → the shared auth-only `fallback_db_factory`;
|
|
49
50
|
* otherwise a memoized factory whose `init` runs
|
|
50
51
|
* `[auth_migration_ns, ...migration_namespaces]` on each reset. The
|
|
51
52
|
* reset-on-`create` gives the same fresh-db-per-test isolation as the
|
|
@@ -54,12 +55,12 @@ const fallback_factories_by_namespaces = new Map();
|
|
|
54
55
|
*/
|
|
55
56
|
const resolve_fallback_factory = (migration_namespaces) => {
|
|
56
57
|
if (!migration_namespaces || migration_namespaces.length === 0) {
|
|
57
|
-
return
|
|
58
|
+
return fallback_db_factory;
|
|
58
59
|
}
|
|
59
60
|
const key = migration_namespaces.map((ns) => ns.namespace).join(',');
|
|
60
61
|
let factory = fallback_factories_by_namespaces.get(key);
|
|
61
62
|
if (!factory) {
|
|
62
|
-
factory =
|
|
63
|
+
factory = create_default_db_factory(async (db) => {
|
|
63
64
|
await run_migrations(db, [auth_migration_ns, ...migration_namespaces]);
|
|
64
65
|
});
|
|
65
66
|
fallback_factories_by_namespaces.set(key, factory);
|
|
@@ -176,7 +177,7 @@ const default_test_fs_stubs = {
|
|
|
176
177
|
* resets it to false before this runs).
|
|
177
178
|
*/
|
|
178
179
|
const _build_test_backend = async (options) => {
|
|
179
|
-
const { db: existing_db, db_type = '
|
|
180
|
+
const { db: existing_db, db_type = 'pglet-memory', password = stub_password_deps, audit_factory = default_audit_factory, fs_stubs = default_test_fs_stubs, migration_namespaces } = options;
|
|
180
181
|
if (existing_db && migration_namespaces && migration_namespaces.length > 0) {
|
|
181
182
|
throw new Error('test app setup: pass either `db` (caller owns migrations) or `migration_namespaces` ' +
|
|
182
183
|
'(harness migrates), not both');
|
|
@@ -188,14 +189,14 @@ const _build_test_backend = async (options) => {
|
|
|
188
189
|
let db;
|
|
189
190
|
let db_name;
|
|
190
191
|
if (existing_db) {
|
|
191
|
-
// Reset singleton config row from a previous test (harmless on fresh
|
|
192
|
+
// Reset singleton config row from a previous test (harmless on a fresh database).
|
|
192
193
|
await existing_db.query('UPDATE app_settings SET open_signup = false, updated_at = NULL, updated_by = NULL WHERE open_signup = true OR updated_at IS NOT NULL');
|
|
193
194
|
db = existing_db;
|
|
194
195
|
db_name = 'test';
|
|
195
196
|
}
|
|
196
197
|
else {
|
|
197
|
-
// In-memory
|
|
198
|
-
// instead of creating a new
|
|
198
|
+
// In-memory default driver via cached factory — reuses the WASM instance from
|
|
199
|
+
// `testing/db.ts` instead of creating a new instance each time. Schema is reset and migrations re-run
|
|
199
200
|
// on each call, but the expensive WASM cold start only happens once per loaded
|
|
200
201
|
// copy of `testing/db.ts` — under the `db` project's `isolate: false` +
|
|
201
202
|
// `fileParallelism: false` that is once for the whole run.
|
|
@@ -205,11 +206,11 @@ const _build_test_backend = async (options) => {
|
|
|
205
206
|
}
|
|
206
207
|
const backend = {
|
|
207
208
|
// a supplied `db` reports the caller's `db_type`; the auto-created one names
|
|
208
|
-
//
|
|
209
|
-
// (`
|
|
209
|
+
// pglet unconditionally — a run that installs another default factory
|
|
210
|
+
// (`set_default_db_factory`) before this module loads gets that driver
|
|
210
211
|
// here, and no caller reads this field to pick behavior: it is reported,
|
|
211
212
|
// not dispatched on
|
|
212
|
-
db_type: existing_db ? db_type : '
|
|
213
|
+
db_type: existing_db ? db_type : 'pglet-memory',
|
|
213
214
|
db_name,
|
|
214
215
|
// the factory's init ran the migrations, for a supplied `db` and the auto-created one alike
|
|
215
216
|
migration_results: [],
|
|
@@ -230,7 +231,7 @@ const _build_test_backend = async (options) => {
|
|
|
230
231
|
* Create an app server with a bootstrapped account for testing.
|
|
231
232
|
*
|
|
232
233
|
* Sets up:
|
|
233
|
-
* - Auth tables (via cached
|
|
234
|
+
* - Auth tables (via the cached default factory, or reuses existing `db`)
|
|
234
235
|
* - A keeper account with hashed password
|
|
235
236
|
* - Role role_grants for each role in `options.roles`
|
|
236
237
|
* - An API token for Bearer auth
|
|
@@ -310,7 +311,7 @@ const create_bearer_headers_builder = (api_token) => (extra) => ({
|
|
|
310
311
|
*
|
|
311
312
|
* A fresh Hono app is created each call — middleware closures bind to the
|
|
312
313
|
* server's deps (db, keyring), so reuse across servers is unsafe.
|
|
313
|
-
* The expensive resource (
|
|
314
|
+
* The expensive resource (the WASM database) is cached separately in `testing/db.ts`.
|
|
314
315
|
*
|
|
315
316
|
* @param options - test app configuration
|
|
316
317
|
* @returns a `TestApp` ready for HTTP testing
|
|
@@ -408,7 +409,7 @@ export const create_test_app_for_bootstrap = async (options) => {
|
|
|
408
409
|
const { session_options, bootstrap, bootstrap_token } = options;
|
|
409
410
|
// Caller-supplied DB may carry lock state from a prior test — reset to false
|
|
410
411
|
// before `_build_test_backend` runs (which doesn't touch the lock itself).
|
|
411
|
-
//
|
|
412
|
+
// A fresh database already starts at false (factory init).
|
|
412
413
|
if (options.db) {
|
|
413
414
|
await options.db.query('UPDATE bootstrap_lock SET bootstrapped = false WHERE bootstrapped = true');
|
|
414
415
|
}
|
|
@@ -34,7 +34,7 @@ export interface AuditCompletenessTestOptions {
|
|
|
34
34
|
* Composable audit log completeness test suite.
|
|
35
35
|
*
|
|
36
36
|
* Verifies that every auth mutation route produces the correct audit log
|
|
37
|
-
* event type. Exercises routes via HTTP requests against a real
|
|
37
|
+
* event type. Exercises routes via HTTP requests against a real
|
|
38
38
|
* database, then reads events back through the `audit_log_list` RPC
|
|
39
39
|
* (the production observation path the admin UI consumes).
|
|
40
40
|
*
|
|
@@ -96,7 +96,7 @@ const json_session_headers = (fixture, extra) => fixture.create_session_headers(
|
|
|
96
96
|
* Composable audit log completeness test suite.
|
|
97
97
|
*
|
|
98
98
|
* Verifies that every auth mutation route produces the correct audit log
|
|
99
|
-
* event type. Exercises routes via HTTP requests against a real
|
|
99
|
+
* event type. Exercises routes via HTTP requests against a real
|
|
100
100
|
* database, then reads events back through the `audit_log_list` RPC
|
|
101
101
|
* (the production observation path the admin UI consumes).
|
|
102
102
|
*
|
|
@@ -36,7 +36,7 @@ export interface RecordingAuditEmitter {
|
|
|
36
36
|
* Build a no-op `AuditEmitter` that records every `emit`, `emit_pool`, and
|
|
37
37
|
* `emit_role_grant_target` call into `calls` as an `AuditLogInput`. Use to
|
|
38
38
|
* capture audit metadata shapes in unit tests (e.g. password change failure
|
|
39
|
-
* outcome, role-grant create denial) without standing up
|
|
39
|
+
* outcome, role-grant create denial) without standing up a database and the
|
|
40
40
|
* `query_audit_log` pipeline.
|
|
41
41
|
*
|
|
42
42
|
* **Capture scope — all four production fan-out shapes.**
|
|
@@ -34,7 +34,7 @@ export const install_audit_drift_guard = () => {
|
|
|
34
34
|
* Build a no-op `AuditEmitter` that records every `emit`, `emit_pool`, and
|
|
35
35
|
* `emit_role_grant_target` call into `calls` as an `AuditLogInput`. Use to
|
|
36
36
|
* capture audit metadata shapes in unit tests (e.g. password change failure
|
|
37
|
-
* outcome, role-grant create denial) without standing up
|
|
37
|
+
* outcome, role-grant create denial) without standing up a database and the
|
|
38
38
|
* `query_audit_log` pipeline.
|
|
39
39
|
*
|
|
40
40
|
* **Capture scope — all four production fan-out shapes.**
|
|
@@ -6,15 +6,15 @@ export interface BodySizeSmugglingCrossTestOptions {
|
|
|
6
6
|
/** RPC endpoint path to target. Default `/api/rpc`. */
|
|
7
7
|
readonly rpc_path?: string;
|
|
8
8
|
/**
|
|
9
|
-
* Whether the backend closes the connection
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* the
|
|
14
|
-
*
|
|
15
|
-
* and
|
|
16
|
-
* consumer that
|
|
17
|
-
*
|
|
9
|
+
* Whether the backend closes the connection after an oversized-body `413`
|
|
10
|
+
* (`capabilities.oversized_reject_closes_connection`). `true` (default)
|
|
11
|
+
* requires that the pipelined GET goes unanswered — at most one response.
|
|
12
|
+
* `false` (Bun) requires no desync instead: exactly two well-formed
|
|
13
|
+
* responses, the 413 and one matching what the backend answers that GET
|
|
14
|
+
* sent alone — so `rpc_path` must answer a bare `GET` with a stable status
|
|
15
|
+
* and body, and a backend that closes after the 413 fails. Default `true`
|
|
16
|
+
* so a consumer that leaves the flag out fails loud on a backend that
|
|
17
|
+
* keeps the connection.
|
|
18
18
|
*/
|
|
19
19
|
readonly closes_connection?: boolean;
|
|
20
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"body_size_smuggling.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/body_size_smuggling.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"body_size_smuggling.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/body_size_smuggling.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAgE9B,4EAA4E;AAC5E,MAAM,WAAW,iCAAiC;IACjD,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CACrC;AAkGD,eAAO,MAAM,wCAAwC,GACpD,SAAS,iCAAiC,KACxC,IA0GF,CAAC"}
|