@endora-commerce/test-kit 0.100.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/LICENSE +21 -0
- package/README.md +108 -0
- package/dist/database/index.d.ts +17 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +17 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/lease.d.ts +115 -0
- package/dist/database/lease.d.ts.map +1 -0
- package/dist/database/lease.js +204 -0
- package/dist/database/lease.js.map +1 -0
- package/dist/database/provision.d.ts +135 -0
- package/dist/database/provision.d.ts.map +1 -0
- package/dist/database/provision.js +457 -0
- package/dist/database/provision.js.map +1 -0
- package/dist/database/run-isolation.d.ts +356 -0
- package/dist/database/run-isolation.d.ts.map +1 -0
- package/dist/database/run-isolation.js +490 -0
- package/dist/database/run-isolation.js.map +1 -0
- package/dist/server/compose-test-server.d.ts +251 -0
- package/dist/server/compose-test-server.d.ts.map +1 -0
- package/dist/server/compose-test-server.js +359 -0
- package/dist/server/compose-test-server.js.map +1 -0
- package/dist/server/composition.d.ts +112 -0
- package/dist/server/composition.d.ts.map +1 -0
- package/dist/server/composition.js +32 -0
- package/dist/server/composition.js.map +1 -0
- package/dist/server/index.d.ts +13 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +12 -0
- package/dist/server/index.js.map +1 -0
- package/dist/support/entity-index.d.ts +91 -0
- package/dist/support/entity-index.d.ts.map +1 -0
- package/dist/support/entity-index.js +56 -0
- package/dist/support/entity-index.js.map +1 -0
- package/dist/support/index.d.ts +134 -0
- package/dist/support/index.d.ts.map +1 -0
- package/dist/support/index.js +153 -0
- package/dist/support/index.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-invocation test isolation (issue #189).
|
|
3
|
+
*
|
|
4
|
+
* ## The defect
|
|
5
|
+
*
|
|
6
|
+
* Isolation in this suite is **per database and per Redis instance**, not per
|
|
7
|
+
* invocation. `helpers/test-server.ts` truncates `SEEDED_TABLES`, composes a
|
|
8
|
+
* server and seeds fixtures on every booting file, so a second `vitest run`
|
|
9
|
+
* against the same `b2b_test` lands its truncate in the middle of the first
|
|
10
|
+
* one's setup. Three agents hit that in one day and every one of them read it
|
|
11
|
+
* as a real failure first: `Hook timed out in 30000ms` in `beforeAll`, then
|
|
12
|
+
* `Cannot read properties of undefined (reading 'app')` in the teardown that
|
|
13
|
+
* never got a handle; a shifting subset of one directory failing with 403s and
|
|
14
|
+
* missing fixtures, a different subset each run; and a role created through the
|
|
15
|
+
* API reading back `null` because another invocation had truncated
|
|
16
|
+
* `admin_roles` between the write and the read.
|
|
17
|
+
*
|
|
18
|
+
* The cost is not the flakes. It is that a false failure is indistinguishable
|
|
19
|
+
* from a true one, so the failure is either chased for an hour or — worse —
|
|
20
|
+
* dismissed as "probably the shared database" when it is real.
|
|
21
|
+
*
|
|
22
|
+
* ## The answer
|
|
23
|
+
*
|
|
24
|
+
* A run gets its **own** database and its **own** Redis logical database,
|
|
25
|
+
* automatically. The escape hatch already existed and was manual — every agent
|
|
26
|
+
* that got clean results set `TEST_DATABASE_URL=…/b2b_<something>_test` by hand
|
|
27
|
+
* — so this makes the thing that already worked the default rather than a thing
|
|
28
|
+
* you have to know. (156 hand-named test databases were standing on the
|
|
29
|
+
* developer machine that reported this, 4.1 GB of them, which is the other half
|
|
30
|
+
* of what "manual" costs.)
|
|
31
|
+
*
|
|
32
|
+
* **Per invocation, not per file.** The harness's per-file cost already
|
|
33
|
+
* dominates the suite (issue #72: a truncate is 1149 ms per composition), so a
|
|
34
|
+
* fresh database per *file* would be unaffordable. Per invocation is the
|
|
35
|
+
* granularity the defect actually has.
|
|
36
|
+
*
|
|
37
|
+
* **Cloned, not migrated.** `<base>_tpl` is the migrated template — created and
|
|
38
|
+
* brought up to date once, under an advisory lock so concurrent invocations
|
|
39
|
+
* cannot race on it — and each run is `create database … template <base>_tpl`,
|
|
40
|
+
* which is a file copy: 0.2 s warm against the 39 MB this schema occupies.
|
|
41
|
+
* Nothing about the migration coverage changes: the template is still migrated
|
|
42
|
+
* from scratch on a fresh cluster, which is what the CI job's comment about
|
|
43
|
+
* exercising the whole chain is protecting.
|
|
44
|
+
*
|
|
45
|
+
* **And it is the template of this run's migration set, not the machine's.**
|
|
46
|
+
* `<base>_tpl_<digest>` (issue #289): the digest covers the ordered migration
|
|
47
|
+
* class names *and* the content of every file that writes into a template, so
|
|
48
|
+
* two branches that differ anywhere a template can see get two templates, and
|
|
49
|
+
* two trees that agree share one and migrate once between them. Before that
|
|
50
|
+
* there was one `<base>_tpl` and a check comparing applied migration *names*
|
|
51
|
+
* against the configured order — which catches a branch that added a migration
|
|
52
|
+
* and cannot catch one that changed what a migration of the same name does.
|
|
53
|
+
* See `templateDigest`. What the name claims is checked against the template's
|
|
54
|
+
* own provenance comment and against `mikro_orm_migrations` before anything is
|
|
55
|
+
* cloned; a template that cannot account for itself is rebuilt, never used.
|
|
56
|
+
*
|
|
57
|
+
* **Names satisfy the existing guard.** `runDatabaseName` refuses to produce a
|
|
58
|
+
* name `TEST_DATABASE_NAME_PATTERN` would not accept, so the harness's refusal
|
|
59
|
+
* to truncate a non-test database is untouched — not loosened, not bypassed.
|
|
60
|
+
* That predicate lives here now and every caller imports it, so there is
|
|
61
|
+
* one spelling of it rather than three.
|
|
62
|
+
*
|
|
63
|
+
* **Redis by logical database index, not by key prefix.** Every Redis client in
|
|
64
|
+
* this tree — 8 in `src/`, 40-odd in `test/` — is built as
|
|
65
|
+
* `new Redis(process.env['REDIS_URL'] ?? 'redis://localhost:6379')`, and
|
|
66
|
+
* ioredis reads the index off the DSN path. Pointing `REDIS_URL` at
|
|
67
|
+
* `…/<index>` therefore isolates all of them, including BullMQ, with no call
|
|
68
|
+
* site changed. A key prefix would have to be threaded through every one of
|
|
69
|
+
* those constructions, and `keys(pattern)` — which `dropStaleCaches` uses — is
|
|
70
|
+
* not a key-taking command as far as ioredis is concerned, so a prefixed client
|
|
71
|
+
* would still scan and delete another run's keys.
|
|
72
|
+
*
|
|
73
|
+
* ## Cleanup
|
|
74
|
+
*
|
|
75
|
+
* The run database is dropped by the lease's own release. A **crashed**
|
|
76
|
+
* run cannot run its teardown, so every invocation also sweeps: run databases
|
|
77
|
+
* carry their creation instant in their name, and one older than
|
|
78
|
+
* `STALE_RUN_DATABASE_MS` with no connection to it is dropped, at most
|
|
79
|
+
* `SWEEP_LIMIT` per invocation. Only names this module generated are ever
|
|
80
|
+
* considered — the 156 hand-named databases and anything else on the cluster
|
|
81
|
+
* are outside the pattern by construction, and `strandedRunDatabases` is
|
|
82
|
+
* unit-tested on exactly that. Redis leases expire on their own TTL.
|
|
83
|
+
*
|
|
84
|
+
* **Templates are collected too**, and have to be: one per migration set means
|
|
85
|
+
* one left behind whenever a branch gains a migration or is rebased.
|
|
86
|
+
* `staleTemplates` is the other half of the bargain keying them made — same
|
|
87
|
+
* three conditions, with the age read from the template's provenance rather
|
|
88
|
+
* than from its name, because what matters about a template is when it was last
|
|
89
|
+
* *used*.
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* A database name that says "this database exists to be wiped".
|
|
93
|
+
*
|
|
94
|
+
* The one spelling of the judgement. `assertTestDatabaseUrl` applies it before
|
|
95
|
+
* a run touches anything, `runDatabaseName` refuses to emit a name that fails
|
|
96
|
+
* it, and the application's own dev-seed guard keeps its copy pinned to this one
|
|
97
|
+
* by a test of its own — `backend/src/seeds/dev-seed-guard.ts` is `src/`, so it
|
|
98
|
+
* cannot import a test's module and has to re-spell the regex.
|
|
99
|
+
*/
|
|
100
|
+
export declare const TEST_DATABASE_NAME_PATTERN: RegExp;
|
|
101
|
+
/** How many hex characters of the digest a template name carries. */
|
|
102
|
+
export declare const TEMPLATE_DIGEST_LENGTH = 12;
|
|
103
|
+
/** How old a run database must be before a sweep may take it for stranded. */
|
|
104
|
+
export declare const STALE_RUN_DATABASE_MS: number;
|
|
105
|
+
/**
|
|
106
|
+
* How long a template survives with nothing using it.
|
|
107
|
+
*
|
|
108
|
+
* Templates are keyed by the migration set, so a branch that adds a migration
|
|
109
|
+
* leaves the previous set's template behind the moment it is rebased or merged.
|
|
110
|
+
* A day of nobody asking for a set is the point at which keeping its 19 MB
|
|
111
|
+
* costs more than the one migration pass rebuilding it would.
|
|
112
|
+
*/
|
|
113
|
+
export declare const STALE_TEMPLATE_MS: number;
|
|
114
|
+
/** How many stranded databases one invocation drops, so a sweep cannot become the run's cost. */
|
|
115
|
+
export declare const SWEEP_LIMIT = 25;
|
|
116
|
+
/** The environment variable that turns per-invocation isolation off. */
|
|
117
|
+
export declare const ISOLATION_ENV = "BACKEND_TEST_ISOLATION";
|
|
118
|
+
/** Set this to keep the run database after the run, for a post-mortem. */
|
|
119
|
+
export declare const KEEP_DATABASE_ENV = "BACKEND_TEST_KEEP_DATABASE";
|
|
120
|
+
/**
|
|
121
|
+
* The base DSN, exported to the workers by the lease on the isolated
|
|
122
|
+
* path only.
|
|
123
|
+
*
|
|
124
|
+
* Its **presence is the statement** "this invocation has a migrated template,
|
|
125
|
+
* and a file that needs a database of its own may clone it" — which is what
|
|
126
|
+
* `setupMigratorTestDb` asks. Nothing derives it from the run database's name:
|
|
127
|
+
* a run database is `<base>_r_<stamp>_<token>` and taking the base back out of
|
|
128
|
+
* one would be a second, weaker spelling of `runDatabaseName`.
|
|
129
|
+
*/
|
|
130
|
+
export declare const BASE_DATABASE_URL_ENV = "BACKEND_TEST_BASE_URL";
|
|
131
|
+
/**
|
|
132
|
+
* The template this run was cloned from, exported to the workers alongside it.
|
|
133
|
+
*
|
|
134
|
+
* A name and not a derivation, because since #289 there is more than one
|
|
135
|
+
* template on the cluster and which one is this run's is a fact about the run,
|
|
136
|
+
* not about the base: another invocation may build a template of its own while
|
|
137
|
+
* this one is still going, and a file that re-derived "the template" mid-run
|
|
138
|
+
* would clone whichever set happened to be newest.
|
|
139
|
+
*/
|
|
140
|
+
export declare const TEMPLATE_DATABASE_ENV = "BACKEND_TEST_TEMPLATE";
|
|
141
|
+
export type IsolationMode = 'per-invocation' | 'shared';
|
|
142
|
+
export declare function isolationMode(env?: NodeJS.ProcessEnv): IsolationMode;
|
|
143
|
+
/**
|
|
144
|
+
* Why this run is sharing the base database rather than taking one of its own,
|
|
145
|
+
* or `undefined` when it is not.
|
|
146
|
+
*/
|
|
147
|
+
export declare function sharedDatabaseReason(env: NodeJS.ProcessEnv, baseName: string): 'explicit' | 'name-override' | undefined;
|
|
148
|
+
/** Whether this run keeps its database for a post-mortem instead of dropping it. */
|
|
149
|
+
export declare function keepRunDatabase(env?: NodeJS.ProcessEnv): boolean;
|
|
150
|
+
/**
|
|
151
|
+
* The migrated source every run of *this migration set* is cloned from.
|
|
152
|
+
*
|
|
153
|
+
* The digest is in the name because that is what makes two different migration
|
|
154
|
+
* sets two different databases: a template is shared exactly by the runs whose
|
|
155
|
+
* platform it actually is, and never by the runs that merely share a cluster
|
|
156
|
+
* with it. See `templateDigest` for what "the same set" means, and issue #289
|
|
157
|
+
* for what one shared `<base>_tpl` cost.
|
|
158
|
+
*/
|
|
159
|
+
export declare function templateDatabaseName(base: string, digest: string): string;
|
|
160
|
+
/**
|
|
161
|
+
* The lock every invocation of this base takes before it touches a template.
|
|
162
|
+
*
|
|
163
|
+
* One key for the whole family rather than one per digest: a sweep walks the
|
|
164
|
+
* templates of *other* digests, so it has to exclude an invocation that is
|
|
165
|
+
* half-way through building one. It is also, deliberately, the exact string the
|
|
166
|
+
* pre-#289 code derived its key from, so an invocation running that code still
|
|
167
|
+
* serializes against this one while the two versions coexist on a machine.
|
|
168
|
+
*/
|
|
169
|
+
export declare function templateFamilyName(base: string): string;
|
|
170
|
+
/** The digest a template name carries, or `undefined` for a name this module did not make. */
|
|
171
|
+
export declare function parseTemplateDatabaseName(base: string, name: string): {
|
|
172
|
+
readonly digest: string;
|
|
173
|
+
} | undefined;
|
|
174
|
+
/** What a template is built from: this run's migration order and the sources behind it. */
|
|
175
|
+
export interface TemplateInputs {
|
|
176
|
+
/** The migration class names this run applies, in the order it applies them. */
|
|
177
|
+
readonly migrations: readonly string[];
|
|
178
|
+
/** Every file whose content decides what the migrated template holds. */
|
|
179
|
+
readonly sources: readonly TemplateSource[];
|
|
180
|
+
}
|
|
181
|
+
export interface TemplateSource {
|
|
182
|
+
/** Repository-relative, so two worktrees of the same commit agree. */
|
|
183
|
+
readonly path: string;
|
|
184
|
+
readonly sha256: string;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* What makes two runs' templates the same template.
|
|
188
|
+
*
|
|
189
|
+
* Issue #189 keyed the template on the base database alone and compared the
|
|
190
|
+
* *names* of the applied migrations against this run's order before cloning it.
|
|
191
|
+
* That catches a template another branch added a migration to. It does not
|
|
192
|
+
* catch — and cannot — a branch that changed what a migration of the same name
|
|
193
|
+
* *does*, which is the ordinary shape of two agents iterating on the same
|
|
194
|
+
* feature, and it is how a run whose tree contained no such string failed
|
|
195
|
+
* against a payment method row called `paypal_checkout` seeded from a branch it
|
|
196
|
+
* had never seen (issue #289).
|
|
197
|
+
*
|
|
198
|
+
* So the identity is the whole input: the ordered class names — order included,
|
|
199
|
+
* because a manifest `dependencies` edit reorders migrations without touching
|
|
200
|
+
* one of them — and the content of every file that writes into the template,
|
|
201
|
+
* which is every migration source plus the handful of files that seed the
|
|
202
|
+
* platform invariants. Two trees that agree on all of it share a template and
|
|
203
|
+
* pay one migration pass between them; two that do not cannot collide, because
|
|
204
|
+
* they are not looking at the same database at all.
|
|
205
|
+
*
|
|
206
|
+
* It **throws on an empty input** rather than digesting nothing: every empty
|
|
207
|
+
* input hashes to the same value, so a caller that read no migrations would
|
|
208
|
+
* quietly name the same template as a caller that read all of them — a template
|
|
209
|
+
* of unknown provenance, which is the defect and not a fix for it.
|
|
210
|
+
*/
|
|
211
|
+
export declare function templateDigest(inputs: TemplateInputs): string;
|
|
212
|
+
/** What a template says about itself, in the comment PostgreSQL keeps on the database. */
|
|
213
|
+
export interface TemplateProvenance {
|
|
214
|
+
readonly digest: string;
|
|
215
|
+
/** How many migrations were applied when it was built — a second, cheaper thing to disagree about. */
|
|
216
|
+
readonly migrations: number;
|
|
217
|
+
readonly lastUsedAt: Date;
|
|
218
|
+
}
|
|
219
|
+
export declare function formatTemplateProvenance(provenance: TemplateProvenance): string;
|
|
220
|
+
/**
|
|
221
|
+
* What the template says it is, or `undefined` when it says nothing this
|
|
222
|
+
* version understands.
|
|
223
|
+
*
|
|
224
|
+
* Every "undefined" is a template a run must rebuild rather than clone: an
|
|
225
|
+
* older version's template, a hand-made database that happens to fit the name,
|
|
226
|
+
* one whose build died before it could sign itself. "I cannot tell what this
|
|
227
|
+
* holds" and "this holds the wrong thing" get the same answer on purpose.
|
|
228
|
+
*/
|
|
229
|
+
export declare function parseTemplateProvenance(comment: string | null | undefined): TemplateProvenance | undefined;
|
|
230
|
+
export interface StaleTemplateSelection {
|
|
231
|
+
readonly base: string;
|
|
232
|
+
/** Every database name on the cluster. */
|
|
233
|
+
readonly names: readonly string[];
|
|
234
|
+
readonly busy: ReadonlySet<string>;
|
|
235
|
+
/** This invocation's own template, which is never stale. */
|
|
236
|
+
readonly keep: string;
|
|
237
|
+
/** When each template was last used, from its own provenance comment. */
|
|
238
|
+
readonly lastUsed: ReadonlyMap<string, Date>;
|
|
239
|
+
readonly now: Date;
|
|
240
|
+
readonly maxAgeMs: number;
|
|
241
|
+
readonly limit: number;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* The templates a sweep may drop.
|
|
245
|
+
*
|
|
246
|
+
* Keying templates by their migration set is what stops two branches sharing
|
|
247
|
+
* one; the cost of it is that a branch leaves its set's template behind when it
|
|
248
|
+
* merges, so something has to collect them. Same three conditions as the run
|
|
249
|
+
* database sweep — a name this module generated, nothing connected, nobody
|
|
250
|
+
* using it lately — with the age read from the template's own provenance
|
|
251
|
+
* comment rather than from its name, because a template's useful age is when it
|
|
252
|
+
* was last *used* and not when it was built.
|
|
253
|
+
*
|
|
254
|
+
* A template with no readable provenance is stale immediately. It is a database
|
|
255
|
+
* no run would clone anyway (provisioning rebuilds one it cannot identify), so
|
|
256
|
+
* leaving it costs disk and buys nothing. The pre-#289 `<base>_tpl` is not in
|
|
257
|
+
* the population at all — `parseTemplateDatabaseName` refuses it — because an
|
|
258
|
+
* invocation running older code clones that one *during* its run, and dropping
|
|
259
|
+
* it under such a run would fail it for a reason in nobody's diff.
|
|
260
|
+
*/
|
|
261
|
+
export declare function staleTemplates(input: StaleTemplateSelection): string[];
|
|
262
|
+
export declare function randomRunToken(): string;
|
|
263
|
+
/**
|
|
264
|
+
* `<base>_r_<epoch-seconds base36>_<6 hex>`.
|
|
265
|
+
*
|
|
266
|
+
* The instant is in the name because `pg_database` has no creation timestamp
|
|
267
|
+
* and the sweep needs an age. The random tail is what makes two invocations
|
|
268
|
+
* starting in the same second distinct.
|
|
269
|
+
*/
|
|
270
|
+
export declare function runDatabaseName(base: string, createdAt?: Date, token?: string): string;
|
|
271
|
+
export declare function parseRunDatabaseName(base: string, name: string): {
|
|
272
|
+
readonly createdAt: Date;
|
|
273
|
+
} | undefined;
|
|
274
|
+
export interface StrandedSelection {
|
|
275
|
+
readonly base: string;
|
|
276
|
+
/** Every database name on the cluster. */
|
|
277
|
+
readonly names: readonly string[];
|
|
278
|
+
/** Names with at least one session connected, from `pg_stat_activity`. */
|
|
279
|
+
readonly busy: ReadonlySet<string>;
|
|
280
|
+
/** This invocation's own database, which is never stranded. */
|
|
281
|
+
readonly keep: string;
|
|
282
|
+
readonly now: Date;
|
|
283
|
+
readonly maxAgeMs: number;
|
|
284
|
+
readonly limit: number;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The stranded run databases a sweep may drop.
|
|
288
|
+
*
|
|
289
|
+
* Three conditions, and each one is load-bearing: the name is one this module
|
|
290
|
+
* generated (so no foreign database is ever a candidate), it is older than the
|
|
291
|
+
* threshold (so a live run is not taken for a corpse — the complete suite takes
|
|
292
|
+
* the better part of an hour), and nothing is connected to it right now (a
|
|
293
|
+
* booting file closes the ORM between files, so idleness alone would not be
|
|
294
|
+
* enough, which is why it is `and` rather than `or`).
|
|
295
|
+
*/
|
|
296
|
+
export declare function strandedRunDatabases(input: StrandedSelection): string[];
|
|
297
|
+
/** The same DSN, pointed at another database on the same server. */
|
|
298
|
+
export declare function withDatabase(url: string, database: string): string;
|
|
299
|
+
export declare function databaseNameOf(url: string): string;
|
|
300
|
+
/** The same Redis DSN, pointed at a logical database index. */
|
|
301
|
+
export declare function redisUrlWithDatabase(url: string, index: number): string;
|
|
302
|
+
/** Whether a Redis DSN already names a logical database — an explicit choice this module leaves alone. */
|
|
303
|
+
export declare function redisUrlNamesDatabase(url: string): boolean;
|
|
304
|
+
/** Identifies this invocation in a Redis lease and in the log lines. */
|
|
305
|
+
export declare function runIdentity(): string;
|
|
306
|
+
/**
|
|
307
|
+
* A 32-bit key for `pg_advisory_lock`, derived from the template name so two
|
|
308
|
+
* bases do not serialize against each other. FNV-1a, folded into a signed int.
|
|
309
|
+
*/
|
|
310
|
+
export declare function advisoryLockKey(name: string): number;
|
|
311
|
+
/**
|
|
312
|
+
* Why the migration template cannot be brought forward to this run's migration
|
|
313
|
+
* set by `migrator.up()`, and must be rebuilt from empty instead.
|
|
314
|
+
*/
|
|
315
|
+
export interface TemplateDrift {
|
|
316
|
+
/**
|
|
317
|
+
* `unknown-migration` — a name applied to the template that this run's
|
|
318
|
+
* registry does not contain at all. `out-of-order` — one of this run's own
|
|
319
|
+
* migrations, applied in a position the configured order does not put it in.
|
|
320
|
+
*/
|
|
321
|
+
readonly kind: 'unknown-migration' | 'out-of-order';
|
|
322
|
+
/** The applied migration the judgement is about. */
|
|
323
|
+
readonly name: string;
|
|
324
|
+
/** The migration this run's order has in that position, when there is one. */
|
|
325
|
+
readonly expected?: string;
|
|
326
|
+
/** The whole finding as one line, for the log or for a throw. */
|
|
327
|
+
readonly message: string;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Whether the template is a database this run's migrations could have produced.
|
|
331
|
+
*
|
|
332
|
+
* The template is **long-lived and shared by every branch on the machine**, and
|
|
333
|
+
* it is only ever moved forward by `migrator.up()`, which appends. That is
|
|
334
|
+
* enough exactly when what is already applied is a **prefix** of the order this
|
|
335
|
+
* run configures: then the pending ones land after it, and the result is the
|
|
336
|
+
* order a database migrated from scratch today would have. Anything else —
|
|
337
|
+
* another branch's migration, or one of ours applied somewhere the order does
|
|
338
|
+
* not put it — is a database no `up()` can repair, so it is rebuilt.
|
|
339
|
+
*
|
|
340
|
+
* Both shapes are ordinary here, not exotic. Five agents share one cluster, so
|
|
341
|
+
* a template routinely carries a migration the branch running has never heard
|
|
342
|
+
* of; and `orderMigrations` places a migration by its module's position in the
|
|
343
|
+
* dependency graph, so a migration added anywhere but the last module lands at
|
|
344
|
+
* the **end** of an incrementally-migrated template and in the **middle** of a
|
|
345
|
+
* fresh one.
|
|
346
|
+
*
|
|
347
|
+
* That is not cosmetic. It broke
|
|
348
|
+
* `test/integration/catalog/attributes-migration-parity.test.ts`, which drives
|
|
349
|
+
* the real migrator: umzug reverts the last migration in *configured* order,
|
|
350
|
+
* while the test reads the last one in *applied* (`id`) order, and the two stop
|
|
351
|
+
* agreeing the moment the template stops being a prefix. The test then walked
|
|
352
|
+
* `down()` past its own target, never reached its termination condition, timed
|
|
353
|
+
* out, and left the run database with most of its schema reverted.
|
|
354
|
+
*/
|
|
355
|
+
export declare function templateDrift(applied: readonly string[], expected: readonly string[], templateName?: string): TemplateDrift | undefined;
|
|
356
|
+
//# sourceMappingURL=run-isolation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-isolation.d.ts","sourceRoot":"","sources":["../../src/database/run-isolation.ts"],"names":[],"mappings":"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"}
|