import test from 'brittle'
import Corestore from 'corestore'
import path from 'bare-path'
import fs from 'bare-fs'
import os from 'bare-os'
import { MediaStore } from '../../lib/media-store.js'
function tmpdir () {
const dir = path.join(os.tmpdir(), 'hn-gc-test-' + Date.now() + '-' + Math.random().toString(36).slice(2))
fs.mkdirSync(dir, { recursive: true })
return dir
}
function rmrf (dir) {
try { fs.rmSync(dir, { recursive: true, force: true }) } catch {}
}
test('GC - scheduleOrphan clears blob after grace period', async (t) => {
const dir = tmpdir()
try {
const store = new Corestore(dir)
const media = new MediaStore(store, {
graceMs: 100,
isReferencedAnywhere: async () => false
})
await media.ready()
const buf = Buffer.from('orphan data')
const hash = await media.put(buf, 'text/plain')
t.is(await media.has(hash), true)
media.scheduleOrphan(hash)
// Wait for grace period + buffer
await new Promise(r => setTimeout(r, 250))
t.is(await media.has(hash), false)
} finally {
rmrf(dir)
}
})
test('GC - cancelOrphan prevents deletion', async (t) => {
const dir = tmpdir()
try {
const store = new Corestore(dir)
const media = new MediaStore(store, {
graceMs: 200,
isReferencedAnywhere: async () => false
})
await media.ready()
const buf = Buffer.from('rescued data')
const hash = await media.put(buf, 'text/plain')
media.scheduleOrphan(hash)
// Cancel before grace period
await new Promise(r => setTimeout(r, 50))
media.cancelOrphan(hash)
// Wait past original grace period
await new Promise(r => setTimeout(r, 300))
t.is(await media.has(hash), true)
} finally {
rmrf(dir)
}
})
test('GC - scheduleOrphan skips if still referenced', async (t) => {
const dir = tmpdir()
try {
const store = new Corestore(dir)
const media = new MediaStore(store, {
graceMs: 100,
isReferencedAnywhere: async () => true
})
await media.ready()
const buf = Buffer.from('still in use')
const hash = await media.put(buf, 'text/plain')
media.scheduleOrphan(hash)
await new Promise(r => setTimeout(r, 250))
t.is(await media.has(hash), true)
} finally {
rmrf(dir)
}
})
test('GC - duplicate scheduleOrphan is idempotent', async (t) => {
const dir = tmpdir()
try {
const store = new Corestore(dir)
const media = new MediaStore(store, {
graceMs: 100,
isReferencedAnywhere: async () => false
})
await media.ready()
const buf = Buffer.from('double schedule')
const hash = await media.put(buf, 'text/plain')
media.scheduleOrphan(hash)
media.scheduleOrphan(hash)
await new Promise(r => setTimeout(r, 250))
t.is(await media.has(hash), false)
} finally {
rmrf(dir)
}
})