153 lines
4.3 KiB
TypeScript
153 lines
4.3 KiB
TypeScript
import fs from 'fs';
|
|
import os from 'os';
|
|
import path from 'path';
|
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { Database } from 'bun:sqlite';
|
|
|
|
describe('migrate json state step', () => {
|
|
const tempRoots: string[] = [];
|
|
|
|
afterEach(() => {
|
|
vi.resetModules();
|
|
vi.unstubAllEnvs();
|
|
vi.restoreAllMocks();
|
|
for (const root of tempRoots.splice(0)) {
|
|
fs.rmSync(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
it('does not migrate legacy json state during startup and leaves files in place', async () => {
|
|
const tempRoot = fs.mkdtempSync(
|
|
path.join(os.tmpdir(), 'ejclaw-migrate-json-init-'),
|
|
);
|
|
tempRoots.push(tempRoot);
|
|
const storeDir = path.join(tempRoot, 'store');
|
|
const dataDir = path.join(tempRoot, 'data');
|
|
fs.mkdirSync(storeDir, { recursive: true });
|
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
vi.stubEnv('EJCLAW_STORE_DIR', storeDir);
|
|
vi.stubEnv('EJCLAW_DATA_DIR', dataDir);
|
|
|
|
fs.writeFileSync(
|
|
path.join(dataDir, 'router_state.json'),
|
|
JSON.stringify({ last_timestamp: '1234' }),
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(dataDir, 'sessions.json'),
|
|
JSON.stringify({ 'group-a': 'session-123' }),
|
|
);
|
|
|
|
const { _initTestDatabase, initDatabase } = await import('../src/db.js');
|
|
|
|
expect(() => initDatabase()).toThrow(
|
|
/Legacy JSON state migration required before startup/,
|
|
);
|
|
expect(fs.existsSync(path.join(dataDir, 'router_state.json'))).toBe(true);
|
|
expect(fs.existsSync(path.join(dataDir, 'sessions.json'))).toBe(true);
|
|
expect(
|
|
fs.existsSync(path.join(dataDir, 'router_state.json.migrated')),
|
|
).toBe(false);
|
|
expect(fs.existsSync(path.join(dataDir, 'sessions.json.migrated'))).toBe(
|
|
false,
|
|
);
|
|
|
|
_initTestDatabase();
|
|
});
|
|
|
|
it('migrates router_state.json and sessions.json only via explicit setup step', async () => {
|
|
const tempRoot = fs.mkdtempSync(
|
|
path.join(os.tmpdir(), 'ejclaw-migrate-json-step-'),
|
|
);
|
|
tempRoots.push(tempRoot);
|
|
const storeDir = path.join(tempRoot, 'store');
|
|
const dataDir = path.join(tempRoot, 'data');
|
|
fs.mkdirSync(storeDir, { recursive: true });
|
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
vi.stubEnv('EJCLAW_STORE_DIR', storeDir);
|
|
vi.stubEnv('EJCLAW_DATA_DIR', dataDir);
|
|
|
|
fs.writeFileSync(
|
|
path.join(dataDir, 'router_state.json'),
|
|
JSON.stringify({
|
|
last_timestamp: '1234',
|
|
last_agent_timestamp: {
|
|
'dc:test-room': '5678',
|
|
},
|
|
}),
|
|
);
|
|
fs.writeFileSync(
|
|
path.join(dataDir, 'sessions.json'),
|
|
JSON.stringify({
|
|
'group-a': 'session-123',
|
|
'group-b': 'session-456',
|
|
}),
|
|
);
|
|
|
|
const emitStatusMock = vi.fn();
|
|
vi.doMock('./status.js', () => ({
|
|
emitStatus: emitStatusMock,
|
|
}));
|
|
|
|
const { run } = await import('./migrate-json-state.js');
|
|
|
|
await run([]);
|
|
|
|
const db = new Database(path.join(storeDir, 'messages.db'), {
|
|
readonly: true,
|
|
});
|
|
expect(
|
|
db.prepare('SELECT key, value FROM router_state ORDER BY key').all(),
|
|
).toEqual([
|
|
{
|
|
key: 'last_agent_seq',
|
|
value: '{"dc:test-room":"5678"}',
|
|
},
|
|
{
|
|
key: 'last_seq',
|
|
value: '1234',
|
|
},
|
|
]);
|
|
expect(
|
|
db
|
|
.prepare(
|
|
`SELECT group_folder, agent_type, session_id
|
|
FROM sessions
|
|
ORDER BY group_folder`,
|
|
)
|
|
.all(),
|
|
).toEqual([
|
|
{
|
|
group_folder: 'group-a',
|
|
agent_type: 'claude-code',
|
|
session_id: 'session-123',
|
|
},
|
|
{
|
|
group_folder: 'group-b',
|
|
agent_type: 'claude-code',
|
|
session_id: 'session-456',
|
|
},
|
|
]);
|
|
db.close();
|
|
|
|
expect(fs.existsSync(path.join(dataDir, 'router_state.json'))).toBe(false);
|
|
expect(fs.existsSync(path.join(dataDir, 'sessions.json'))).toBe(false);
|
|
expect(
|
|
fs.existsSync(path.join(dataDir, 'router_state.json.migrated')),
|
|
).toBe(true);
|
|
expect(fs.existsSync(path.join(dataDir, 'sessions.json.migrated'))).toBe(
|
|
true,
|
|
);
|
|
expect(emitStatusMock).toHaveBeenLastCalledWith(
|
|
'MIGRATE_JSON_STATE',
|
|
expect.objectContaining({
|
|
MIGRATED_ROUTER_STATE_KEYS: 2,
|
|
MIGRATED_SESSIONS: 2,
|
|
RENAMED_ROUTER_STATE_JSON: true,
|
|
RENAMED_SESSIONS_JSON: true,
|
|
STATUS: 'success',
|
|
}),
|
|
);
|
|
});
|
|
});
|