feat: rebuild warm operations workbench
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { migrateDatabase } from '../../infrastructure/database/migrations.js';
|
||||
import { resolveOperationTargets, resolveTargets } from './target-resolver.js';
|
||||
|
||||
function fixture() {
|
||||
const db = new Database(':memory:');
|
||||
db.pragma('foreign_keys = ON');
|
||||
migrateDatabase(db);
|
||||
const now = '2026-07-30T00:00:00.000Z';
|
||||
const insert = db.prepare(
|
||||
'INSERT INTO instances (id,name,base_url,enabled,config_revision,created_at,updated_at) VALUES (?,?,?,?,?,?,?)',
|
||||
);
|
||||
insert.run('a', 'Alpha', 'http://10.0.0.1', 1, 3, now, now);
|
||||
insert.run('b', 'Beta', 'http://10.0.0.2', 1, 2, now, now);
|
||||
insert.run('c', 'Disabled', 'http://10.0.0.3', 0, 1, now, now);
|
||||
const tag = db.prepare('INSERT INTO instance_tags (instance_id,tag,created_at) VALUES (?,?,?)');
|
||||
tag.run('a', 'lab', now);
|
||||
tag.run('a', 'east', now);
|
||||
tag.run('b', 'lab', now);
|
||||
tag.run('c', 'east', now);
|
||||
return db;
|
||||
}
|
||||
|
||||
describe('resolveTargets', () => {
|
||||
it('resolves enabled fixed targets in selector order with current revisions', () => {
|
||||
const db = fixture();
|
||||
expect(resolveTargets(db, { mode: 'fixed', instanceIds: ['b', 'c', 'a'] })).toEqual([
|
||||
{ id: 'b', revision: 2 },
|
||||
{ id: 'a', revision: 3 },
|
||||
]);
|
||||
db.close();
|
||||
});
|
||||
|
||||
it('resolves dynamic all and any tag matches on every call', () => {
|
||||
const db = fixture();
|
||||
expect(resolveTargets(db, { mode: 'tags', match: 'all', tags: ['lab', 'east'] })).toEqual([
|
||||
{ id: 'a', revision: 3 },
|
||||
]);
|
||||
expect(resolveTargets(db, { mode: 'tags', match: 'any', tags: ['lab', 'east'] })).toEqual([
|
||||
{ id: 'a', revision: 3 },
|
||||
{ id: 'b', revision: 2 },
|
||||
]);
|
||||
db.prepare(
|
||||
'INSERT INTO instances (id,name,base_url,enabled,config_revision,created_at,updated_at) VALUES (?,?,?,?,?,?,?)',
|
||||
).run(
|
||||
'd',
|
||||
'Dynamic',
|
||||
'http://10.0.0.4',
|
||||
1,
|
||||
1,
|
||||
'2026-07-30T00:00:00.000Z',
|
||||
'2026-07-30T00:00:00.000Z',
|
||||
);
|
||||
db.prepare('INSERT INTO instance_tags (instance_id,tag,created_at) VALUES (?,?,?)').run(
|
||||
'd',
|
||||
'east',
|
||||
'2026-07-30T00:00:00.000Z',
|
||||
);
|
||||
expect(
|
||||
resolveTargets(db, { mode: 'tags', match: 'any', tags: ['east'] }).map((x) => x.id),
|
||||
).toEqual(['a', 'd']);
|
||||
db.close();
|
||||
});
|
||||
|
||||
it('separates targets whose required operation capability is unavailable', () => {
|
||||
const db = fixture();
|
||||
const now = '2026-07-30T00:00:00.000Z';
|
||||
db.prepare(
|
||||
'INSERT INTO capabilities (instance_id,operation_id,state,observed_at,created_at,updated_at) VALUES (?,?,?,?,?,?)',
|
||||
).run('a', 'postServiceRestart', 'supported', now, now, now);
|
||||
db.prepare(
|
||||
'INSERT INTO capabilities (instance_id,operation_id,state,observed_at,created_at,updated_at) VALUES (?,?,?,?,?,?)',
|
||||
).run('b', 'postServiceRestart', 'unsupported', now, now, now);
|
||||
expect(
|
||||
resolveOperationTargets(db, { mode: 'fixed', instanceIds: ['a', 'b'] }, 'restart-service'),
|
||||
).toEqual({
|
||||
targets: [{ id: 'a', revision: 3 }],
|
||||
targetSnapshot: ['a', 'b'],
|
||||
unavailableInstanceIds: ['b'],
|
||||
});
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user