Skip to content

Commit d61ff15

Browse files
committed
test(driver-sql): pin the NODE_ENV=production auto-migrate guard with a safe drift
The case staged relax_not_null, which ADR-0113 made needs_confirm, so auto-reconcile never applied it with or without the guard, and it asserted no warning. It now stages a runtime-token column DEFAULT (drop_column_default, category safe), asserts the DEFAULT survives and the production warning is logged, beside a development control showing the same boot removes it. Claude-Session: https://claude.ai/code/session_01XrcLWFkToZjHv2DJDAHhz4 Co-authored-by: Claude <noreply@anthropic.com>
1 parent ea08ce5 commit d61ff15

1 file changed

Lines changed: 46 additions & 3 deletions

File tree

‎packages/drivers/driver-sql/src/sql-driver-schema-drift.test.ts‎

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,58 @@ describe('SqlDriver managed-schema drift (#2186)', () => {
199199
expect(warnedDrift).toMatch(/os migrate/);
200200
});
201201

202+
// The production guard is pinned with a `safe` drift — the only category
203+
// auto-reconcile applies — so the guard is the sole reason it stays put:
204+
// a pre-#4560 build wrote the `current_user` token as the column DEFAULT,
205+
// and `drop_column_default` removes it. The control below proves the same
206+
// boot applies it outside production.
207+
const PRODUCTION_GUARD_WARNING = "[schema-drift] autoMigrate='safe' is ignored under NODE_ENV=production";
208+
const seedTokenDefaultTable = async () => {
209+
await knexInstance.schema.createTable('biz_unit', (t: any) => {
210+
t.string('id').primary();
211+
t.timestamp('created_at');
212+
t.timestamp('updated_at');
213+
t.string('owner').defaultTo('current_user');
214+
});
215+
};
216+
const tokenDefaultMeta = [{ name: 'biz_unit', fields: { owner: { type: 'string', defaultValue: 'current_user' } } }];
217+
const warned = (driver: SqlDriver): string =>
218+
((driver as any).logger.warn as ReturnType<typeof vi.fn>).mock.calls.map((c: any[]) => String(c[0])).join('\n');
219+
220+
it('applies the safe drop_column_default drift outside production (control for the guard below)', async () => {
221+
const prev = process.env.NODE_ENV;
222+
process.env.NODE_ENV = 'development';
223+
try {
224+
const driver = makeDriver({ autoMigrate: 'safe' });
225+
await seedTokenDefaultTable();
226+
await driver.initObjects(tokenDefaultMeta);
227+
228+
const info = await knexInstance('biz_unit').columnInfo();
229+
expect(info.owner.defaultValue ?? null).toBeNull();
230+
expect(await driver.detectManagedDrift()).toHaveLength(0);
231+
expect(warned(driver)).not.toContain(PRODUCTION_GUARD_WARNING);
232+
} finally {
233+
process.env.NODE_ENV = prev;
234+
}
235+
});
236+
202237
it('is force-disabled under NODE_ENV=production (warns, does not alter)', async () => {
203238
const prev = process.env.NODE_ENV;
204239
process.env.NODE_ENV = 'production';
205240
try {
206241
const driver = makeDriver({ autoMigrate: 'safe' });
207-
await seedLegacyTable(driver);
208-
await driver.initObjects(relaxedMeta);
242+
await seedTokenDefaultTable();
243+
await driver.initObjects(tokenDefaultMeta);
244+
245+
// Unchanged: the token DEFAULT the control above sees removed is still there...
209246
const info = await knexInstance('biz_unit').columnInfo();
210-
expect(info.region_code.nullable).toBe(false); // unchanged
247+
expect(String(info.owner.defaultValue)).toContain('current_user');
248+
// ...the drift is still the `safe` one auto-reconcile would have applied...
249+
const d = (await driver.detectManagedDrift()).find((x) => x.column === 'owner');
250+
expect(d?.category).toBe('safe');
251+
expect(d?.op.type).toBe('drop_column_default');
252+
// ...and the boot said why.
253+
expect(warned(driver)).toContain(PRODUCTION_GUARD_WARNING);
211254
} finally {
212255
process.env.NODE_ENV = prev;
213256
}

0 commit comments

Comments
 (0)