@web4/bitdrive
Version:
Bitdrive is a secure, real time distributed file system
319 lines (271 loc) • 8.04 kB
JavaScript
const tape = require('tape')
const bitwebCrypto = require('@web4/bitweb-crypto')
const Chainstore = require('@web4/chainstore')
const ram = require('random-access-memory')
const create = require('./helpers/create')
const Replicator = require('./helpers/replicator')
tape('close event', function (t) {
t.plan(1)
var drive = create()
drive.on('close', function () {
t.pass('close event')
t.end()
})
drive.ready(function () {
drive.close()
})
})
tape('write and read', function (t) {
var drive = create()
drive.writeFile('/hello.txt', 'world', function (err) {
t.error(err, 'no error')
drive.readFile('/hello.txt', function (err, buf) {
t.error(err, 'no error')
t.same(buf, Buffer.from('world'))
t.end()
})
})
})
tape('write and read, with encoding', function (t) {
var drive = create()
drive.writeFile('/hello.txt', 'world', { encoding: 'utf8' }, function (err) {
t.error(err, 'no error')
drive.readFile('/hello.txt', { encoding: 'utf8' }, function (err, str) {
t.error(err, 'no error')
t.same(str, 'world')
t.end()
})
})
})
tape('write and read (2 parallel)', function (t) {
t.plan(6)
var drive = create()
drive.writeFile('/hello.txt', 'world', function (err) {
t.error(err, 'no error')
drive.readFile('/hello.txt', function (err, buf) {
t.error(err, 'no error')
t.same(buf, Buffer.from('world'))
})
})
drive.writeFile('/world.txt', 'hello', function (err) {
t.error(err, 'no error')
drive.readFile('/world.txt', function (err, buf) {
t.error(err, 'no error')
t.same(buf, Buffer.from('hello'))
})
})
})
tape('write and read (sparse)', function (t) {
var drive = create()
drive.on('ready', function () {
var clone = create(drive.key)
var r = new Replicator(t)
r.replicate(clone, drive)
drive.writeFile('/hello.txt', 'world', function (err) {
t.error(err, 'no error')
var readStream = clone.createReadStream('/hello.txt')
readStream.on('data', function (data) {
t.same(data.toString(), 'world')
r.end()
})
})
})
})
tape('root is always there', function (t) {
var drive = create()
drive.access('/', function (err) {
t.error(err, 'no error')
drive.readdir('/', function (err, list) {
t.error(err, 'no error')
t.same(list, [])
t.end()
})
})
})
tape('provide keypair', function (t) {
const keyPair = bitwebCrypto.keyPair()
var drive = create(keyPair.publicKey, { keyPair })
drive.on('ready', function () {
t.ok(drive.writable)
t.ok(drive.metadata.writable)
t.ok(keyPair.publicKey.equals(drive.key))
drive.writeFile('/hello.txt', 'world', function (err) {
t.error(err, 'no error')
drive.readFile('/hello.txt', function (err, buf) {
t.error(err, 'no error')
t.same(buf, Buffer.from('world'))
t.end()
})
})
})
})
tape.skip('can reopen when providing a keypair', function (t) {
const keyPair = bitwebCrypto.keyPair()
const store = new Chainstore(ram)
var drive = create(keyPair.publicKey, { keyPair, chainstore: store })
drive.on('ready', function () {
t.ok(drive.writable)
t.ok(drive.metadata.writable)
t.ok(keyPair.publicKey.equals(drive.key))
drive.writeFile('/hello.txt', 'world', function (err) {
t.error(err, 'no error')
console.log('CORE LENGTH BEFORE CLOSE:', drive.metadata.length)
drive.close(err => {
t.error(err, 'no error')
drive = create(keyPair.publicKey, { keyPair, chainstore: store })
drive.on('ready', function () {
console.log('CORE LENGTH:', drive.metadata.length)
t.ok(drive.writable)
t.ok(drive.metadata.writable)
t.ok(keyPair.publicKey.equals(drive.key))
drive.readFile('/hello.txt', function (err, buf) {
t.error(err, 'no error')
t.same(buf, Buffer.from('world'))
t.end()
})
})
})
})
})
})
tape('write and read, no cache', function (t) {
var drive = create({
metadataStorageCacheSize: 0,
contentStorageCacheSize: 0,
treeCacheSize: 0
})
drive.writeFile('/hello.txt', 'world', function (err) {
t.error(err, 'no error')
drive.readFile('/hello.txt', function (err, buf) {
t.error(err, 'no error')
t.same(buf, Buffer.from('world'))
t.end()
})
})
})
tape('can read a single directory', async function (t) {
const drive = create(null)
let files = ['a', 'b', 'c', 'd', 'e', 'f']
let fileSet = new Set(files)
for (let file of files) {
await insertFile(file, 'a small file')
}
drive.readdir('/', (err, files) => {
t.error(err, 'no error')
for (let file of files) {
t.true(fileSet.has(file), 'correct file was listed')
fileSet.delete(file)
}
t.same(fileSet.size, 0, 'all files were listed')
t.end()
})
function insertFile (name, content) {
return new Promise((resolve, reject) => {
drive.writeFile(name, content, err => {
if (err) return reject(err)
return resolve()
})
})
}
})
tape.skip('can stream a large directory', async function (t) {
const drive = create(null)
let files = new Array(1000).fill(0).map((_, idx) => '' + idx)
let fileSet = new Set(files)
for (let file of files) {
await insertFile(file, 'a small file')
}
let stream = drive.createDirectoryStream('/')
stream.on('data', ({ path, stat }) => {
if (!fileSet.has(path)) {
return t.fail('an incorrect file was streamed')
}
fileSet.delete(path)
})
stream.on('end', () => {
t.same(fileSet.size, 0, 'all files were streamed')
t.end()
})
function insertFile (name, content) {
return new Promise((resolve, reject) => {
drive.writeFile(name, content, err => {
if (err) return reject(err)
return resolve()
})
})
}
})
tape('can read sparse metadata', async function (t) {
const r = new Replicator(t)
const { read, write } = await getTestDrives()
let files = ['a', 'b/a/b', 'b/c', 'c/b', 'd/e/f/g/h', 'd/e/a', 'e/a', 'e/b', 'f', 'g']
for (let file of files) {
await insertFile(file, 'a small file')
await checkFile(file)
}
r.end()
function checkFile (file) {
return new Promise(resolve => {
read.stat(file, (err, st) => {
t.error(err, 'no error')
t.true(st)
return resolve()
})
})
}
function insertFile (name, content) {
return new Promise((resolve, reject) => {
write.writeFile(name, content, err => {
if (err) return reject(err)
return resolve()
})
})
}
function getTestDrives () {
return new Promise(resolve => {
let drive = create()
drive.on('ready', () => {
let clone = create(drive.key, { sparseMetadata: true, sparse: true })
r.replicate(clone, drive)
return resolve({ read: clone, write: drive })
})
})
}
})
tape('unavailable drive becomes ready', function (t) {
var drive1 = create()
var drive2 = null
drive1.ready(err => {
t.error(err, 'no error')
drive2 = create(drive1.key)
drive2.ready(err => {
t.error(err, 'no error')
drive2.readFile('blah', (err, contents) => {
t.true(err)
t.same(err.errno, 2)
t.end()
})
})
})
})
tape('copy', function (t) {
var drive = create()
drive.ready(err => {
t.error(err, 'no error')
drive.writeFile('hello', 'world', err => {
t.error(err, 'no error')
drive.copy('hello', 'also_hello', err => {
t.error(err, 'no error')
drive.readFile('hello', { encoding: 'utf8' }, (err, contents) => {
t.error(err, 'no error')
t.same(contents, 'world')
drive.readFile('also_hello', { encoding: 'utf8' }, (err, contents) => {
t.error(err, 'no error')
t.same(contents, 'world')
t.end()
})
})
})
})
})
})