import test from 'brittle' import fs from 'fs' import os from 'os' import path from 'path' import { bareOsQvacModelsGuestPath, bareOsQvacModelsHostPath, bareOsQvacModelsStripHashPrefix, bareOsQvacHostGgufMatchesSize, bareOsQvacPrepareHostCacheConfig, bareOsQvacMaterializeGgufToHost, bareOsQvacMirrorHostGgufToHdms, bareOsQvacListHdmsGgufs, bareOsQvacFindHdmsGguf, BARE_OS_QVAC_MODELS_GUEST_ROOT } from './lib/bare-os-qvac-models-store.mjs' test('guest/host path + hash prefix mapping', async (t) => { t.is( bareOsQvacModelsGuestPath('5b8aae816570a09d_Qwen3-0.6B-Q4_0.gguf'), BARE_OS_QVAC_MODELS_GUEST_ROOT + '/5b8aae816570a09d_Qwen3-0.6B-Q4_0.gguf' ) t.is( bareOsQvacModelsStripHashPrefix('5b8aae816570a09d_Qwen3-0.6B-Q4_0.gguf'), 'Qwen3-0.6B-Q4_0.gguf' ) t.is( bareOsQvacModelsStripHashPrefix('Qwen3-0.6B-Q4_0.gguf'), 'Qwen3-0.6B-Q4_0.gguf' ) const host = bareOsQvacModelsHostPath('a.gguf', '/tmp/qvac-cache') t.is(host, path.join('/tmp/qvac-cache', 'a.gguf')) }) test('skip materialize when host size matches', async (t) => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-qvac-models-')) const hostPath = path.join(dir, 'model.gguf') const payload = Buffer.from('GGUF-fake-payload-0123456789') fs.writeFileSync(hostPath, payload) t.ok(bareOsQvacHostGgufMatchesSize(hostPath, payload.byteLength)) t.absent(bareOsQvacHostGgufMatchesSize(hostPath, payload.byteLength + 1)) /** @type {Record} */ const files = { [BARE_OS_QVAC_MODELS_GUEST_ROOT + '/model.gguf']: payload } const vfs = { async stat(p) { const b = files[p] if (!b) throw new Error('ENOENT') return { size: b.byteLength } }, async readFile(p) { const b = files[p] if (!b) throw new Error('ENOENT') return b }, async writeFile() { throw new Error('should not write') }, async readdir() { return ['model.gguf'] } } const r = await bareOsQvacMaterializeGgufToHost({ vfs, guestPath: BARE_OS_QVAC_MODELS_GUEST_ROOT + '/model.gguf', hostPath, guestSize: payload.byteLength }) t.ok(r.ok) t.ok(r.skipped) t.is(r.reason, 'size_match') fs.rmSync(dir, { recursive: true, force: true }) }) test('materialize + mirror round-trip via fake vfs', async (t) => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-qvac-models-')) const hostPath = path.join(dir, 'hash_demo.gguf') const payload = Buffer.from('GGUF-roundtrip-bytes') /** @type {Record} */ const files = { [BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf']: payload } const vfs = { async stat(p) { const b = files[p] if (!b) throw new Error('ENOENT') return { size: b.byteLength } }, async readFile(p) { const b = files[p] if (!b) throw new Error('ENOENT') return b }, async writeFile(p, buf) { files[p] = Buffer.from(buf) }, async readdir() { return Object.keys(files).map((p) => path.basename(p)) } } const mat = await bareOsQvacMaterializeGgufToHost({ vfs, guestPath: BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf', hostPath }) t.ok(mat.ok) t.absent(mat.skipped) t.is(fs.readFileSync(hostPath).equals(payload), true) // Change host and mirror back const next = Buffer.from('GGUF-roundtrip-bytes-UPDATED') fs.writeFileSync(hostPath, next) const mir = await bareOsQvacMirrorHostGgufToHdms({ vfs, hostPath, guestName: 'hash_demo.gguf' }) t.ok(mir.ok) t.absent(mir.skipped) t.ok( files[BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf'].equals(next) ) const names = await bareOsQvacListHdmsGgufs(vfs) t.ok(names.includes('hash_demo.gguf')) const found = await bareOsQvacFindHdmsGguf(vfs, 'hash_demo.gguf') t.is(found, BARE_OS_QVAC_MODELS_GUEST_ROOT + '/hash_demo.gguf') fs.rmSync(dir, { recursive: true, force: true }) }) test('prepareHostCacheConfig writes absolute cacheDirectory', async (t) => { const prev = process.env.BARE_OS_HOST_DATA const prevCfg = process.env.QVAC_CONFIG_PATH const prevRequire = globalThis.require const root = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-host-data-')) process.env.BARE_OS_HOST_DATA = root try { delete globalThis.require const cacheDir = path.join(root, 'qvac', 'models') const prepared = bareOsQvacPrepareHostCacheConfig({ cacheDir }) t.is(prepared.cacheDir, cacheDir) t.ok(fs.existsSync(prepared.configPath)) const body = JSON.parse(fs.readFileSync(prepared.configPath, 'utf8')) t.is(body.cacheDirectory, cacheDir) t.is(body.loggerLevel, 'error') t.is(body.loggerConsoleOutput, true) t.is(process.env.QVAC_CONFIG_PATH, prepared.configPath) t.is(typeof globalThis.require, 'function') const viaRequire = globalThis.require(prepared.configPath) t.is(viaRequire.cacheDirectory, cacheDir) } finally { if (prevRequire === undefined) delete globalThis.require else globalThis.require = prevRequire if (prev === undefined) delete process.env.BARE_OS_HOST_DATA else process.env.BARE_OS_HOST_DATA = prev if (prevCfg === undefined) delete process.env.QVAC_CONFIG_PATH else process.env.QVAC_CONFIG_PATH = prevCfg fs.rmSync(root, { recursive: true, force: true }) } })