@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/db.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
2
|
import type { Db } from '../db/db.js';
|
|
3
|
-
/**
|
|
4
|
-
* CI detection — `CI=true` is set automatically by GitHub Actions, GitLab CI, etc.
|
|
5
|
-
*/
|
|
6
|
-
export declare const IS_CI: boolean;
|
|
7
3
|
/**
|
|
8
4
|
* Factory interface for creating test database instances.
|
|
9
5
|
*/
|
|
@@ -15,75 +11,83 @@ export interface DbFactory {
|
|
|
15
11
|
skip_reason?: string;
|
|
16
12
|
}
|
|
17
13
|
/**
|
|
18
|
-
* Reset a test database to a clean
|
|
14
|
+
* Reset a test database to a clean slate by dropping and recreating the `public` schema.
|
|
19
15
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
16
|
+
* `DROP SCHEMA public CASCADE; CREATE SCHEMA public` in plain SQL, so it resets
|
|
17
|
+
* every driver: the in-memory factories call it on each `create()`, and it is
|
|
18
|
+
* recommended at the start of `init_schema` callbacks for `create_pg_factory`,
|
|
19
|
+
* whose persistent databases accumulate stale DDL across fuz_app versions.
|
|
20
|
+
* Drift-proof — it wipes every table, type, and sequence regardless of
|
|
21
|
+
* namespace, so it needs no upkeep when the schema gains a table. The database
|
|
22
|
+
* instance remains usable after reset.
|
|
23
23
|
*
|
|
24
24
|
* @mutates db - drops the `public` schema and recreates it; all rows in all
|
|
25
25
|
* tables are gone after this returns.
|
|
26
26
|
*/
|
|
27
|
-
export declare const
|
|
27
|
+
export declare const reset_public_schema: (db: Db) => Promise<void>;
|
|
28
28
|
/**
|
|
29
|
-
* Builds a `DbFactory` from a schema initializer —
|
|
29
|
+
* Builds a `DbFactory` from a schema initializer — the shape of every factory builder here.
|
|
30
30
|
*/
|
|
31
31
|
export type DbFactoryBuilder = (init_schema: (db: Db) => Promise<void>) => DbFactory;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* Create a PGlite (in-memory) database factory for tests.
|
|
34
|
+
*
|
|
35
|
+
* Always enabled — needs the optional `@electric-sql/pglite` peer installed.
|
|
36
|
+
* Shares one PGlite WASM instance across the PGlite factories this module
|
|
37
|
+
* builds; each `create()` resets the schema via `DROP SCHEMA public CASCADE`
|
|
38
|
+
* instead of paying the cold start again.
|
|
39
|
+
*
|
|
40
|
+
* @param init_schema - callback to initialize the database schema
|
|
34
41
|
*/
|
|
35
|
-
export
|
|
36
|
-
/**
|
|
37
|
-
* Whether an installed substitute (`set_substitute_db_factory`) may stand in
|
|
38
|
-
* for the PGlite factory at this call site. Defaults to `true`; pass `false`
|
|
39
|
-
* where PGlite itself is the subject under test.
|
|
40
|
-
*/
|
|
41
|
-
substitutable?: boolean;
|
|
42
|
-
}
|
|
42
|
+
export declare const create_pglite_factory: DbFactoryBuilder;
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
* Create a pglet-wasm (in-memory) database factory for tests.
|
|
45
|
+
*
|
|
46
|
+
* Always enabled — needs the optional `@fuzdev/pglet-wasm` peer installed.
|
|
47
|
+
* Shares one pglet instance across the pglet-wasm factories this module
|
|
48
|
+
* builds, created with fuz_app's value coercion (`PGLET_COERCION`); each
|
|
49
|
+
* `create()` resets the schema via `DROP SCHEMA public CASCADE`.
|
|
46
50
|
*
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
* @param init_schema - callback to initialize the database schema
|
|
52
|
+
*/
|
|
53
|
+
export declare const create_pglet_wasm_factory: DbFactoryBuilder;
|
|
54
|
+
/**
|
|
55
|
+
* Install the builder `create_default_db_factory` uses, so suites written
|
|
56
|
+
* against the default run against another driver without being edited —
|
|
57
|
+
* `create_pglite_factory` to run them on PGlite. Pass `null` to restore
|
|
58
|
+
* pglet-wasm.
|
|
50
59
|
*
|
|
51
60
|
* The slot is read when a factory is built, not when it creates a database,
|
|
52
|
-
* so install before the first `
|
|
61
|
+
* so install before the first `create_default_db_factory` call — a vitest
|
|
53
62
|
* `setupFiles` entry, which runs ahead of every test file's imports, is the
|
|
54
63
|
* shape fuz_app's own `db` project uses. A factory built earlier (including
|
|
55
64
|
* the module-level fallback in `testing/app_server.ts`) keeps the driver it
|
|
56
65
|
* was built with, and uninstalling does not revert it.
|
|
57
66
|
*
|
|
58
|
-
* @param create_factory - the builder to install, or `null` to
|
|
67
|
+
* @param create_factory - the builder to install, or `null` to restore the default
|
|
68
|
+
* @returns the builder this replaced (`null` for pglet-wasm), so a caller can put it back
|
|
59
69
|
*/
|
|
60
|
-
export declare const
|
|
70
|
+
export declare const set_default_db_factory: (create_factory: DbFactoryBuilder | null) => DbFactoryBuilder | null;
|
|
61
71
|
/**
|
|
62
|
-
* Create
|
|
63
|
-
*
|
|
64
|
-
* Always enabled — no external dependencies required.
|
|
65
|
-
* Shares a single PGlite WASM instance across the PGlite factories this module builds.
|
|
66
|
-
* Subsequent `create()` calls reset the schema via `DROP SCHEMA public CASCADE`
|
|
67
|
-
* instead of paying the WASM cold-start cost again.
|
|
72
|
+
* Create the default in-memory database factory for tests: pglet-wasm, or the
|
|
73
|
+
* builder `set_default_db_factory` installed.
|
|
68
74
|
*
|
|
69
|
-
*
|
|
70
|
-
* `
|
|
75
|
+
* The factory fuz_app's own test helpers fall back to when a suite passes none
|
|
76
|
+
* (`create_test_app_server`, `describe_rate_limiting_tests`,
|
|
77
|
+
* `describe_sse_route_tests`). Call `create_pglite_factory` or
|
|
78
|
+
* `create_pglet_wasm_factory` directly to pin a driver.
|
|
71
79
|
*
|
|
72
80
|
* @param init_schema - callback to initialize the database schema
|
|
73
|
-
* @param options - `substitutable: false` pins this call site to PGlite
|
|
74
81
|
*/
|
|
75
|
-
export declare const
|
|
82
|
+
export declare const create_default_db_factory: DbFactoryBuilder;
|
|
76
83
|
/**
|
|
77
84
|
* Create a pg (PostgreSQL) database factory for tests.
|
|
78
85
|
*
|
|
79
|
-
* Skipped when `test_url` is not provided.
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* For full clean-slate behavior (recommended), call `drop_auth_schema(db)`
|
|
85
|
-
* at the start of `init_schema` before running migrations. This handles
|
|
86
|
-
* upstream schema changes that go beyond adding new tables/columns.
|
|
86
|
+
* Skipped when `test_url` is not provided. Each `create()` opens a pool,
|
|
87
|
+
* resets the `public` schema (`reset_public_schema`) and runs `init_schema` —
|
|
88
|
+
* the lifecycle every factory here shares, so a persistent test database never
|
|
89
|
+
* carries stale DDL or tracker rows from an earlier run or another suite's
|
|
90
|
+
* schema. Point `test_url` at a database used only for tests.
|
|
87
91
|
*
|
|
88
92
|
* @param init_schema - callback to initialize the database schema
|
|
89
93
|
* @param test_url - PostgreSQL connection URL (e.g. from `TEST_DATABASE_URL`)
|
|
@@ -107,21 +111,6 @@ export declare const auth_truncate_tables: string[];
|
|
|
107
111
|
* touch audit logging don't need to truncate it.
|
|
108
112
|
*/
|
|
109
113
|
export declare const auth_integration_truncate_tables: string[];
|
|
110
|
-
/**
|
|
111
|
-
* Reset the entire `public` schema for a clean slate before re-migration.
|
|
112
|
-
*
|
|
113
|
-
* Recommended at the start of `init_schema` callbacks for `create_pg_factory`.
|
|
114
|
-
* Persistent test databases accumulate stale DDL across fuz_app versions;
|
|
115
|
-
* `DROP SCHEMA public CASCADE; CREATE SCHEMA public` wipes every table, type,
|
|
116
|
-
* and sequence regardless of namespace, so migrations always run against a
|
|
117
|
-
* truly empty database. Drift-proof — unlike a hand-maintained drop list it
|
|
118
|
-
* needs no upkeep when the schema gains a table. Despite the historical name,
|
|
119
|
-
* this resets the whole schema, not just auth tables (the only documented use
|
|
120
|
-
* is clean-slate re-migration, which always wanted a full reset).
|
|
121
|
-
*
|
|
122
|
-
* @mutates db - drops and recreates the `public` schema; all tables gone.
|
|
123
|
-
*/
|
|
124
|
-
export declare const drop_auth_schema: (db: Db) => Promise<void>;
|
|
125
114
|
/**
|
|
126
115
|
* Create a `describe_db` function bound to specific factories and truncate tables.
|
|
127
116
|
*
|
package/dist/testing/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/db.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA8B7B,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/db.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA8B7B,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAQtC;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,GAAU,IAAI,EAAE,KAAG,OAAO,CAAC,IAAI,CAG9D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC;AAgDrF;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,EAAE,gBACqC,CAAC;AAE1E;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,EAAE,gBACyC,CAAC;AAKlF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,sBAAsB,GAClC,gBAAgB,gBAAgB,GAAG,IAAI,KACrC,gBAAgB,GAAG,IAIrB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,EAAE,gBAC+B,CAAC;AAExE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAC7B,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EACtC,WAAW,MAAM,KACf,SA6DF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,UAQhC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,UAAyC,CAAC;AAEvF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,GAC9B,WAAW,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,EACvC,iBAAiB,KAAK,CAAC,MAAM,CAAC,KAC5B,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,KAAK,IAAI,CAwBzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,KAAK,CAAC,SAAS,CAAC,KAAG,IAQnE,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB,GACrC,IAAI,EAAE,EACN,OAAO,MAAM,EACb,SAAS,aAAa,CAAC,MAAM,CAAC,KAC5B,OAAO,CAAC,IAAI,CAId,CAAC"}
|
package/dist/testing/db.js
CHANGED
|
@@ -2,129 +2,153 @@ import './assert_dev_env.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Test database fixtures for parameterized testing.
|
|
4
4
|
*
|
|
5
|
-
* Provides factory builders for creating test databases with
|
|
6
|
-
* and pg (PostgreSQL) drivers. Consumer
|
|
7
|
-
* initialization via `run_migrations` and
|
|
5
|
+
* Provides factory builders for creating test databases with pglet-wasm (the
|
|
6
|
+
* in-memory default), PGlite (in-memory) and pg (PostgreSQL) drivers. Consumer
|
|
7
|
+
* projects provide their own schema initialization via `run_migrations` and
|
|
8
|
+
* compose factories into test suites.
|
|
8
9
|
*
|
|
9
10
|
* @example
|
|
10
11
|
* ```ts
|
|
11
|
-
* import {
|
|
12
|
+
* import {create_default_db_factory, create_pg_factory} from '@fuzdev/fuz_app/testing/db.ts';
|
|
12
13
|
* import {run_migrations} from '@fuzdev/fuz_app/db/migrate.ts';
|
|
13
14
|
* import {auth_migration_ns} from '@fuzdev/fuz_app/auth/migrations.ts';
|
|
14
15
|
*
|
|
15
16
|
* const init_schema = async (db) => {
|
|
16
17
|
* await run_migrations(db, [auth_migration_ns]);
|
|
17
18
|
* };
|
|
18
|
-
* const
|
|
19
|
+
* const default_factory = create_default_db_factory(init_schema);
|
|
19
20
|
* const pg_factory = create_pg_factory(init_schema, process.env.TEST_DATABASE_URL);
|
|
20
|
-
* export const db_factories = [
|
|
21
|
+
* export const db_factories = [default_factory, pg_factory];
|
|
21
22
|
* ```
|
|
22
23
|
*
|
|
23
24
|
* @module
|
|
24
25
|
*/
|
|
25
26
|
import { describe, beforeAll, beforeEach, afterAll, assert } from 'vitest';
|
|
26
|
-
import { to_error_message } from '@fuzdev/fuz_util/error.ts';
|
|
27
27
|
import { create_pglite_db } from '../db/db_pglite.js';
|
|
28
|
+
import { create_pglet_db_driver, create_pglet_instance } from '../db/db_pglet.js';
|
|
28
29
|
import { assert_valid_sql_identifier } from '../db/sql_identifier.js';
|
|
29
30
|
import { create_pg_db, register_pg_type_parsers } from '../db/db_pg.js';
|
|
30
31
|
import { query_public_columns } from '../db/schema_ready.js';
|
|
32
|
+
import { pg_error_code } from '../db/pg_error.js';
|
|
31
33
|
/**
|
|
32
|
-
*
|
|
33
|
-
*/
|
|
34
|
-
export const IS_CI = process.env.CI === 'true';
|
|
35
|
-
/**
|
|
36
|
-
* Reset a test database to a clean state by dropping and recreating the public schema.
|
|
34
|
+
* Reset a test database to a clean slate by dropping and recreating the `public` schema.
|
|
37
35
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
36
|
+
* `DROP SCHEMA public CASCADE; CREATE SCHEMA public` in plain SQL, so it resets
|
|
37
|
+
* every driver: the in-memory factories call it on each `create()`, and it is
|
|
38
|
+
* recommended at the start of `init_schema` callbacks for `create_pg_factory`,
|
|
39
|
+
* whose persistent databases accumulate stale DDL across fuz_app versions.
|
|
40
|
+
* Drift-proof — it wipes every table, type, and sequence regardless of
|
|
41
|
+
* namespace, so it needs no upkeep when the schema gains a table. The database
|
|
42
|
+
* instance remains usable after reset.
|
|
41
43
|
*
|
|
42
44
|
* @mutates db - drops the `public` schema and recreates it; all rows in all
|
|
43
45
|
* tables are gone after this returns.
|
|
44
46
|
*/
|
|
45
|
-
export const
|
|
47
|
+
export const reset_public_schema = async (db) => {
|
|
46
48
|
await db.query('DROP SCHEMA public CASCADE');
|
|
47
49
|
await db.query('CREATE SCHEMA public');
|
|
48
50
|
};
|
|
49
|
-
// Module-level PGlite cache — one instance shared by the PGlite factories this
|
|
50
|
-
// module builds, for as long as the module is loaded. Under the `db` project's
|
|
51
|
-
// `isolate: false` + `fileParallelism: false` that is the whole run; a project
|
|
52
|
-
// that isolates its files gets one per worker instead.
|
|
53
|
-
let module_db = null;
|
|
54
|
-
// The installed stand-in for `create_pglite_factory`, `null` when none is installed.
|
|
55
|
-
let substitute_db_factory = null;
|
|
56
51
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
52
|
+
* Build a factory over one module-level instance per driver: the first
|
|
53
|
+
* `create()` creates it, and each `create()` resets its `public` schema and
|
|
54
|
+
* runs `init_schema`, so only the first pays the WASM cold start.
|
|
59
55
|
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
56
|
+
* The instance lives as long as this module stays loaded — under the `db`
|
|
57
|
+
* project's `isolate: false` + `fileParallelism: false` that is the whole run;
|
|
58
|
+
* a project that isolates its files gets one per worker. A promise rather than
|
|
59
|
+
* a value, so two concurrent first `create()` calls build one instance, and a
|
|
60
|
+
* failed first load is the error every later `create()` reports.
|
|
61
|
+
*/
|
|
62
|
+
const create_shared_instance_factory = (name, resolve_db, init_schema) => {
|
|
63
|
+
return {
|
|
64
|
+
name,
|
|
65
|
+
skip: false,
|
|
66
|
+
async create() {
|
|
67
|
+
const db = await resolve_db();
|
|
68
|
+
// the instance is shared with every factory of this driver, so it may hold any schema
|
|
69
|
+
await reset_public_schema(db);
|
|
70
|
+
await init_schema(db);
|
|
71
|
+
return db;
|
|
72
|
+
},
|
|
73
|
+
async close() {
|
|
74
|
+
// No-op: the instance is module-level, so it lives as long as this module
|
|
75
|
+
// stays loaded. Nothing frees it earlier.
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
// The module-level instances the shared factories hand out, created on first use.
|
|
80
|
+
let pglite_db = null;
|
|
81
|
+
let pglet_wasm_db = null;
|
|
82
|
+
const resolve_pglite_db = () => (pglite_db ??= (async () => {
|
|
83
|
+
const { PGlite } = await import('@electric-sql/pglite');
|
|
84
|
+
return create_pglite_db(new PGlite()).db;
|
|
85
|
+
})());
|
|
86
|
+
const resolve_pglet_wasm_db = () => (pglet_wasm_db ??= create_pglet_instance().then((pglet) => create_pglet_db_driver(pglet).db));
|
|
87
|
+
/**
|
|
88
|
+
* Create a PGlite (in-memory) database factory for tests.
|
|
89
|
+
*
|
|
90
|
+
* Always enabled — needs the optional `@electric-sql/pglite` peer installed.
|
|
91
|
+
* Shares one PGlite WASM instance across the PGlite factories this module
|
|
92
|
+
* builds; each `create()` resets the schema via `DROP SCHEMA public CASCADE`
|
|
93
|
+
* instead of paying the cold start again.
|
|
94
|
+
*
|
|
95
|
+
* @param init_schema - callback to initialize the database schema
|
|
96
|
+
*/
|
|
97
|
+
export const create_pglite_factory = (init_schema) => create_shared_instance_factory('pglite', resolve_pglite_db, init_schema);
|
|
98
|
+
/**
|
|
99
|
+
* Create a pglet-wasm (in-memory) database factory for tests.
|
|
100
|
+
*
|
|
101
|
+
* Always enabled — needs the optional `@fuzdev/pglet-wasm` peer installed.
|
|
102
|
+
* Shares one pglet instance across the pglet-wasm factories this module
|
|
103
|
+
* builds, created with fuz_app's value coercion (`PGLET_COERCION`); each
|
|
104
|
+
* `create()` resets the schema via `DROP SCHEMA public CASCADE`.
|
|
105
|
+
*
|
|
106
|
+
* @param init_schema - callback to initialize the database schema
|
|
107
|
+
*/
|
|
108
|
+
export const create_pglet_wasm_factory = (init_schema) => create_shared_instance_factory('pglet-wasm', resolve_pglet_wasm_db, init_schema);
|
|
109
|
+
// The builder `create_default_db_factory` uses, `null` for pglet-wasm.
|
|
110
|
+
let default_db_factory_builder = null;
|
|
111
|
+
/**
|
|
112
|
+
* Install the builder `create_default_db_factory` uses, so suites written
|
|
113
|
+
* against the default run against another driver without being edited —
|
|
114
|
+
* `create_pglite_factory` to run them on PGlite. Pass `null` to restore
|
|
115
|
+
* pglet-wasm.
|
|
63
116
|
*
|
|
64
117
|
* The slot is read when a factory is built, not when it creates a database,
|
|
65
|
-
* so install before the first `
|
|
118
|
+
* so install before the first `create_default_db_factory` call — a vitest
|
|
66
119
|
* `setupFiles` entry, which runs ahead of every test file's imports, is the
|
|
67
120
|
* shape fuz_app's own `db` project uses. A factory built earlier (including
|
|
68
121
|
* the module-level fallback in `testing/app_server.ts`) keeps the driver it
|
|
69
122
|
* was built with, and uninstalling does not revert it.
|
|
70
123
|
*
|
|
71
|
-
* @param create_factory - the builder to install, or `null` to
|
|
124
|
+
* @param create_factory - the builder to install, or `null` to restore the default
|
|
125
|
+
* @returns the builder this replaced (`null` for pglet-wasm), so a caller can put it back
|
|
72
126
|
*/
|
|
73
|
-
export const
|
|
74
|
-
|
|
127
|
+
export const set_default_db_factory = (create_factory) => {
|
|
128
|
+
const previous = default_db_factory_builder;
|
|
129
|
+
default_db_factory_builder = create_factory;
|
|
130
|
+
return previous;
|
|
75
131
|
};
|
|
76
132
|
/**
|
|
77
|
-
* Create
|
|
78
|
-
*
|
|
79
|
-
* Always enabled — no external dependencies required.
|
|
80
|
-
* Shares a single PGlite WASM instance across the PGlite factories this module builds.
|
|
81
|
-
* Subsequent `create()` calls reset the schema via `DROP SCHEMA public CASCADE`
|
|
82
|
-
* instead of paying the WASM cold-start cost again.
|
|
133
|
+
* Create the default in-memory database factory for tests: pglet-wasm, or the
|
|
134
|
+
* builder `set_default_db_factory` installed.
|
|
83
135
|
*
|
|
84
|
-
*
|
|
85
|
-
* `
|
|
136
|
+
* The factory fuz_app's own test helpers fall back to when a suite passes none
|
|
137
|
+
* (`create_test_app_server`, `describe_rate_limiting_tests`,
|
|
138
|
+
* `describe_sse_route_tests`). Call `create_pglite_factory` or
|
|
139
|
+
* `create_pglet_wasm_factory` directly to pin a driver.
|
|
86
140
|
*
|
|
87
141
|
* @param init_schema - callback to initialize the database schema
|
|
88
|
-
* @param options - `substitutable: false` pins this call site to PGlite
|
|
89
142
|
*/
|
|
90
|
-
export const
|
|
91
|
-
if (substitute_db_factory && options?.substitutable !== false) {
|
|
92
|
-
return substitute_db_factory(init_schema);
|
|
93
|
-
}
|
|
94
|
-
return {
|
|
95
|
-
name: 'pglite',
|
|
96
|
-
skip: false,
|
|
97
|
-
async create() {
|
|
98
|
-
if (module_db) {
|
|
99
|
-
await reset_pglite(module_db);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
const { PGlite } = await import('@electric-sql/pglite');
|
|
103
|
-
const pglite = new PGlite();
|
|
104
|
-
module_db = create_pglite_db(pglite).db;
|
|
105
|
-
}
|
|
106
|
-
await init_schema(module_db);
|
|
107
|
-
return module_db;
|
|
108
|
-
},
|
|
109
|
-
async close() {
|
|
110
|
-
// No-op: the instance is the module-level cache above, so it lives as long
|
|
111
|
-
// as this module stays loaded — under the `db` project's `isolate: false` +
|
|
112
|
-
// `fileParallelism: false` that is the whole run. Nothing frees the PGlite
|
|
113
|
-
// instance earlier.
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
};
|
|
143
|
+
export const create_default_db_factory = (init_schema) => (default_db_factory_builder ?? create_pglet_wasm_factory)(init_schema);
|
|
117
144
|
/**
|
|
118
145
|
* Create a pg (PostgreSQL) database factory for tests.
|
|
119
146
|
*
|
|
120
|
-
* Skipped when `test_url` is not provided.
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* For full clean-slate behavior (recommended), call `drop_auth_schema(db)`
|
|
126
|
-
* at the start of `init_schema` before running migrations. This handles
|
|
127
|
-
* upstream schema changes that go beyond adding new tables/columns.
|
|
147
|
+
* Skipped when `test_url` is not provided. Each `create()` opens a pool,
|
|
148
|
+
* resets the `public` schema (`reset_public_schema`) and runs `init_schema` —
|
|
149
|
+
* the lifecycle every factory here shares, so a persistent test database never
|
|
150
|
+
* carries stale DDL or tracker rows from an earlier run or another suite's
|
|
151
|
+
* schema. Point `test_url` at a database used only for tests.
|
|
128
152
|
*
|
|
129
153
|
* @param init_schema - callback to initialize the database schema
|
|
130
154
|
* @param test_url - PostgreSQL connection URL (e.g. from `TEST_DATABASE_URL`)
|
|
@@ -166,17 +190,14 @@ export const create_pg_factory = (init_schema, test_url) => {
|
|
|
166
190
|
pool_ref = pool;
|
|
167
191
|
const { db } = create_pg_db(pool);
|
|
168
192
|
try {
|
|
169
|
-
|
|
170
|
-
// tables. Prevents stale tracker rows from skipping migrations
|
|
171
|
-
// when DDL changes between test sessions. Migrations use
|
|
172
|
-
// IF NOT EXISTS guards, so re-running is safe.
|
|
173
|
-
await db.query('DROP TABLE IF EXISTS schema_version');
|
|
193
|
+
await reset_public_schema(db);
|
|
174
194
|
await init_schema(db);
|
|
175
195
|
}
|
|
176
196
|
catch (error) {
|
|
177
197
|
await pool.end();
|
|
178
|
-
|
|
179
|
-
|
|
198
|
+
// 3D000 invalid_catalog_name — the database itself is missing, not
|
|
199
|
+
// something a migration referenced
|
|
200
|
+
if (pg_error_code(error) === '3D000') {
|
|
180
201
|
const db_name = test_url.split('/').pop()?.split('?')[0] ?? 'test_db';
|
|
181
202
|
throw new Error(`Database "${db_name}" does not exist. Create it with: createdb ${db_name}`);
|
|
182
203
|
}
|
|
@@ -219,24 +240,6 @@ export const auth_truncate_tables = [
|
|
|
219
240
|
* touch audit logging don't need to truncate it.
|
|
220
241
|
*/
|
|
221
242
|
export const auth_integration_truncate_tables = [...auth_truncate_tables, 'audit_log'];
|
|
222
|
-
/**
|
|
223
|
-
* Reset the entire `public` schema for a clean slate before re-migration.
|
|
224
|
-
*
|
|
225
|
-
* Recommended at the start of `init_schema` callbacks for `create_pg_factory`.
|
|
226
|
-
* Persistent test databases accumulate stale DDL across fuz_app versions;
|
|
227
|
-
* `DROP SCHEMA public CASCADE; CREATE SCHEMA public` wipes every table, type,
|
|
228
|
-
* and sequence regardless of namespace, so migrations always run against a
|
|
229
|
-
* truly empty database. Drift-proof — unlike a hand-maintained drop list it
|
|
230
|
-
* needs no upkeep when the schema gains a table. Despite the historical name,
|
|
231
|
-
* this resets the whole schema, not just auth tables (the only documented use
|
|
232
|
-
* is clean-slate re-migration, which always wanted a full reset).
|
|
233
|
-
*
|
|
234
|
-
* @mutates db - drops and recreates the `public` schema; all tables gone.
|
|
235
|
-
*/
|
|
236
|
-
export const drop_auth_schema = async (db) => {
|
|
237
|
-
await db.query('DROP SCHEMA public CASCADE');
|
|
238
|
-
await db.query('CREATE SCHEMA public');
|
|
239
|
-
};
|
|
240
243
|
/**
|
|
241
244
|
* Create a `describe_db` function bound to specific factories and truncate tables.
|
|
242
245
|
*
|
|
@@ -4,7 +4,7 @@ import './assert_dev_env.js';
|
|
|
4
4
|
*
|
|
5
5
|
* `describe_standard_integration_tests` creates a composable test suite that
|
|
6
6
|
* exercises the full middleware stack (origin, session, bearer_auth, request_context)
|
|
7
|
-
* against a real
|
|
7
|
+
* against a real database. Consumers call it with their route factory and
|
|
8
8
|
* session config — all auth route tests come for free.
|
|
9
9
|
*
|
|
10
10
|
* Tests use `stub_password_deps` (deterministic hashing, no Argon2 overhead).
|
|
@@ -16,7 +16,8 @@ export interface RateLimitingTestOptions {
|
|
|
16
16
|
/** Optional overrides for `AppServerOptions`. */
|
|
17
17
|
app_options?: SuiteAppOptions;
|
|
18
18
|
/**
|
|
19
|
-
* Database factories to run tests against. Default:
|
|
19
|
+
* Database factories to run tests against. Default: the default factory
|
|
20
|
+
* (`create_default_db_factory`) only.
|
|
20
21
|
*/
|
|
21
22
|
db_factories?: Array<DbFactory>;
|
|
22
23
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate_limiting.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rate_limiting.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA0B7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIvD,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAIhE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B
|
|
1
|
+
{"version":3,"file":"rate_limiting.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rate_limiting.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA0B7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIvD,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAIhE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACvC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,wDAAwD;IACxD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,uBAAuB,CAAC;CACxC;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,uBAAuB,KAAG,IAqK/E,CAAC"}
|
|
@@ -25,7 +25,7 @@ import { RateLimiter } from '../rate_limiter.js';
|
|
|
25
25
|
import { RateLimitError } from '../http/error_schemas.js';
|
|
26
26
|
import { auth_migration_ns } from '../auth/migrations.js';
|
|
27
27
|
import { create_test_app } from './app_server.js';
|
|
28
|
-
import {
|
|
28
|
+
import { create_default_db_factory, create_describe_db, auth_integration_truncate_tables } from './db.js';
|
|
29
29
|
import { find_auth_route, assert_rate_limit_retry_after_header } from './integration_helpers.js';
|
|
30
30
|
import { run_migrations } from '../db/migrate.js';
|
|
31
31
|
/**
|
|
@@ -49,7 +49,7 @@ export const describe_rate_limiting_tests = (options) => {
|
|
|
49
49
|
const init_schema = async (db) => {
|
|
50
50
|
await run_migrations(db, [auth_migration_ns]);
|
|
51
51
|
};
|
|
52
|
-
const factories = options.db_factories ?? [
|
|
52
|
+
const factories = options.db_factories ?? [create_default_db_factory(init_schema)];
|
|
53
53
|
const describe_db = create_describe_db(factories, auth_integration_truncate_tables);
|
|
54
54
|
/** Create a tight rate limiter for testing — low attempt count, long window. */
|
|
55
55
|
const create_test_rate_limiter = () => new RateLimiter({ max_attempts, window_ms: 60_000, cleanup_interval_ms: 0 });
|
|
@@ -14,10 +14,18 @@ import './assert_dev_env.js';
|
|
|
14
14
|
* so a label set / ordering drift (e.g. `cell_visibility`) is a gated fact,
|
|
15
15
|
* not invisible
|
|
16
16
|
*
|
|
17
|
-
* Designed for `pg_catalog` introspection —
|
|
18
|
-
*
|
|
17
|
+
* Designed for `pg_catalog` introspection — it runs on PostgreSQL, PGlite and
|
|
18
|
+
* pglet. The snapshot is fully deterministic: every collection sorts by
|
|
19
19
|
* a stable key and excludes time-varying fields like `applied_at`.
|
|
20
20
|
*
|
|
21
|
+
* Index and constraint definitions are compared as the engine renders them,
|
|
22
|
+
* so both sides of a parity comparison need engines that render alike. pglet
|
|
23
|
+
* leaves an index's modifiers out of `pg_indexes.indexdef` — per-key sort
|
|
24
|
+
* direction, `NULLS` placement, operator classes, `NULLS NOT DISTINCT` — so a
|
|
25
|
+
* pglet snapshot diffed against a PostgreSQL one reports every index that
|
|
26
|
+
* uses one, with identical DDL on both sides. Take both snapshots on
|
|
27
|
+
* PostgreSQL.
|
|
28
|
+
*
|
|
21
29
|
* Paired with `testing/schema_parity.ts` for comparison + assertion helpers.
|
|
22
30
|
*
|
|
23
31
|
* @module
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema_introspect.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/schema_introspect.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B
|
|
1
|
+
{"version":3,"file":"schema_introspect.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/schema_introspect.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,cAAc;;;;;;iBAWzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,qCAAqC;AACrC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;iBAOxB,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,gBAAgB;;iBAE3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;iBAG3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;iBAOzB,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB;;;;iBAOhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE1E;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;iBAE3B,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GAAU,IAAI,EAAE,KAAG,OAAO,CAAC,gBAAgB,CAa9E,CAAC;AAEF,kDAAkD;AAClD,MAAM,WAAW,0BAA0B;IAC1C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChD;AA8DD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GACjC,IAAI,EAAE,EACN,UAAS,0BAA+B,KACtC,OAAO,CAAC,cAAc,CAyHxB,CAAC"}
|
|
@@ -14,10 +14,18 @@ import './assert_dev_env.js';
|
|
|
14
14
|
* so a label set / ordering drift (e.g. `cell_visibility`) is a gated fact,
|
|
15
15
|
* not invisible
|
|
16
16
|
*
|
|
17
|
-
* Designed for `pg_catalog` introspection —
|
|
18
|
-
*
|
|
17
|
+
* Designed for `pg_catalog` introspection — it runs on PostgreSQL, PGlite and
|
|
18
|
+
* pglet. The snapshot is fully deterministic: every collection sorts by
|
|
19
19
|
* a stable key and excludes time-varying fields like `applied_at`.
|
|
20
20
|
*
|
|
21
|
+
* Index and constraint definitions are compared as the engine renders them,
|
|
22
|
+
* so both sides of a parity comparison need engines that render alike. pglet
|
|
23
|
+
* leaves an index's modifiers out of `pg_indexes.indexdef` — per-key sort
|
|
24
|
+
* direction, `NULLS` placement, operator classes, `NULLS NOT DISTINCT` — so a
|
|
25
|
+
* pglet snapshot diffed against a PostgreSQL one reports every index that
|
|
26
|
+
* uses one, with identical DDL on both sides. Take both snapshots on
|
|
27
|
+
* PostgreSQL.
|
|
28
|
+
*
|
|
21
29
|
* Paired with `testing/schema_parity.ts` for comparison + assertion helpers.
|
|
22
30
|
*
|
|
23
31
|
* @module
|
|
@@ -187,11 +195,11 @@ export const query_schema_snapshot = async (db, options = {}) => {
|
|
|
187
195
|
WHERE schemaname = $1
|
|
188
196
|
ORDER BY tablename ASC, indexname ASC`, [schema]);
|
|
189
197
|
// Constraints — pg_get_constraintdef produces a canonical text rendering.
|
|
190
|
-
// Skip NOT NULL constraints (`contype = 'n'`):
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
//
|
|
198
|
+
// Skip NOT NULL constraints (`contype = 'n'`): a named `pg_constraint` row
|
|
199
|
+
// per NOT NULL column is something an engine may or may not catalog
|
|
200
|
+
// (PostgreSQL 18, PGlite 0.5 and pglet 0.1 each do), and nullability is
|
|
201
|
+
// already captured per-column by `is_nullable` — including the rows would
|
|
202
|
+
// report an engine-cataloging difference as drift between two backends.
|
|
195
203
|
const constraint_rows = await db.query(`SELECT c.conrelid::regclass::text AS table_name,
|
|
196
204
|
c.conname,
|
|
197
205
|
c.contype::text,
|
|
@@ -41,7 +41,7 @@ export interface SseRouteTestOptions {
|
|
|
41
41
|
create_route_specs: (ctx: AppServerContext) => Array<RouteSpec>;
|
|
42
42
|
/** Optional overrides for `AppServerOptions`. */
|
|
43
43
|
app_options?: SuiteAppOptions;
|
|
44
|
-
/** Database factories to run tests against. Default:
|
|
44
|
+
/** Database factories to run tests against. Default: the default factory (`create_default_db_factory`) only. */
|
|
45
45
|
db_factories?: Array<DbFactory>;
|
|
46
46
|
/**
|
|
47
47
|
* Backend audit event callback — threaded to `create_test_app_server`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,oBAAoB,CAAC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,
|
|
1
|
+
{"version":3,"file":"sse_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/sse_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAmB7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,oBAAoB,CAAC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpE,OAAO,EAIN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAO1B,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IACnC,4CAA4C;IAC5C,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,qDAAqD;IACrD,kBAAkB,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IAChE,iDAAiD;IACjD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,gHAAgH;IAChH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAChD;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,8BAA8B;IAC9B,MAAM,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;CAChC;AAmDD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,GAAI,SAAS,mBAAmB,KAAG,IAkIvE,CAAC"}
|
|
@@ -18,7 +18,7 @@ import { SSE_CONNECTED_COMMENT } from '../realtime/sse_constants.js';
|
|
|
18
18
|
import { ROLE_ADMIN } from '../auth/role_schema.js';
|
|
19
19
|
import { create_audit_emitter } from '../auth/audit_emitter.js';
|
|
20
20
|
import { create_test_app } from './app_server.js';
|
|
21
|
-
import {
|
|
21
|
+
import { create_default_db_factory } from './db.js';
|
|
22
22
|
import { find_route_spec, pick_auth_headers } from './integration_helpers.js';
|
|
23
23
|
import { rpc_call, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup } from './rpc_helpers.js';
|
|
24
24
|
import { run_migrations } from '../db/migrate.js';
|
|
@@ -74,7 +74,7 @@ export const describe_sse_route_tests = (options) => {
|
|
|
74
74
|
const init_schema = async (db) => {
|
|
75
75
|
await run_migrations(db, [auth_migration_ns]);
|
|
76
76
|
};
|
|
77
|
-
const factories = options.db_factories ?? [
|
|
77
|
+
const factories = options.db_factories ?? [create_default_db_factory(init_schema)];
|
|
78
78
|
for (const factory of factories) {
|
|
79
79
|
const describe_fn = factory.skip ? describe.skip : describe;
|
|
80
80
|
describe_fn(`SSE validation (${factory.name})`, () => {
|
package/dist/testing/stubs.js
CHANGED
|
@@ -160,7 +160,7 @@ export const create_stub_app_deps = () => ({
|
|
|
160
160
|
* @param options - the deps and `close` to use in place of the defaults
|
|
161
161
|
*/
|
|
162
162
|
export const create_stub_app_backend = (options) => ({
|
|
163
|
-
db_type: '
|
|
163
|
+
db_type: 'pglet-memory',
|
|
164
164
|
db_name: 'test',
|
|
165
165
|
migration_results: [],
|
|
166
166
|
close: options?.close ?? (async () => { }),
|
|
@@ -17,9 +17,11 @@ export interface WsTransportOptions {
|
|
|
17
17
|
* Origin header for the upgrade. Backends running with
|
|
18
18
|
* `ALLOWED_ORIGINS=http://localhost:*` accept `http://localhost:<port>`.
|
|
19
19
|
* Defaults to `base_url` — acceptable because cross-process tests
|
|
20
|
-
* always run against `localhost`.
|
|
20
|
+
* always run against `localhost`. `null` sends no `Origin` at all, which a
|
|
21
|
+
* daemon-token upgrade needs: both spines discard a daemon token (and a
|
|
22
|
+
* bearer token) presented in a browser context.
|
|
21
23
|
*/
|
|
22
|
-
readonly origin?: string;
|
|
24
|
+
readonly origin?: string | null;
|
|
23
25
|
/**
|
|
24
26
|
* Optional per-call default for `wait_for` timeouts. Falls back to
|
|
25
27
|
* `WS_CLIENT_DEFAULT_TIMEOUT_MS` if omitted.
|