test(24-02): cover buildDriftHistoryRows update/delete/create/no-change cases
- 6 unit tests exercising the pure drift-classification wiring in Route53SyncService - Confirms whole-recordset before/after payloads, not per-field deltas - Confirms CRUD-originated changes still get tagged sync_detected_drift (sync cannot distinguish actor) - Full suite green aside from 2 pre-existing itglue-search.test.ts failures logged in deferred-items.md (unrelated to this plan)
This commit is contained in:
parent
d8c0912f4b
commit
0acf1fa24f
1 changed files with 126 additions and 0 deletions
126
lib/services/route53-sync-service.test.ts
Normal file
126
lib/services/route53-sync-service.test.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/**
|
||||||
|
* lib/services/route53-sync-service.ts unit tests.
|
||||||
|
*
|
||||||
|
* Only buildDriftHistoryRows is exercised here — a pure function taking
|
||||||
|
* hand-constructed NormalizedRecordSet maps, no AWS or Postgres mocking
|
||||||
|
* required (matches the plan's stated test scope for this file).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { buildDriftHistoryRows } from './route53-sync-service';
|
||||||
|
import type { NormalizedRecordSet } from './route53-record-key';
|
||||||
|
|
||||||
|
function makeRecordSet(overrides: Partial<NormalizedRecordSet> = {}): NormalizedRecordSet {
|
||||||
|
return {
|
||||||
|
recordKey: 'Z123:www.example.com.:A:',
|
||||||
|
zoneId: 'Z123',
|
||||||
|
name: 'www.example.com.',
|
||||||
|
type: 'A',
|
||||||
|
setIdentifier: null,
|
||||||
|
ttl: 300,
|
||||||
|
resourceRecords: [{ value: '10.0.0.1' }],
|
||||||
|
aliasTarget: null,
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('buildDriftHistoryRows', () => {
|
||||||
|
it('produces one update row with non-null before/after when TTL changes', () => {
|
||||||
|
const key = 'Z123:www.example.com.:A:';
|
||||||
|
const prev = makeRecordSet({ ttl: 300 });
|
||||||
|
const next = makeRecordSet({ ttl: 600 });
|
||||||
|
|
||||||
|
const rows = buildDriftHistoryRows(
|
||||||
|
new Map([[key, prev]]),
|
||||||
|
new Map([[key, next]]),
|
||||||
|
'Z123'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(rows).toHaveLength(1);
|
||||||
|
expect(rows[0].changeAction).toBe('update');
|
||||||
|
expect(rows[0].zoneId).toBe('Z123');
|
||||||
|
expect(rows[0].recordKey).toBe(key);
|
||||||
|
expect(rows[0].beforeValue).not.toBeNull();
|
||||||
|
expect(rows[0].afterValue).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('produces a delete row with non-null before and null after when the mirror row has no AWS match', () => {
|
||||||
|
const key = 'Z123:gone.example.com.:A:';
|
||||||
|
const prev = makeRecordSet({ recordKey: key, name: 'gone.example.com.' });
|
||||||
|
|
||||||
|
const rows = buildDriftHistoryRows(new Map([[key, prev]]), new Map(), 'Z123');
|
||||||
|
|
||||||
|
expect(rows).toHaveLength(1);
|
||||||
|
expect(rows[0].changeAction).toBe('delete');
|
||||||
|
expect(rows[0].beforeValue).not.toBeNull();
|
||||||
|
expect(rows[0].afterValue).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('produces a create row with null before and non-null after when AWS has no matching mirror row', () => {
|
||||||
|
const key = 'Z123:new.example.com.:A:';
|
||||||
|
const next = makeRecordSet({ recordKey: key, name: 'new.example.com.' });
|
||||||
|
|
||||||
|
const rows = buildDriftHistoryRows(new Map(), new Map([[key, next]]), 'Z123');
|
||||||
|
|
||||||
|
expect(rows).toHaveLength(1);
|
||||||
|
expect(rows[0].changeAction).toBe('create');
|
||||||
|
expect(rows[0].beforeValue).toBeNull();
|
||||||
|
expect(rows[0].afterValue).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('produces zero rows when mirror and AWS recordsets are identical', () => {
|
||||||
|
const key = 'Z123:www.example.com.:A:';
|
||||||
|
const prev = makeRecordSet();
|
||||||
|
const next = makeRecordSet();
|
||||||
|
|
||||||
|
const rows = buildDriftHistoryRows(
|
||||||
|
new Map([[key, prev]]),
|
||||||
|
new Map([[key, next]]),
|
||||||
|
'Z123'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(rows).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('stores the whole recordset (name, type, setIdentifier, ttl, resourceRecords, aliasTarget) in before/after, not a per-field delta', () => {
|
||||||
|
const key = 'Z123:www.example.com.:A:';
|
||||||
|
const prev = makeRecordSet({ ttl: 300 });
|
||||||
|
const next = makeRecordSet({ ttl: 600 });
|
||||||
|
|
||||||
|
const rows = buildDriftHistoryRows(
|
||||||
|
new Map([[key, prev]]),
|
||||||
|
new Map([[key, next]]),
|
||||||
|
'Z123'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(rows[0].afterValue).toEqual({
|
||||||
|
name: 'www.example.com.',
|
||||||
|
type: 'A',
|
||||||
|
setIdentifier: null,
|
||||||
|
ttl: 600,
|
||||||
|
resourceRecords: [{ value: '10.0.0.1' }],
|
||||||
|
aliasTarget: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('a record changed by Pulse CRUD in the same window is still tagged as drift by the sync (sync cannot distinguish actor)', () => {
|
||||||
|
// The sync has no notion of "who changed this" — it only compares
|
||||||
|
// mirror vs. AWS-live state. A CRUD-originated change looks identical
|
||||||
|
// to an out-of-band AWS console edit from the sync's perspective, so it
|
||||||
|
// still produces a drift row here. The CRUD route's own pulse_crud row
|
||||||
|
// (written elsewhere, not by this function) is the authoritative one;
|
||||||
|
// both rows are expected to coexist in the ledger.
|
||||||
|
const key = 'Z123:www.example.com.:A:';
|
||||||
|
const prev = makeRecordSet({ ttl: 300 });
|
||||||
|
const next = makeRecordSet({ ttl: 900 }); // as if Pulse CRUD had just updated this
|
||||||
|
|
||||||
|
const rows = buildDriftHistoryRows(
|
||||||
|
new Map([[key, prev]]),
|
||||||
|
new Map([[key, next]]),
|
||||||
|
'Z123'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(rows).toHaveLength(1);
|
||||||
|
expect(rows[0].changeAction).toBe('update');
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Add table
Add a link
Reference in a new issue