/** * M4 soak: query falls back to HyperDB warm after memory miss / "restart". */ import test from 'brittle' import fs from 'fs' import path from 'path' import { fileURLToPath } from 'url' import { MetricStore } from '../server/services/store.js' import { openDb, closeDb, getDb } from '../server/db/index.js' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const TMP = path.join(__dirname, '..', 'tmp-store-hyperdb-test') test('query uses hyperdb-warm when memory is empty', async (t) => { fs.rmSync(TMP, { recursive: true, force: true }) process.env.PEARDATA_DATA_DIR = TMP delete process.env.PEARDATA_HYPERDB await closeDb().catch(() => {}) const db = await openDb() t.ok(db) const now = Date.now() await db.putMetricPoints([ { chart: 'system.cpu', context: 'system.cpu', ts: now - 120_000, values: { user: 11, system: 4, nice: 0, iowait: 0, irq: 0, softirq: 0, idle: 85 }, tier: 1, }, { chart: 'system.cpu', context: 'system.cpu', ts: now - 60_000, values: { user: 22, system: 5, nice: 0, iowait: 0, irq: 0, softirq: 0, idle: 73 }, tier: 1, }, ]) // Fresh memory store (simulates process restart with empty rings) const store = new MetricStore() const q = await store.query({ chart: 'system.cpu', after: Math.floor((now - 180_000) / 1000), before: Math.floor(now / 1000), points: 60, tier: 1, }) t.absent(q.error) t.is(q.source, 'hyperdb-warm') t.ok(q.data.length >= 2) await closeDb() // Re-open same Corestore — warm points must still be queryable const db2 = await openDb() t.ok(db2) t.is(getDb(), db2) const store2 = new MetricStore() const q2 = await store2.query({ chart: 'system.cpu', after: Math.floor((now - 180_000) / 1000), before: Math.floor(now / 1000), points: 60, tier: 1, }) t.is(q2.source, 'hyperdb-warm') t.ok(q2.data.length >= 2) await closeDb() fs.rmSync(TMP, { recursive: true, force: true }) delete process.env.PEARDATA_DATA_DIR })