Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ipfs-log

Package Overview
Dependencies
Maintainers
1
Versions
113
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ipfs-log - npm Package Compare versions

Comparing version 1.4.1 to 1.4.2

10

package.json
{
"name": "ipfs-log",
"version": "1.4.1",
"version": "1.4.2",
"description": "Append-only log for IPFS",

@@ -23,7 +23,7 @@ "main": "src/log.js",

"idb-plus-blob-store": "^1.1.2",
"ipfs": "^0.5.0",
"ipfs-api": "^4.0.2",
"ipfsd-ctl": "^0.13.0",
"ipfs": "^0.6.1",
"ipfs-api": "^4.1.0",
"ipfsd-ctl": "^0.14.0",
"json-loader": "^0.5.4",
"libp2p-ipfs-browser": "^0.2.0",
"libp2p-ipfs-browser": "^0.4.0",
"logplease": "^1.2.6",

@@ -30,0 +30,0 @@ "mocha": "^2.4.5",

@@ -8,240 +8,263 @@ 'use strict';

const Entry = require('../src/entry');
// const ipfsd = require('ipfsd-ctl');
const IPFS = require('ipfs')
const ipfsd = require('ipfsd-ctl');
let ipfs;
let ipfs, ipfsDaemon;
const IpfsApis = [{
// js-ipfs
start: () => {
return new Promise((resolve, reject) => {
const IPFS = require('ipfs')
const ipfs = new IPFS();
resolve(ipfs);
// ipfs.goOnline((err) => {
// if(err)
// reject(err);
// else
// resolve(ipfs);
// });
});
},
stop: () => Promise.resolve()
// stop: () => new Promise((resolve, reject) => ipfs.goOffline(resolve))
}, {
// js-ipfs-api via local daemon
start: () => {
return new Promise((resolve, reject) => {
ipfsd.disposableApi((err, ipfs) => {
if(err) console.error(err);
resolve(ipfs);
});
// ipfsd.local((err, node) => {
// if(err) reject(err);
// ipfsDaemon = node;
// ipfsDaemon.startDaemon((err, ipfs) => {
// if(err) reject(err);
// resolve(ipfs);
// });
// });
});
},
stop: () => Promise.resolve()
// stop: () => new Promise((resolve, reject) => ipfsDaemon.stopDaemon(resolve))
}];
const startIpfs = () => {
return new Promise((resolve, reject) => {
// Use disposable ipfs api with a local daemon
// ipfsd.disposableApi((err, ipfs) => {
// if(err) console.error(err);
// resolve(ipfs);
// });
// Use a local running daemon
// ipfsd.local((err, node) => {
// if(err) reject(err);
// node.startDaemon((err, ipfs) => {
// if(err) reject(err);
// resolve(ipfs);
// });
// });
// Use js-ipfs daemon
const ipfs = new IPFS();
ipfs.goOnline(() => {
resolve(ipfs)
})
});
};
IpfsApis.forEach(function(ipfsApi) {
describe('Entry', function() {
this.timeout(20000);
before(async((done) => {
try {
// ipfs = await(startIpfs());
ipfs = new IPFS();
} catch(e) {
console.log(e);
assert.equals(e, null);
}
this.timeout(2000);
done();
}));
describe('create', () => {
it('creates a an empty entry', async((done) => {
const expectedHash = 'QmfAouPZ2Cu3Cjbjm63RVeWJt6L9QjTSyFLe9SK5dWXN1j';
const entry = await(Entry.create(ipfs));
assert.equal(entry.payload, null);
assert.equal(entry.next.length, 0);
assert.equal(entry.hash, expectedHash);
describe('Entry', function() {
this.timeout(40000);
before(async((done) => {
try {
ipfs = await(ipfsApi.start());
} catch(e) {
console.log(e);
assert.equal(e, null);
}
this.timeout(2000);
done();
}));
it('creates a entry with payload', async((done) => {
const expectedHash = 'QmP2wHv43QtH3aCj4pUXeoVmkdtqNBVtx5bfYyNSH6LmXG';
const payload = 'hello world';
const entry = await(Entry.create(ipfs, payload));
assert.equal(entry.payload, payload);
assert.equal(entry.next.length, 0);
assert.equal(entry.hash, expectedHash);
after(async((done) => {
await(ipfsApi.stop());
done();
}));
it('creates a entry with payload and next', async((done) => {
const expectedHash = 'QmW94BLFbGNbaPjgGasX1rV9aYdE2qxnQnUBf9PbLkiBUo';
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2, entry1));
assert.equal(entry2.payload, payload2);
assert.equal(entry2.next.length, 1);
assert.equal(entry2.hash, expectedHash);
done();
}));
describe('create', () => {
it('creates a an empty entry', async((done) => {
const expectedHash = 'QmfAouPZ2Cu3Cjbjm63RVeWJt6L9QjTSyFLe9SK5dWXN1j';
// console.log(ipfs)
const entry = await(Entry.create(ipfs));
assert.equal(entry.payload, null);
assert.equal(entry.next.length, 0);
assert.equal(entry.hash, expectedHash);
done();
}));
it('`next` parameter can be a string', async((done) => {
const entry1 = await(Entry.create(ipfs, null));
const entry2 = await(Entry.create(ipfs, null, entry1.hash));
assert.equal(typeof entry2.next[0] === 'string', true);
done();
}));
it('creates a entry with payload', async((done) => {
const expectedHash = 'QmP2wHv43QtH3aCj4pUXeoVmkdtqNBVtx5bfYyNSH6LmXG';
const payload = 'hello world';
const entry = await(Entry.create(ipfs, payload));
assert.equal(entry.payload, payload);
assert.equal(entry.next.length, 0);
assert.equal(entry.hash, expectedHash);
done();
}));
it('`next` parameter can be an instance of Entry', async((done) => {
const entry1 = await(Entry.create(ipfs, null));
const entry2 = await(Entry.create(ipfs, null, entry1));
assert.equal(typeof entry2.next[0] === 'string', true);
done();
}));
it('creates a entry with payload and next', async((done) => {
const expectedHash = 'QmW94BLFbGNbaPjgGasX1rV9aYdE2qxnQnUBf9PbLkiBUo';
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2, entry1));
assert.equal(entry2.payload, payload2);
assert.equal(entry2.next.length, 1);
assert.equal(entry2.hash, expectedHash);
done();
}));
it('throws an error if ipfs is not defined', async((done) => {
try {
const entry = await(Entry.create());
} catch(e) {
assert.equal(e.message, 'Entry requires ipfs instance');
}
done();
}));
});
it('`next` parameter can be a string', async((done) => {
const entry1 = await(Entry.create(ipfs, null));
const entry2 = await(Entry.create(ipfs, null, entry1.hash));
assert.equal(typeof entry2.next[0] === 'string', true);
done();
}));
describe('fromIpfsHash', () => {
it('creates a entry from ipfs hash', async((done) => {
const expectedHash = 'QmW94BLFbGNbaPjgGasX1rV9aYdE2qxnQnUBf9PbLkiBUo';
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2, entry1));
const final = await(Entry.fromIpfsHash(ipfs, entry2.hash));
assert.equal(final.payload, payload2);
assert.equal(final.next.length, 1);
assert.equal(final.next[0], entry1.hash);
assert.equal(final.hash, expectedHash);
done();
}));
it('`next` parameter can be an instance of Entry', async((done) => {
const entry1 = await(Entry.create(ipfs, null));
const entry2 = await(Entry.create(ipfs, null, entry1));
assert.equal(typeof entry2.next[0] === 'string', true);
done();
}));
it('throws an error if ipfs is not present', async((done) => {
try {
const entry = await(Entry.fromIpfsHash());
} catch(e) {
assert.equal(e.message, 'Entry requires ipfs instance');
}
done();
}));
it('throws an error if ipfs is not defined', async((done) => {
try {
const entry = await(Entry.create());
} catch(e) {
assert.equal(e.message, 'Entry requires ipfs instance');
}
done();
}));
});
it('throws an error if hash is undefined', async((done) => {
try {
const entry = await(Entry.fromIpfsHash(ipfs));
} catch(e) {
assert.equal(e.message, 'Invalid hash: undefined');
}
done();
}));
});
describe('fromIpfsHash', () => {
it('creates a entry from ipfs hash', async((done) => {
const expectedHash = 'QmW94BLFbGNbaPjgGasX1rV9aYdE2qxnQnUBf9PbLkiBUo';
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2, entry1));
const final = await(Entry.fromIpfsHash(ipfs, entry2.hash));
assert.equal(final.payload, payload2);
assert.equal(final.next.length, 1);
assert.equal(final.next[0], entry1.hash);
assert.equal(final.hash, expectedHash);
done();
}));
describe('hasChild', () => {
it('returns true if entry has a child', async((done) => {
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2, entry1));
assert.equal(entry2.hasChild(entry1), true);
done();
}));
it('throws an error if ipfs is not present', async((done) => {
try {
const entry = await(Entry.fromIpfsHash());
} catch(e) {
assert.equal(e.message, 'Entry requires ipfs instance');
}
done();
}));
it('returns false if entry does not have a child', async((done) => {
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2));
const entry3 = await(Entry.create(ipfs, payload2, entry2));
assert.equal(entry2.hasChild(entry1), false);
assert.equal(entry3.hasChild(entry1), false);
assert.equal(entry3.hasChild(entry2), true);
done();
}));
});
it('throws an error if hash is undefined', async((done) => {
try {
const entry = await(Entry.fromIpfsHash(ipfs));
} catch(e) {
assert.equal(e.message, 'Invalid hash: undefined');
}
done();
}));
});
describe('getIpfsHash', () => {
it('returns an ipfs hash', async((done) => {
const expectedHash = 'QmfAouPZ2Cu3Cjbjm63RVeWJt6L9QjTSyFLe9SK5dWXN1j';
const entry = await(Entry.create(ipfs));
const hash = await(Entry.getIpfsHash(ipfs, entry));
assert.equal(hash, expectedHash);
done();
}));
});
describe('hasChild', () => {
it('returns true if entry has a child', async((done) => {
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2, entry1));
assert.equal(entry2.hasChild(entry1), true);
done();
}));
describe('asJson', () => {
it('returns the entry as json with empty values', async((done) => {
const payload = 'hello world';
const entry = await(Entry.create(ipfs, payload));
assert.notEqual(entry.asJson, null);
assert.equal(entry.asJson.payload, payload);
assert.equal(entry.asJson.next.length, 0);
done();
}));
it('returns false if entry does not have a child', async((done) => {
const payload1 = 'hello world';
const payload2 = 'hello again';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2));
const entry3 = await(Entry.create(ipfs, payload2, entry2));
assert.equal(entry2.hasChild(entry1), false);
assert.equal(entry3.hasChild(entry1), false);
assert.equal(entry3.hasChild(entry2), true);
done();
}));
});
it('returns the entry as json with values', async((done) => {
const payload = 'hello world';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, payload, entry1));
assert.equal(typeof entry2.next[0] === 'string', true);
assert.notEqual(entry2.asJson, null);
assert.equal(entry2.asJson.payload, payload);
assert.equal(entry2.asJson.next.length, 1);
assert.equal(entry2.asJson.next[0], entry1.hash);
done();
}));
describe('getIpfsHash', () => {
it('returns an ipfs hash', async((done) => {
const expectedHash = 'QmfAouPZ2Cu3Cjbjm63RVeWJt6L9QjTSyFLe9SK5dWXN1j';
const entry = await(Entry.create(ipfs));
const hash = await(Entry.getIpfsHash(ipfs, entry));
assert.equal(hash, expectedHash);
done();
}));
});
it('returns entry as json with values when next is a hash', async((done) => {
const payload = 'hello world';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, payload, [entry1.hash]));
assert.equal(typeof entry2.next[0] === 'string', true);
assert.notEqual(entry2.asJson, null);
assert.equal(entry2.asJson.payload, payload);
assert.equal(entry2.asJson.next.length, 1);
assert.equal(entry2.asJson.next[0], entry1.hash);
done();
}));
});
describe('asJson', () => {
it('returns the entry as json with empty values', async((done) => {
const payload = 'hello world';
const entry = await(Entry.create(ipfs, payload));
assert.notEqual(entry.asJson, null);
assert.equal(entry.asJson.payload, payload);
assert.equal(entry.asJson.next.length, 0);
done();
}));
describe('equals', () => {
it('entrys are equal when the payload is the same', async((done) => {
const payload = 'hello world 1';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, payload));
assert.equal(Entry.equals(entry1, entry2), true);
done();
}));
it('returns the entry as json with values', async((done) => {
const payload = 'hello world';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, payload, entry1));
assert.equal(typeof entry2.next[0] === 'string', true);
assert.notEqual(entry2.asJson, null);
assert.equal(entry2.asJson.payload, payload);
assert.equal(entry2.asJson.next.length, 1);
assert.equal(entry2.asJson.next[0], entry1.hash);
done();
}));
it('entrys are not equal when the payload is different', async((done) => {
const payload1 = 'hello world 1';
const payload2 = 'hello world 2';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2));
assert.equal(Entry.equals(entry1, entry2), false);
done();
}));
it('returns entry as json with values when next is a hash', async((done) => {
const payload = 'hello world';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, payload, [entry1.hash]));
assert.equal(typeof entry2.next[0] === 'string', true);
assert.notEqual(entry2.asJson, null);
assert.equal(entry2.asJson.payload, payload);
assert.equal(entry2.asJson.next.length, 1);
assert.equal(entry2.asJson.next[0], entry1.hash);
done();
}));
});
it('entrys are equal when next references and payloads are the same', async((done) => {
const payload = 'hello world 1';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, null, entry1));
const entry3 = await(Entry.create(ipfs, null, entry1));
assert.equal(Entry.equals(entry2, entry3), true);
done();
}));
describe('equals', () => {
it('entrys are equal when the payload is the same', async((done) => {
const payload = 'hello world 1';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, payload));
assert.equal(Entry.equals(entry1, entry2), true);
done();
}));
it('entrys are not equal when next references are not the same', async((done) => {
const payload1 = 'hello world 1';
const payload2 = 'hello world 2';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2));
const entry3 = await(Entry.create(ipfs, null, entry1));
const entry4 = await(Entry.create(ipfs, null, entry2));
assert.equal(Entry.equals(entry3, entry4), false);
done();
}));
it('entrys are not equal when the payload is different', async((done) => {
const payload1 = 'hello world 1';
const payload2 = 'hello world 2';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2));
assert.equal(Entry.equals(entry1, entry2), false);
done();
}));
it('entrys are equal when next references and payloads are the same', async((done) => {
const payload = 'hello world 1';
const entry1 = await(Entry.create(ipfs, payload));
const entry2 = await(Entry.create(ipfs, null, entry1));
const entry3 = await(Entry.create(ipfs, null, entry1));
assert.equal(Entry.equals(entry2, entry3), true);
done();
}));
it('entrys are not equal when next references are not the same', async((done) => {
const payload1 = 'hello world 1';
const payload2 = 'hello world 2';
const entry1 = await(Entry.create(ipfs, payload1));
const entry2 = await(Entry.create(ipfs, payload2));
const entry3 = await(Entry.create(ipfs, null, entry1));
const entry4 = await(Entry.create(ipfs, null, entry2));
assert.equal(Entry.equals(entry3, entry4), false);
done();
}));
});
});
});

@@ -9,98 +9,87 @@ 'use strict';

const Entry = require('../src/entry');
// const ipfsd = require('ipfsd-ctl');
const IPFS = require('ipfs')
const ipfsd = require('ipfsd-ctl');
let ipfs, entry;
let ipfs, ipfsDaemon;
const IpfsApis = [{
// js-ipfs
start: () => {
return new Promise((resolve, reject) => {
const IPFS = require('ipfs')
const ipfs = new IPFS();
// ipfs.goOnline(() => resolve(ipfs));
resolve(ipfs);
});
},
stop: () => Promise.resolve()
// stop: () => new Promise((resolve, reject) => ipfs.goOffline(resolve))
}, {
// js-ipfs-api via local daemon
start: () => {
return new Promise((resolve, reject) => {
ipfsd.disposableApi((err, ipfs) => {
if(err) console.error(err);
resolve(ipfs);
});
// ipfsd.local((err, node) => {
// if(err) reject(err);
// ipfsDaemon = node;
// ipfsDaemon.startDaemon((err, ipfs) => {
// if(err) reject(err);
// resolve(ipfs);
// });
// });
});
},
stop: () => Promise.resolve()
// stop: () => new Promise((resolve, reject) => ipfsDaemon.stopDaemon(resolve))
}];
const startIpfs = () => {
return new Promise((resolve, reject) => {
// Use disposable ipfs api with a local daemon
// ipfsd.disposableApi((err, ipfs) => {
// if(err) console.error(err);
// resolve(ipfs);
// });
// Use a local running daemon
// ipfsd.local((err, node) => {
// if(err) reject(err);
// node.startDaemon((err, ipfs) => {
// if(err) reject(err);
// resolve(ipfs);
// });
// });
// Use js-ipfs daemon
const ipfs = new IPFS();
ipfs.goOnline(() => {
resolve(ipfs)
})
});
};
IpfsApis.forEach(function(ipfsApi) {
describe('Log', async(function() {
// this.timeout(20000);
before(async((done) => {
try {
// ipfs = await(startIpfs());
ipfs = new IPFS();
} catch(e) {
console.log(e);
assert.equal(e, null);
}
this.timeout(2000);
done();
}));
describe('create', async(() => {
it('creates an empty log', async((done) => {
const log = new Log(ipfs, 'A');
assert.equal(log.id, 'A');
assert.equal(log._items instanceof Array, true);
assert.equal(log._items.length, 0);
assert.equal(log._currentBatch instanceof Array, true);
assert.equal(log._currentBatch.length, 0);
assert.equal(log._ipfs, ipfs);
assert.equal(log.hash, null);
done();
}));
it('throws an error if ipfs is not defined', async((done) => {
describe('Log', function() {
this.timeout(40000);
before(async((done) => {
try {
const log = new Log();
ipfs = await(ipfsApi.start());
} catch(e) {
assert.equal(e.message, 'Ipfs instance not defined');
console.log(e);
assert.equal(e, null);
}
this.timeout(2000);
done();
}));
it('throws an error if id is not defined', async((done) => {
try {
const log = new Log(ipfs);
} catch(e) {
assert.equal(e.message, 'id is not defined');
}
after(async((done) => {
await(ipfsApi.stop());
done();
}));
}));
describe('serialize', async(() => {
let log;
const expectedData = {
id: "A",
items: [
'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR',
'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi',
'QmQM4Xg6EGGGEKRYu3jX3cpTcXK53XvSgQpxZd2qGY1L2V'
]
};
describe('create', async(() => {
it('creates an empty log', async((done) => {
const log = new Log(ipfs, 'A');
assert.equal(log.id, 'A');
assert.equal(log._items instanceof Array, true);
assert.equal(log._items.length, 0);
assert.equal(log._currentBatch instanceof Array, true);
assert.equal(log._currentBatch.length, 0);
assert.equal(log._ipfs, ipfs);
assert.equal(log.hash, null);
done();
}));
beforeEach(async((done) => {
log = new Log(ipfs, 'A');
await(log.add("one"));
await(log.add("two"));
await(log.add("three"));
done();
}));
it('throws an error if ipfs is not defined', async((done) => {
try {
const log = new Log();
} catch(e) {
assert.equal(e.message, 'Ipfs instance not defined');
}
done();
}));
describe('snapshot', async(() => {
it('returns the current batch of items', async((done) => {
assert.equal(JSON.stringify(log.snapshot), JSON.stringify(expectedData));
it('throws an error if id is not defined', async((done) => {
try {
const log = new Log(ipfs);
} catch(e) {
assert.equal(e.message, 'id is not defined');
}
done();

@@ -110,683 +99,711 @@ }));

describe('fromSnapshot', () => {
it('creates a log from a snapshot', async((done) => {
const str = JSON.stringify(log.snapshot, null, 2)
const res = await(Log.fromJson(ipfs, JSON.parse(str)));
assert.equal(res.items.length, 3);
assert.equal(res.items[0].hash, expectedData.items[0]);
assert.equal(res.items[1].hash, expectedData.items[1]);
assert.equal(res.items[2].hash, expectedData.items[2]);
describe('serialize', async(() => {
let log;
const expectedData = {
id: "A",
items: [
'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR',
'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi',
'QmQM4Xg6EGGGEKRYu3jX3cpTcXK53XvSgQpxZd2qGY1L2V'
]
};
beforeEach(async((done) => {
log = new Log(ipfs, 'A');
await(log.add("one"));
await(log.add("two"));
await(log.add("three"));
done();
}));
});
describe('getIpfsHash', async(() => {
it('returns the log as ipfs hash', async((done) => {
const expectedHash = 'QmaRz4njJX2W8QYwWLa1jhEbYUdJhhqibsBbnRYuWgr1r7';
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(ipfs, log));
assert.equal(hash, expectedHash);
done();
describe('snapshot', async(() => {
it('returns the current batch of items', async((done) => {
assert.equal(JSON.stringify(log.snapshot), JSON.stringify(expectedData));
done();
}));
}));
it('log serialized to ipfs contains the correct data', async((done) => {
const expectedData = { id: "A", items: [] };
// const expectedData = {
// Data: '{"id":"A","items":[]}',
// Links: [],
// "Hash":"QmaRz4njJX2W8QYwWLa1jhEbYUdJhhqibsBbnRYuWgr1r7",
// "Size":23
// };
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(ipfs, log));
const res = await(ipfs.object.get(hash, { enc: 'base58' }));
const result = JSON.parse(res.toJSON().Data);
// assert.equal(JSON.stringify(res.toJSON().Data), JSON.stringify(expectedData));
assert.equal(result.id, expectedData.id);
assert.equal(result.items.length, expectedData.items.length);
done();
describe('fromSnapshot', () => {
it('creates a log from a snapshot', async((done) => {
const str = JSON.stringify(log.snapshot, null, 2)
const res = await(Log.fromJson(ipfs, JSON.parse(str)));
assert.equal(res.items.length, 3);
assert.equal(res.items[0].hash, expectedData.items[0]);
assert.equal(res.items[1].hash, expectedData.items[1]);
assert.equal(res.items[2].hash, expectedData.items[2]);
done();
}));
});
describe('getIpfsHash', async(() => {
it('returns the log as ipfs hash', async((done) => {
const expectedHash = 'QmaRz4njJX2W8QYwWLa1jhEbYUdJhhqibsBbnRYuWgr1r7';
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(ipfs, log));
assert.equal(hash, expectedHash);
done();
}));
it('log serialized to ipfs contains the correct data', async((done) => {
const expectedData = { id: "A", items: [] };
// const expectedData = {
// Data: '{"id":"A","items":[]}',
// Links: [],
// "Hash":"QmaRz4njJX2W8QYwWLa1jhEbYUdJhhqibsBbnRYuWgr1r7",
// "Size":23
// };
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(ipfs, log));
const res = await(ipfs.object.get(hash, { enc: 'base58' }));
const result = JSON.parse(res.toJSON().Data);
// assert.equal(JSON.stringify(res.toJSON().Data), JSON.stringify(expectedData));
assert.equal(result.id, expectedData.id);
assert.equal(result.items.length, expectedData.items.length);
done();
}));
it('throws an error if ipfs is not defined', async((done) => {
try {
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(null, log));
} catch(e) {
assert.equal(e.message, 'Ipfs instance not defined');
}
done();
}));
}));
it('throws an error if ipfs is not defined', async((done) => {
try {
describe('fromIpfsHash', async(() => {
it('creates an empty log from ipfs hash', async((done) => {
const expectedData = { id: "A", items: [] };
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(null, log));
} catch(e) {
assert.equal(e.message, 'Ipfs instance not defined');
}
done();
const hash = await(Log.getIpfsHash(ipfs, log));
const res = await(Log.fromIpfsHash(ipfs, hash));
assert.equal(JSON.stringify(res.snapshot), JSON.stringify(expectedData));
done();
}));
it('creates a log from ipfs hash', async((done) => {
const hash = await(Log.getIpfsHash(ipfs, log));
const res = await(Log.fromIpfsHash(ipfs, hash));
assert.equal(res.items.length, 3);
assert.equal(res.items[0].hash, expectedData.items[0]);
assert.equal(res.items[1].hash, expectedData.items[1]);
assert.equal(res.items[2].hash, expectedData.items[2]);
done();
}));
}));
}));
describe('fromIpfsHash', async(() => {
it('creates an empty log from ipfs hash', async((done) => {
const expectedData = { id: "A", items: [] };
describe('items', () => {
it('returns all entrys in the log', async((done) => {
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(ipfs, log));
const res = await(Log.fromIpfsHash(ipfs, hash));
assert.equal(JSON.stringify(res.snapshot), JSON.stringify(expectedData));
let items = log.items;
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 0);
await(log.add("hello1"));
await(log.add("hello2"));
await(log.add("hello3"));
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 3);
assert.equal(log.items[0].payload, 'hello1');
assert.equal(log.items[1].payload, 'hello2');
assert.equal(log.items[2].payload, 'hello3');
assert.equal(log._items.length, 0);
assert.equal(log._currentBatch.length, 3);
done();
}));
it('creates a log from ipfs hash', async((done) => {
const hash = await(Log.getIpfsHash(ipfs, log));
const res = await(Log.fromIpfsHash(ipfs, hash));
assert.equal(res.items.length, 3);
assert.equal(res.items[0].hash, expectedData.items[0]);
assert.equal(res.items[1].hash, expectedData.items[1]);
assert.equal(res.items[2].hash, expectedData.items[2]);
it('returns all entrys from current batch and all known entrys', async((done) => {
const log = new Log(ipfs, 'A');
let items = log.items;
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 0);
await(log.add("hello1"));
await(log.add("hello2"));
log._commit();
await(log.add("hello3"));
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 3);
assert.equal(log.items[0].payload, 'hello1');
assert.equal(log.items[1].payload, 'hello2');
assert.equal(log.items[2].payload, 'hello3');
assert.equal(log._items.length, 2);
assert.equal(log._currentBatch.length, 1);
done();
}));
}));
}));
});
describe('items', () => {
it('returns all entrys in the log', async((done) => {
const log = new Log(ipfs, 'A');
let items = log.items;
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 0);
await(log.add("hello1"));
await(log.add("hello2"));
await(log.add("hello3"));
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 3);
assert.equal(log.items[0].payload, 'hello1');
assert.equal(log.items[1].payload, 'hello2');
assert.equal(log.items[2].payload, 'hello3');
assert.equal(log._items.length, 0);
assert.equal(log._currentBatch.length, 3);
done();
}));
describe('add', () => {
it('adds an item to an empty log', async((done) => {
const log = new Log(ipfs, 'A');
await(log.add("hello1"));
const item = log.items[0];
assert.equal(log.items.length, 1);
assert.equal(log._currentBatch.length, 1);
assert.equal(log._items.length, 0);
assert.equal(item, log._currentBatch[0]);
assert.equal(item.payload, 'hello1');
done();
}));
it('returns all entrys from current batch and all known entrys', async((done) => {
const log = new Log(ipfs, 'A');
let items = log.items;
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 0);
await(log.add("hello1"));
await(log.add("hello2"));
log._commit();
await(log.add("hello3"));
it('adds 100 items to a log', async((done) => {
const log = new Log(ipfs, 'A');
const amount = 100;
assert.equal(log.items instanceof Array, true);
assert.equal(log.items.length, 3);
assert.equal(log.items[0].payload, 'hello1');
assert.equal(log.items[1].payload, 'hello2');
assert.equal(log.items[2].payload, 'hello3');
assert.equal(log._items.length, 2);
assert.equal(log._currentBatch.length, 1);
done();
}));
});
for(let i = 1; i <= amount; i ++) {
await(log.add("hello" + i));
}
describe('add', () => {
it('adds an item to an empty log', async((done) => {
const log = new Log(ipfs, 'A');
await(log.add("hello1"));
const item = log.items[0];
assert.equal(log.items.length, 1);
assert.equal(log._currentBatch.length, 1);
assert.equal(log._items.length, 0);
assert.equal(item, log._currentBatch[0]);
assert.equal(item.payload, 'hello1');
done();
}));
const last = _.last(log.items);
assert.equal(log.items.length, amount);
assert.equal(last.payload, 'hello' + amount);
assert.notEqual(last.next.length, 0);
it('adds 100 items to a log', async((done) => {
const log = new Log(ipfs, 'A');
const amount = 100;
done();
}));
for(let i = 1; i <= amount; i ++) {
await(log.add("hello" + i));
}
it('commits the log after batch size was reached', async((done) => {
const log = new Log(ipfs, 'A');
const last = _.last(log.items);
assert.equal(log.items.length, amount);
assert.equal(last.payload, 'hello' + amount);
assert.notEqual(last.next.length, 0);
for(let i = 1; i <= Log.batchSize; i ++) {
await(log.add("hello" + i));
}
done();
}));
assert.equal(log.items.length, Log.batchSize);
assert.equal(log._currentBatch.length, Log.batchSize);
assert.equal(log._items.length, 0);
it('commits the log after batch size was reached', async((done) => {
const log = new Log(ipfs, 'A');
const item = _.last(log.items);
assert.equal(log.items.length, Log.batchSize);
assert.equal(item.payload, 'hello' + Log.batchSize);
assert.notEqual(item.next.length, 0);
for(let i = 1; i <= Log.batchSize; i ++) {
await(log.add("hello" + i));
}
done();
}));
});
assert.equal(log.items.length, Log.batchSize);
assert.equal(log._currentBatch.length, Log.batchSize);
assert.equal(log._items.length, 0);
describe('join', () => {
let log1, log2, log3, log4;
const item = _.last(log.items);
assert.equal(log.items.length, Log.batchSize);
assert.equal(item.payload, 'hello' + Log.batchSize);
assert.notEqual(item.next.length, 0);
beforeEach(async((done) => {
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
log4 = new Log(ipfs, 'D');
done();
}));
done();
}));
});
it('joins only unique items', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.join(log2));
describe('join', () => {
let log1, log2, log3, log4;
assert.equal(log1.items.length, 4);
assert.equal(log1.items[0].hash, 'QmUEH5SEuRZhZ7RETwEX2df2BtTR2xUYZR3qBrhjnxqocb');
assert.equal(log1.items[1].hash, 'Qma1PaYbyW1rZA4npPnuJzA3ov5Je4N9cvAn2p6Ju1iPQS');
assert.equal(log1.items[2].hash, 'QmdZwCR96sP61aaTbcLj9DXy9EaiMhTXLRrTxPSXpcZCct');
assert.equal(log1.items[3].hash, 'QmR3jTmVNQGfq4m6sDk2koFHFkSRMxJqSjrTHU293yyWMv');
beforeEach(async((done) => {
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
log4 = new Log(ipfs, 'D');
done();
}));
const last = _.last(log1.items);
assert.equal(last.next.length, 1);
assert.equal(last.next[0], 'QmdZwCR96sP61aaTbcLj9DXy9EaiMhTXLRrTxPSXpcZCct');
done();
}));
it('joins only unique items', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.join(log2));
it('joins logs two ways', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log2.join(log1));
assert.equal(log1.items.length, 4);
assert.equal(log1.items[0].hash, 'QmUEH5SEuRZhZ7RETwEX2df2BtTR2xUYZR3qBrhjnxqocb');
assert.equal(log1.items[1].hash, 'Qma1PaYbyW1rZA4npPnuJzA3ov5Je4N9cvAn2p6Ju1iPQS');
assert.equal(log1.items[2].hash, 'QmdZwCR96sP61aaTbcLj9DXy9EaiMhTXLRrTxPSXpcZCct');
assert.equal(log1.items[3].hash, 'QmR3jTmVNQGfq4m6sDk2koFHFkSRMxJqSjrTHU293yyWMv');
const lastItem1 = _.last(log1.items);
assert.equal(log1._currentBatch.length, 0);
assert.equal(log1._items.length, 4);
assert.equal(lastItem1.payload, 'helloB2');
const last = _.last(log1.items);
assert.equal(last.next.length, 1);
assert.equal(last.next[0], 'QmdZwCR96sP61aaTbcLj9DXy9EaiMhTXLRrTxPSXpcZCct');
done();
}));
const lastItem2 = _.last(log2.items);
assert.equal(log2._currentBatch.length, 0);
assert.equal(log2._items.length, 4);
assert.equal(lastItem2.payload, 'helloA2');
done();
}));
it('joins logs two ways', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log2.join(log1));
it('joins logs twice', async((done) => {
await(log1.add("helloA1"));
await(log2.add("helloB1"));
await(log2.join(log1));
await(log1.add("helloA2"));
await(log2.add("helloB2"));
await(log2.join(log1));
const lastItem1 = _.last(log1.items);
assert.equal(log1._currentBatch.length, 0);
assert.equal(log1._items.length, 4);
assert.equal(lastItem1.payload, 'helloB2');
const secondItem = log2.items[1];
const lastItem = _.last(log2.items);
const lastItem2 = _.last(log2.items);
assert.equal(log2._currentBatch.length, 0);
assert.equal(log2._items.length, 4);
assert.equal(lastItem2.payload, 'helloA2');
done();
}));
assert.equal(log2._currentBatch.length, 0);
assert.equal(log2._items.length, 4);
assert.equal(secondItem.payload, 'helloA1');
assert.equal(lastItem.payload, 'helloA2');
done();
}));
it('joins logs twice', async((done) => {
await(log1.add("helloA1"));
await(log2.add("helloB1"));
await(log2.join(log1));
await(log1.add("helloA2"));
await(log2.add("helloB2"));
await(log2.join(log1));
it('joins 4 logs to one', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
await(log4.add("helloD1"));
await(log4.add("helloD2"));
await(log1.join(log2));
await(log1.join(log3));
await(log1.join(log4));
const secondItem = log2.items[1];
const lastItem = _.last(log2.items);
const secondItem = log1.items[1];
const lastItem = _.last(log1.items);
assert.equal(log2._currentBatch.length, 0);
assert.equal(log2._items.length, 4);
assert.equal(secondItem.payload, 'helloA1');
assert.equal(lastItem.payload, 'helloA2');
done();
}));
assert.equal(log1._currentBatch.length, 0);
assert.equal(log1._items.length, 8);
assert.equal(secondItem.payload, 'helloA2');
assert.equal(lastItem.payload, 'helloD2');
done();
}));
it('joins 4 logs to one', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
await(log4.add("helloD1"));
await(log4.add("helloD2"));
await(log1.join(log2));
await(log1.join(log3));
await(log1.join(log4));
it('joins logs from 4 logs', async((done) => {
await(log1.add("helloA1"));
await(log1.join(log2));
await(log2.add("helloB1"));
await(log2.join(log1));
await(log1.add("helloA2"));
await(log2.add("helloB2"));
await(log1.join(log3));
await(log3.join(log1));
await(log3.add("helloC1"));
await(log4.add("helloD1"));
await(log3.add("helloC2"));
await(log4.add("helloD2"));
await(log1.join(log3));
await(log1.join(log2));
await(log4.join(log2));
await(log4.join(log1));
await(log4.join(log3));
await(log4.add("helloD3"));
await(log4.add("helloD4"));
const secondItem = log4.items[1];
const lastItem1 = _.last(log4._items);
const lastItem2 = _.last(log4.items);
assert.equal(log4._currentBatch.length, 2);
assert.equal(log4._items.length, 8);
assert.equal(secondItem.payload, 'helloD2');
assert.equal(lastItem1.payload, 'helloC2');
assert.equal(lastItem2.payload, 'helloD4');
done();
}));
const secondItem = log1.items[1];
const lastItem = _.last(log1.items);
it('fetches items from history on join', async((done) => {
const count = 32;
for(let i = 1; i < count + 1; i ++) {
await(log1.add("first " + i));
await(log2.add("second " + i));
}
assert.equal(log1._currentBatch.length, 0);
assert.equal(log1._items.length, 8);
assert.equal(secondItem.payload, 'helloA2');
assert.equal(lastItem.payload, 'helloD2');
done();
}));
const hash1 = await(Log.getIpfsHash(ipfs, log1));
const hash2 = await(Log.getIpfsHash(ipfs, log2));
it('joins logs from 4 logs', async((done) => {
await(log1.add("helloA1"));
await(log1.join(log2));
await(log2.add("helloB1"));
await(log2.join(log1));
await(log1.add("helloA2"));
await(log2.add("helloB2"));
await(log1.join(log3));
await(log3.join(log1));
await(log3.add("helloC1"));
await(log4.add("helloD1"));
await(log3.add("helloC2"));
await(log4.add("helloD2"));
await(log1.join(log3));
await(log1.join(log2));
await(log4.join(log2));
await(log4.join(log1));
await(log4.join(log3));
await(log4.add("helloD3"));
await(log4.add("helloD4"));
const secondItem = log4.items[1];
const lastItem1 = _.last(log4._items);
const lastItem2 = _.last(log4.items);
assert.equal(log4._currentBatch.length, 2);
assert.equal(log4._items.length, 8);
assert.equal(secondItem.payload, 'helloD2');
assert.equal(lastItem1.payload, 'helloC2');
assert.equal(lastItem2.payload, 'helloD4');
done();
}));
const other1 = await(Log.fromIpfsHash(ipfs, hash1));
const other2 = await(Log.fromIpfsHash(ipfs, hash2));
await(log3.join(other1));
it('fetches items from history on join', async((done) => {
const count = 32;
for(let i = 1; i < count + 1; i ++) {
await(log1.add("first " + i));
await(log2.add("second " + i));
}
assert.equal(_.includes(log3.items.map((a) => a.hash), undefined), false);
assert.equal(log3.items.length, count);
assert.equal(log3.items[0].payload, "first 1");
assert.equal(_.last(log3.items).payload, "first " + count);
const hash1 = await(Log.getIpfsHash(ipfs, log1));
const hash2 = await(Log.getIpfsHash(ipfs, log2));
await(log3.join(other2));
assert.equal(log3.items.length, count * 2);
assert.equal(log3.items[0].payload, "second 1");
assert.equal(_.last(log3.items).payload, "second " + count);
done();
}));
const other1 = await(Log.fromIpfsHash(ipfs, hash1));
const other2 = await(Log.fromIpfsHash(ipfs, hash2));
await(log3.join(other1));
it('orders fetched items correctly', async((done) => {
const count = Log.batchSize * 3;
for(let i = 1; i < (count * 2) + 1; i ++)
await(log1.add("first " + i));
assert.equal(_.includes(log3.items.map((a) => a.hash), undefined), false);
assert.equal(log3.items.length, count);
assert.equal(log3.items[0].payload, "first 1");
assert.equal(_.last(log3.items).payload, "first " + count);
const hash1 = await(Log.getIpfsHash(ipfs, log1));
const other1 = await(Log.fromIpfsHash(ipfs, hash1));
await(log3.join(other1));
await(log3.join(other2));
assert.equal(log3.items.length, count * 2);
assert.equal(log3.items[0].payload, "second 1");
assert.equal(_.last(log3.items).payload, "second " + count);
done();
}));
assert.equal(log3.items[0].payload, "first 1");
assert.equal(log3.items[log3.items.length - 1].payload, "first " + count * 2);
assert.equal(log3.items.length, count * 2);
it('orders fetched items correctly', async((done) => {
const count = Log.batchSize * 3;
for(let i = 1; i < (count * 2) + 1; i ++)
await(log1.add("first " + i));
// Second batch
for(let i = 1; i < count + 1; i ++)
await(log2.add("second " + i));
const hash1 = await(Log.getIpfsHash(ipfs, log1));
const other1 = await(Log.fromIpfsHash(ipfs, hash1));
await(log3.join(other1));
const hash2 = await(Log.getIpfsHash(ipfs, log2));
const other2 = await(Log.fromIpfsHash(ipfs, hash2));
await(log3.join(other2));
assert.equal(log3.items[0].payload, "first 1");
assert.equal(log3.items[log3.items.length - 1].payload, "first " + count * 2);
assert.equal(log3.items.length, count * 2);
assert.equal(log3.items.length, count + count * 2);
assert.equal(log3.items[0].payload, "second 1");
assert.equal(log3.items[1].payload, "second 2");
assert.equal(_.last(log3.items).payload, "second " + count);
done();
}));
});
// Second batch
for(let i = 1; i < count + 1; i ++)
await(log2.add("second " + i));
describe('_fetchRecursive', () => {
it('returns two items when neither are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
const entry1 = await(Entry.create(ipfs, 'one'))
const entry2 = await(Entry.create(ipfs, 'two', entry1))
const items = await(log1._fetchRecursive(ipfs, entry2.hash, [], 1000, 0));
assert.equal(items.length, 2);
assert.equal(items[0].hash, 'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR');
assert.equal(items[1].hash, 'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi');
done();
}));
const hash2 = await(Log.getIpfsHash(ipfs, log2));
const other2 = await(Log.fromIpfsHash(ipfs, hash2));
await(log3.join(other2));
it('returns three items when none are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
const entry1 = await(Entry.create(ipfs, 'one'))
const entry2 = await(Entry.create(ipfs, 'two', entry1))
const entry3 = await(Entry.create(ipfs, 'three', entry2))
const items = await(log1._fetchRecursive(ipfs, entry3.hash, [], 1000, 0));
assert.equal(items.length, 3);
assert.equal(items[0].hash, 'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR');
assert.equal(items[1].hash, 'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi');
assert.equal(items[2].hash, 'QmQM4Xg6EGGGEKRYu3jX3cpTcXK53XvSgQpxZd2qGY1L2V');
done();
}));
assert.equal(log3.items.length, count + count * 2);
assert.equal(log3.items[0].payload, "second 1");
assert.equal(log3.items[1].payload, "second 2");
assert.equal(_.last(log3.items).payload, "second " + count);
done();
}));
});
it('returns all items when none are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
let entrys = [];
const amount = Log.batchSize * 4;
for(let i = 1; i <= amount; i ++) {
const prev = _.last(entrys);
const n = await(Entry.create(ipfs, 'entry' + i, prev ? prev : null))
entrys.push(n);
}
describe('_fetchRecursive', () => {
it('returns two items when neither are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
const entry1 = await(Entry.create(ipfs, 'one'))
const entry2 = await(Entry.create(ipfs, 'two', entry1))
const items = await(log1._fetchRecursive(ipfs, entry2.hash, [], 1000, 0));
assert.equal(items.length, 2);
assert.equal(items[0].hash, 'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR');
assert.equal(items[1].hash, 'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi');
done();
}));
const items = await(log1._fetchRecursive(ipfs, _.last(entrys).hash, [], 1000, 0));
assert.equal(items.length, amount);
assert.equal(items[0].hash, entrys[0].hash);
assert.equal(_.last(items).hash, _.last(entrys).hash);
done();
}));
it('returns three items when none are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
const entry1 = await(Entry.create(ipfs, 'one'))
const entry2 = await(Entry.create(ipfs, 'two', entry1))
const entry3 = await(Entry.create(ipfs, 'three', entry2))
const items = await(log1._fetchRecursive(ipfs, entry3.hash, [], 1000, 0));
assert.equal(items.length, 3);
assert.equal(items[0].hash, 'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR');
assert.equal(items[1].hash, 'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi');
assert.equal(items[2].hash, 'QmQM4Xg6EGGGEKRYu3jX3cpTcXK53XvSgQpxZd2qGY1L2V');
done();
}));
it('returns only the items that are not in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
const entry1 = await(log1.add('one'))
const entry2 = await(Entry.create(ipfs, 'two', entry1))
const entry3 = await(Entry.create(ipfs, 'three', entry2))
const allHashes = log1.items.map((a) => a.hash);
const items = await(log1._fetchRecursive(ipfs, entry3.hash, allHashes, 1000, 0));
assert.equal(items.length, 2);
assert.equal(items[0].hash, 'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi');
assert.equal(items[1].hash, 'QmQM4Xg6EGGGEKRYu3jX3cpTcXK53XvSgQpxZd2qGY1L2V');
done();
}));
});
it('returns all items when none are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
let entrys = [];
const amount = Log.batchSize * 4;
for(let i = 1; i <= amount; i ++) {
const prev = _.last(entrys);
const n = await(Entry.create(ipfs, 'entry' + i, prev ? prev : null))
entrys.push(n);
}
describe('findHeads', () => {
it('finds one head after one item', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
const items = await(log1._fetchRecursive(ipfs, _.last(entrys).hash, [], 1000, 0));
assert.equal(items.length, amount);
assert.equal(items[0].hash, entrys[0].hash);
assert.equal(_.last(items).hash, _.last(entrys).hash);
done();
}));
await(log1.add("helloA1"));
it('returns only the items that are not in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
const entry1 = await(log1.add('one'))
const entry2 = await(Entry.create(ipfs, 'two', entry1))
const entry3 = await(Entry.create(ipfs, 'three', entry2))
const allHashes = log1.items.map((a) => a.hash);
const items = await(log1._fetchRecursive(ipfs, entry3.hash, allHashes, 1000, 0));
assert.equal(items.length, 2);
assert.equal(items[0].hash, 'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi');
assert.equal(items[1].hash, 'QmQM4Xg6EGGGEKRYu3jX3cpTcXK53XvSgQpxZd2qGY1L2V');
done();
}));
});
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], 'QmUEH5SEuRZhZ7RETwEX2df2BtTR2xUYZR3qBrhjnxqocb');
done();
}));
describe('findHeads', () => {
it('finds one head after one item', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
it('finds one head after two items', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
await(log1.add("helloA1"));
await(log1.add("helloA1"));
await(log1.add("helloA2"));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], 'QmUEH5SEuRZhZ7RETwEX2df2BtTR2xUYZR3qBrhjnxqocb');
done();
}));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], 'Qma1PaYbyW1rZA4npPnuJzA3ov5Je4N9cvAn2p6Ju1iPQS');
done();
}));
it('finds one head after two items', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
it('finds two heads after a join', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log1.add("helloA1"));
const expectedHead1 = await(log1.add("helloA2"));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], 'Qma1PaYbyW1rZA4npPnuJzA3ov5Je4N9cvAn2p6Ju1iPQS');
done();
}));
await(log2.add("helloB1"));
const expectedHead2 = await(log2.add("helloB2"));
it('finds two heads after a join', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
await(log1.join(log2));
await(log1.add("helloA1"));
const expectedHead1 = await(log1.add("helloA2"));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 2);
assert.equal(heads[0], expectedHead2.hash);
assert.equal(heads[1], expectedHead1.hash);
done();
}));
await(log2.add("helloB1"));
const expectedHead2 = await(log2.add("helloB2"));
it('finds one head after two joins', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
await(log1.join(log2));
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.add("helloA3"));
const expectedHead = await(log1.add("helloA4"));
await(log1.join(log2));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 2);
assert.equal(heads[0], expectedHead2.hash);
assert.equal(heads[1], expectedHead1.hash);
done();
}));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], expectedHead.hash);
done();
}));
it('finds one head after two joins', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
it('finds two heads after three joins', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.add("helloA3"));
const expectedHead = await(log1.add("helloA4"));
await(log1.join(log2));
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.add("helloA3"));
const expectedHead1 = await(log1.add("helloA4"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
await(log2.join(log3));
const expectedHead2 = await(log2.add("helloB3"));
await(log1.join(log2));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], expectedHead.hash);
done();
}));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 2);
assert.equal(heads[0], expectedHead2.hash);
assert.equal(heads[1], expectedHead1.hash);
done();
}));
it('finds two heads after three joins', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
it('finds three heads after three joins', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.add("helloA3"));
const expectedHead1 = await(log1.add("helloA4"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
await(log2.join(log3));
const expectedHead2 = await(log2.add("helloB3"));
await(log1.join(log2));
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.add("helloA3"));
const expectedHead1 = await(log1.add("helloA4"));
await(log3.add("helloC1"));
const expectedHead2 = await(log2.add("helloB3"));
const expectedHead3 = await(log3.add("helloC2"));
await(log1.join(log2));
await(log1.join(log3));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 2);
assert.equal(heads[0], expectedHead2.hash);
assert.equal(heads[1], expectedHead1.hash);
done();
}));
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 3);
assert.equal(heads[0], expectedHead3.hash);
assert.equal(heads[1], expectedHead2.hash);
assert.equal(heads[2], expectedHead1.hash);
done();
}));
});
it('finds three heads after three joins', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
const log3 = new Log(ipfs, 'C');
describe('isReferencedInChain', () => {
it('returns true if another entry in the log references the given entry', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const res = Log.isReferencedInChain(log, entry1);
assert.equal(res, true)
done();
}));
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log1.join(log2));
await(log1.add("helloA3"));
const expectedHead1 = await(log1.add("helloA4"));
await(log3.add("helloC1"));
const expectedHead2 = await(log2.add("helloB3"));
const expectedHead3 = await(log3.add("helloC2"));
await(log1.join(log2));
await(log1.join(log3));
it('returns false if no other entry in the log references the given entry', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const res = Log.isReferencedInChain(log, entry2);
assert.equal(res, false)
done();
}));
});
// const heads = Log.findHeads(log1)
const heads = log1._heads;
assert.equal(heads.length, 3);
assert.equal(heads[0], expectedHead3.hash);
assert.equal(heads[1], expectedHead2.hash);
assert.equal(heads[2], expectedHead1.hash);
done();
}));
});
describe('_commit', () => {
it('moves entrys from current batch to all known entrys', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
describe('isReferencedInChain', () => {
it('returns true if another entry in the log references the given entry', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const res = Log.isReferencedInChain(log, entry1);
assert.equal(res, true)
done();
}));
assert.equal(log._items.length, 0)
assert.equal(log._currentBatch.length, 2)
it('returns false if no other entry in the log references the given entry', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const res = Log.isReferencedInChain(log, entry2);
assert.equal(res, false)
done();
}));
});
log._commit();
describe('_commit', () => {
it('moves entrys from current batch to all known entrys', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
assert.equal(log._items.length, 2)
assert.equal(log._currentBatch.length, 0)
done();
}));
});
assert.equal(log._items.length, 0)
assert.equal(log._currentBatch.length, 2)
describe('_insert', () => {
it('insert entry to the log before current batch if parent is in current bathc', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const entry3 = await(Entry.create(ipfs, 'three', entry1))
log._insert(entry3);
assert.equal(log.items.length, 3)
assert.equal(log.items[0].payload, 'three')
assert.equal(log._items.length, 1)
assert.equal(log._items[0].payload, 'three')
done();
}));
log._commit();
it('insert to the log after the parent when parent is not in the current batch', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const entry3 = await(Entry.create(ipfs, 'three', entry1))
log._commit();
log._insert(entry3);
assert.equal(log.items.length, 3)
assert.equal(log.items[1].payload, 'three')
done();
}));
});
assert.equal(log._items.length, 2)
assert.equal(log._currentBatch.length, 0)
done();
}));
});
describe('is a CRDT', () => {
let log1, log2, log3;
describe('_insert', () => {
it('insert entry to the log before current batch if parent is in current bathc', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const entry3 = await(Entry.create(ipfs, 'three', entry1))
log._insert(entry3);
assert.equal(log.items.length, 3)
assert.equal(log.items[0].payload, 'three')
assert.equal(log._items.length, 1)
assert.equal(log._items[0].payload, 'three')
done();
}));
beforeEach(async((done) => {
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
done();
}));
it('insert to the log after the parent when parent is not in the current batch', async((done) => {
const log = new Log(ipfs, 'A');
const entry1 = await(log.add('one'));
const entry2 = await(log.add('two'));
const entry3 = await(Entry.create(ipfs, 'three', entry1))
log._commit();
log._insert(entry3);
assert.equal(log.items.length, 3)
assert.equal(log.items[1].payload, 'three')
done();
}));
});
it('join is associative', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
describe('is a CRDT', () => {
let log1, log2, log3;
// a + (b + c)
await(log2.join(log3));
await(log1.join(log2));
beforeEach(async((done) => {
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
done();
}));
const res1 = log1.items.map((e) => e.hash).join(",");
it('join is associative', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
// a + (b + c)
await(log2.join(log3));
await(log1.join(log2));
// (a + b) + c
await(log1.join(log2));
await(log1.join(log3));
const res1 = log1.items.map((e) => e.hash).join(",");
const res2 = log1.items.map((e) => e.hash).join(",");
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
await(log3.add("helloC1"));
await(log3.add("helloC2"));
// associativity: a + (b + c) == (a + b) + c
const len = (46 + 1) * 6- 1; // 46 == ipfs hash, +1 == .join(","), * 4 == number of items, -1 == last item doesn't get a ',' from .join
assert.equal(res1.length, len)
assert.equal(res2.length, len)
assert.equal(res1, res2);
done();
}));
// (a + b) + c
await(log1.join(log2));
await(log1.join(log3));
it('join is commutative', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.join(log1));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
const res2 = log1.items.map((e) => e.hash).join(",");
// b + a
await(log2.join(log1));
// associativity: a + (b + c) == (a + b) + c
const len = (46 + 1) * 6- 1; // 46 == ipfs hash, +1 == .join(","), * 4 == number of items, -1 == last item doesn't get a ',' from .join
assert.equal(res1.length, len)
assert.equal(res2.length, len)
assert.equal(res1, res2);
done();
}));
const res1 = log2.items.map((e) => e.hash).join(",");
it('join is commutative', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log2.join(log1));
await(log2.add("helloB1"));
await(log2.add("helloB2"));
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
await(log1.add("helloA1"))
await(log1.add("helloA2"))
await(log2.join(log1))
await(log2.add("helloB1"))
await(log2.add("helloB2"))
// b + a
await(log2.join(log1));
// a + b
await(log1.join(log2));
const res1 = log2.items.map((e) => e.hash).join(",");
const res2 = log1.items.map((e) => e.hash).join(",");
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
await(log1.add("helloA1"))
await(log1.add("helloA2"))
await(log2.join(log1))
await(log2.add("helloB1"))
await(log2.add("helloB2"))
// commutativity: a + (b + c) == (a + b) + c
const len = (46 + 1) * 4 - 1; // 46 == ipfs hash length, +1 == .join(","), * 4 == number of items, -1 == last item doesn't get a ',' from .join
assert.equal(res1.length, len)
assert.equal(res2.length, len)
assert.equal(res1, res2);
done();
}));
// a + b
await(log1.join(log2));
const res2 = log1.items.map((e) => e.hash).join(",");
it('join is idempotent', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log1.add("helloA3"));
await(log2.add("helloA1"));
await(log2.add("helloA2"));
await(log2.add("helloA3"));
// commutativity: a + (b + c) == (a + b) + c
const len = (46 + 1) * 4 - 1; // 46 == ipfs hash length, +1 == .join(","), * 4 == number of items, -1 == last item doesn't get a ',' from .join
assert.equal(res1.length, len)
assert.equal(res2.length, len)
assert.equal(res1, res2);
done();
}));
// idempotence: a + a = a
await(log1.join(log2));
assert.equal(log1.id, 'A');
assert.equal(log1.items.length, 3);
done();
}));
});
});
it('join is idempotent', async((done) => {
await(log1.add("helloA1"));
await(log1.add("helloA2"));
await(log1.add("helloA3"));
await(log2.add("helloA1"));
await(log2.add("helloA2"));
await(log2.add("helloA3"));
// idempotence: a + a = a
await(log1.join(log2));
assert.equal(log1.id, 'A');
assert.equal(log1.items.length, 3);
done();
}));
});
}));
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc