import test from 'brittle'
import fs from 'bare-fs'
import path from 'bare-path'
import os from 'bare-os'
import Corestore from 'corestore'
import Hyperbee from 'hyperbee'
import { DriveManager } from '../../lib/drive-manager.js'
function tmpSetup () {
const dir = path.join(os.tmpdir(), 'hn-dm-' + Date.now() + '-' + Math.random().toString(36).slice(2))
fs.mkdirSync(dir, { recursive: true })
const store = new Corestore(dir)
const registry = new Hyperbee(store.get({ name: 'registry' }), {
keyEncoding: 'utf-8',
valueEncoding: 'json'
})
const dm = new DriveManager(store, registry)
return { store, registry, dm, dir }
}
test('createDrive — registers in registry and returns drive', async (t) => {
const { store, registry, dm } = tmpSetup()
await registry.ready()
const drive = await dm.createDrive('work')
t.ok(drive)
t.ok(drive.key)
const entry = await registry.get('notebook-drive:work')
t.ok(entry)
t.is(entry.value.slug, 'work')
t.is(entry.value.isLocal, true)
t.is(entry.value.isShared, false)
t.is(entry.value.driveKey, drive.key.toString('hex'))
await dm.closeAll()
await store.close()
})
test('getDrive — returns cached drive', async (t) => {
const { store, registry, dm } = tmpSetup()
await registry.ready()
const drive1 = await dm.createDrive('cached')
const drive2 = await dm.getDrive('cached')
t.is(drive1, drive2, 'returns same drive instance from cache')
await dm.closeAll()
await store.close()
})
test('getDrive — opens drive from registry after restart', async (t) => {
const { store, registry, dm, dir } = tmpSetup()
await registry.ready()
const drive = await dm.createDrive('test')
await drive.put('/hello.txt', Buffer.from('world'))
await dm.closeAll()
await store.close()
const store2 = new Corestore(dir)
const registry2 = new Hyperbee(store2.get({ name: 'registry' }), {
keyEncoding: 'utf-8',
valueEncoding: 'json'
})
await registry2.ready()
const dm2 = new DriveManager(store2, registry2)
const reopened = await dm2.getDrive('test')
t.ok(reopened)
const buf = await reopened.get('/hello.txt')
t.is(buf.toString(), 'world')
await dm2.closeAll()
await store2.close()
})
test('getDrive — returns null for missing slug', async (t) => {
const { store, registry, dm } = tmpSetup()
await registry.ready()
const result = await dm.getDrive('nonexistent')
t.is(result, null)
await dm.closeAll()
await store.close()
})
test('deleteDrive — removes from registry and cache', async (t) => {
const { store, registry, dm } = tmpSetup()
await registry.ready()
await dm.createDrive('doomed')
await dm.deleteDrive('doomed')
const entry = await registry.get('notebook-drive:doomed')
t.is(entry, null)
t.is(dm._cache.has('doomed'), false)
const result = await dm.getDrive('doomed')
t.is(result, null)
await dm.closeAll()
await store.close()
})
test('listDrives — returns all registered entries', { timeout: 10000 }, async (t) => {
const { store, registry, dm } = tmpSetup()
await registry.ready()
await dm.createDrive('alpha')
await dm.createDrive('beta')
await dm.createDrive('gamma')
const list = await dm.listDrives()
t.is(list.length, 3)
const slugs = list.map(e => e.slug).sort()
t.alike(slugs, ['alpha', 'beta', 'gamma'])
await dm.closeAll()
await store.close()
})
test('addRemoteDrive — sets isLocal false', async (t) => {
const srcDir = path.join(os.tmpdir(), 'hn-dmsrc-' + Date.now() + '-' + Math.random().toString(36).slice(2))
fs.mkdirSync(srcDir, { recursive: true })
const srcStore = new Corestore(srcDir)
const srcReg = new Hyperbee(srcStore.get({ name: 'registry' }), {
keyEncoding: 'utf-8', valueEncoding: 'json'
})
await srcReg.ready()
const srcDm = new DriveManager(srcStore, srcReg)
const srcDrive = await srcDm.createDrive('local')
const keyHex = srcDrive.key.toString('hex')
const { store, registry, dm } = tmpSetup()
await registry.ready()
const remote = await dm.addRemoteDrive(keyHex, 'remote-work')
t.ok(remote)
const info = await dm.getDriveInfo('remote-work')
t.is(info.isLocal, false)
t.is(info.slug, 'remote-work')
t.is(info.driveKey, keyHex)
t.is(dm.isLocal('remote-work'), false)
t.is(dm.isRemote('remote-work'), true)
await dm.closeAll()
await store.close()
await srcDm.closeAll()
await srcStore.close()
})
test('isLocal / isRemote — correct flags', async (t) => {
const { store, registry, dm } = tmpSetup()
await registry.ready()
await dm.createDrive('local-nb')
t.is(dm.isLocal('local-nb'), true)
t.is(dm.isRemote('local-nb'), false)
t.is(dm.isLocal('unknown'), true)
t.is(dm.isRemote('unknown'), false)
await dm.closeAll()
await store.close()
})
test('setShared — updates registry entry', async (t) => {
const { store, registry, dm } = tmpSetup()
await registry.ready()
await dm.createDrive('shared-nb')
let info = await dm.getDriveInfo('shared-nb')
t.is(info.isShared, false)
await dm.setShared('shared-nb', true)
info = await dm.getDriveInfo('shared-nb')
t.is(info.isShared, true)
t.is(dm._cache.get('shared-nb').entry.isShared, true)
await dm.closeAll()
await store.close()
})