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.12 to 1.5.0

39

examples/benchmark.js
'use strict';
const await = require('asyncawait/await');
const async = require('asyncawait/async');
const Log = require('../src/log');

@@ -14,3 +12,3 @@ const Entry = require('../src/entry');

ipfsd.disposableApi((err, ipfs) => {
if(err) console.error(err);
if(err) reject(err)
resolve(ipfs);

@@ -39,8 +37,24 @@ });

let lastTenSeconds = 0;
let store;
let log;
const queryLoop = () => {
log.add(totalQueries)
.then(() => {
totalQueries ++;
lastTenSeconds ++;
queriesPerSecond ++;
setTimeout(() => {
process.nextTick(queryLoop);
}, 0)
})
.catch((e) => {
console.log(e)
process.exit(0);
})
}
let run = (() => {
console.log("Starting IPFS...");
console.log("Starting benchmark...");
startIpfs().then(async((ipfs) => {
startIpfs().then((ipfs) => {
// Output metrics at 1 second interval

@@ -59,15 +73,8 @@ setInterval(() => {

const log = new Log(ipfs, 'A');
for(var i = 0; i < 20000; i ++) {
await(log.add(totalQueries));
totalQueries ++;
lastTenSeconds ++;
queriesPerSecond ++;
}
log = new Log(ipfs, 'A');
queryLoop()
}).catch((e) => console.error(e))
process.exit(0);
})).catch((e) => console.error(e));
})();
module.exports = run;
{
"name": "ipfs-log",
"version": "1.4.12",
"version": "1.5.0",
"description": "Append-only log for IPFS",

@@ -10,6 +10,5 @@ "main": "src/log.js",

"bluebird": "^3.3.5",
"buffer": "^4.5.1",
"lazy.js": "^0.4.2",
"lodash.differencewith": "^4.4.0",
"lodash.flatten": "^4.3.0",
"lodash.take": "^4.1.1",
"lodash.unionwith": "^4.5.0"

@@ -23,2 +22,3 @@ },

"babel-preset-es2015": "^6.6.0",
"buffer": "^4.5.1",
"brfs": "^1.4.3",

@@ -28,3 +28,3 @@ "exports-loader": "^0.6.3",

"ipfs": "^0.13.0",
"ipfs-api": "^6.0.3",
"ipfs-api": "^7.0.0",
"ipfs-merkle-dag": "^0.6.0",

@@ -34,4 +34,3 @@ "ipfsd-ctl": "^0.14.0",

"libp2p-ipfs-browser": "^0.12.0",
"logplease": "^1.2.7",
"mocha": "^2.4.5",
"mocha": "^3.0.1",
"stream-http": "^2.2.1",

@@ -38,0 +37,0 @@ "transform-loader": "^0.2.3",

@@ -25,2 +25,3 @@ # ipfs-log

## Install
```

@@ -34,9 +35,18 @@ npm install ipfs-log

### Quick Example
### Quick Start
Install dependencies:
```
npm install ipfs-log ipfs
```
Run a simple program:
```javascript
const IPFS = require('ipfs')
const Log = require('ipfs-log');
const Log = require('ipfs-log')
const ipfs = new IPFS();
const log = new Log(ipfs, 'A');
const ipfs = new IPFS()
const log = new Log(ipfs, 'A')

@@ -47,35 +57,57 @@ log.add({ some: 'data' })

// [Entry {
// payload: { some: 'data' },
// hash: 'QmYiefTHzCLNroCfKw7YTUy9Yo53sCfwzyU5p7SBBxTcmD',
// next: []
// },
// Entry {
// payload: 'text',
// hash: 'QmdNFpoyXLNdR8Wx5LYZBLcXH8aAEopSMnnubWLn4AciCZ',
// next: [ 'QmYiefTHzCLNroCfKw7YTUy9Yo53sCfwzyU5p7SBBxTcmD' ]
// }]
// [
// {
// payload: { some: 'data' },
// hash: 'QmYiefTHzCLNroCfKw7YTUy9Yo53sCfwzyU5p7SBBxTcmD',
// next: []
// },
// {
// payload: 'text',
// hash: 'QmdNFpoyXLNdR8Wx5LYZBLcXH8aAEopSMnnubWLn4AciCZ',
// next: [ 'QmYiefTHzCLNroCfKw7YTUy9Yo53sCfwzyU5p7SBBxTcmD' ]
// }
// ]
```
### Node.js
See [examples](https://github.com/haadcode/ipfs-log/tree/master/examples) for details.
#### Run
```
node examples/log.js
```
#### Code
```javascript
const IPFS = require('ipfs')
const Log = require('ipfs-log');
const Log = require('ipfs-log')
const log = new Log(new IPFS(), 'A', 'db name', { maxHistory: 1000 });
const log = new Log(new IPFS(), 'A', { maxHistory: 1000 })
log.add('one')
.then((entry1) => {
console.log('Entry1:', entry1.hash, entry1.payload);
return log.add('two');
console.log('Entry1:', entry1.hash, entry1.payload)
return log.add('two')
})
.then((entry2) => {
console.log('Entry2:', entry2.hash, entry2.payload);
console.log('Entry2.next:', entry2.next[0]); // == entry1.hash
});
console.log('Entry2:', entry2.hash, entry2.payload)
console.log('Entry2.next:', entry2.next[0]) // == entry1.hash
})
```
### Browser
*The distribution package for browsers is located in [dist/ipfslog.min.js](https://github.com/haadcode/ipfs-log/tree/master/dist)*
See [examples/browser](https://github.com/haadcode/ipfs-log/tree/master/examples/browser) for details.
#### Run
Open [examples/browser/index.html](https://github.com/haadcode/ipfs-log/tree/master/examples/browser/index.html) or [examples/browser/browser.html](https://github.com/haadcode/ipfs-log/tree/master/examples/browser/browser.html) in your browser.
#### Code
```html

@@ -90,12 +122,12 @@ <html>

<script type="text/javascript">
const ipfs = new window.Ipfs();
const ipfs = new window.Ipfs()
const log = new Log(ipfs, 'A')
log.add('one')
.then((entry1) => {
console.log('Entry1:', entry1.hash, entry1.payload, entry1);
console.log('Entry1:', entry1.hash, entry1.payload, entry1)
return log.add('two')
})
.then((entry2) => {
console.log('Entry2:', entry2.hash, entry2.payload, entry2);
console.log("Entry2.next:", entry2.next[0]);
console.log('Entry2:', entry2.hash, entry2.payload, entry2)
console.log("Entry2.next:", entry2.next[0])
});

@@ -107,3 +139,3 @@ </script>

#### Building the examples
#### Building the browser examples

@@ -118,16 +150,19 @@ ```

### Log
```javascript
const Log = require('ipfs-log');
const Log = require('ipfs-log')
```
#### Instance methods
##### constructor(ipfs, id, [name], [options])
#### Instance Methods
##### constructor(ipfs, id, [options])
Create a log. The first argument is an `ipfs` instance which can be of type `js-ipfs` or `js-ipfs-api`. See https://github.com/ipfs/js-ipfs-api for IPFS api documentation.
```javascript
const ipfs = require('ipfs')(); // ipfs javascript implementation
const ipfs = require('ipfs')() // ipfs javascript implementation
// Or
const ipfs = require('ipfs-api')(); // local ipfs daemon (go-ipfs)
const ipfs = require('ipfs-api')() // local ipfs daemon (go-ipfs)
const log = new Log(ipfs, 'userid', 'name of the log');
const log = new Log(ipfs, 'logid') // 'logid' is a unique identifier for the log, this can usually be a user id
```

@@ -139,4 +174,2 @@

`name` is the name of the log for convenience purposes.
`options` are the following:

@@ -150,2 +183,3 @@ ```javscript

##### add(data)
Add a log entry. The new entry gets the references to previous entries automatically. Returns a *Promise* that resolves to the added `Entry`.

@@ -160,3 +194,4 @@

// [Entry {
//[
// {
// payload: { some: 'data' },

@@ -166,10 +201,12 @@ // hash: 'QmYiefTHzCLNroCfKw7YTUy9Yo53sCfwzyU5p7SBBxTcmD',

// },
// Entry {
// {
// payload: 'text',
// hash: 'QmdNFpoyXLNdR8Wx5LYZBLcXH8aAEopSMnnubWLn4AciCZ',
// next: [ 'QmYiefTHzCLNroCfKw7YTUy9Yo53sCfwzyU5p7SBBxTcmD' ]
// }]
// }
//]
```
##### join(other)
Joins the log with `other` log. Fetches history up to `options.maxHistory` items, ie. items that are not in this log but referred to in items in `other`. Returns a *Promise* that resolves to an `Array` of items that were added.

@@ -181,3 +218,3 @@

log1.join(log2).then((added) => console.log(added)); // ==> ['D', 'E']
log1.join(log2).then((added) => console.log(added)) // ==> ['D', 'E']

@@ -188,2 +225,3 @@ // log1.items ==> ['A', 'B', 'C', 'D', 'E']

##### items
Returns an `Array` of all items in the log.

@@ -197,17 +235,18 @@

##### snapshot
Returns a *snapshot* of the log with items in the current batch. Current batch are the items in the log that have been added locally after the latest join with another log.
```javascript
const snapshot = log.snapshot;
const snapshot = log.snapshot
// snapshot ==> { id: 'log id', items: ['A', 'B', 'C']}
```
#### Class methods
#### Static Methods
All class methods take an `ipfs` instance as the first parameter. The ipfs can be of `js-ipfs` or `js-ipfs-api`. See https://github.com/ipfs/js-ipfs-api for IPFS api documentation.
All static methods take an `ipfs` instance as the first parameter. The ipfs can be of `js-ipfs` or `js-ipfs-api`. See https://github.com/ipfs/js-ipfs-api for IPFS api documentation.
```javascript
const ipfs = require('ipfs')(); // js-ipfs
const ipfs = require('ipfs')() // js-ipfs
// Or
const ipfs = require('ipfs-api')(); // local ipfs daemon
const ipfs = require('ipfs-api')() // local ipfs daemon
```

@@ -218,6 +257,7 @@

##### getIpfsHash(ipfs, log)
Get the IPFS hash of this log. Returns a `Promise` that resolves to an IPFS `hash`.
```javascript
Log.getIpfsHash(ipfs, log).then((hash) => console.log(hash));
Log.getIpfsHash(ipfs, log).then((hash) => console.log(hash))
// ==> 'Qm...abc123'

@@ -227,42 +267,47 @@ ```

##### fromIpfsHash(ipfs, hash)
Create a log from an IPFS hash. Returns a `Promise` that resolves to a `Log` instance.
```javascript
Log.fromIpfsHash(ipfs, hash).then((log) => console.log(log));
Log.fromIpfsHash(ipfs, hash).then((log) => console.log(log))
// ==> instance of Log
```
##### fromSnapshot(ipfs, snapshot)
Create a log from a log snapshot. Returns a `Promise` that resolves a `Log` instance.
## Tests
```javascript
const original = new Log(ipfs, 'id')
```
npm install
npm test
```
// Add items to the original log
// ...
## Build
const snapshot = original.snapshot;
Log.fromSnapshot(ipfs, snapshot).then((log) => console.log(log));
// ==> log is instance of Log and contains the same entries as original log
The build script will build the distribution file for browsers.
```
npm run build
```
### Entry
## Benchmark
**TODO: document [Entry](https://github.com/haadcode/ipfs-log/blob/master/examples/entry.js).**
There's a simple [benchmark program](https://github.com/haadcode/ipfs-log/blob/master/examples/benchmark.js) that can be used to compare performance between two version of `ipfs-log`. It measures write ops / second.
## Tests
```
npm install
npm test
node examples/benchmark.js
```
## Build
The build script will build the distribution file for browsers.
This will output:
```
npm run build
Starting benchmark...
131 queries per second, 131 queries in 1 seconds
50 queries per second, 181 queries in 2 seconds
44 queries per second, 225 queries in 3 seconds
84 queries per second, 309 queries in 4 seconds
111 queries per second, 420 queries in 5 seconds
142 queries per second, 562 queries in 6 seconds
157 queries per second, 719 queries in 7 seconds
195 queries per second, 914 queries in 8 seconds
171 queries per second, 1085 queries in 9 seconds
--> Average of 125 q/s in the last 10 seconds
...
```
## TODO
- Node.js Stream API
- Support for encrypting the hashes
- Support for payload encryption

@@ -1,59 +0,74 @@

'use strict';
'use strict'
class Entry {
constructor(payload, next) {
this.payload = payload || null;
this.hash = null;
this.next = next ? (next instanceof Array ? next : [next]) : [];
this.next = this.next.map((next) => next instanceof Entry ? next.hash : next) // Convert instances of Entry to hashes
}
module.exports = class Entry {
// Returns a Promise<Entry>
// Example:
// Entry.create(ipfs, "hello")
// .then((entry) => console.log(entry)) // { hash: "Qm...Foo", payload: "hello", next: null }
static create(ipfs, data, next = []) {
if (!ipfs) throw new Error("Entry requires ipfs instance")
get asJson() {
let res = { payload: this.payload }
let next = this.next.map((entry) => entry instanceof Entry ? entry.hash : entry) // Convert instances of Entry to hashes
Object.assign(res, { next: next });
return res;
}
// convert single objects to an array and entry objects to single hashes
let nexts = next !== null && next instanceof Array
? next.map((e) => e.hash ? e.hash : e)
: [(next !== null && next.hash ? next.hash : next)]
hasChild(a) {
for(let i = 0; i < this.next.length; i++) {
if(this.next[i] === a.hash)
return true;
let entry = {
hash: null, // "Qm...Foo", we'll set the hash after ipfsfying the data structure,
payload: data, // Can be any JSON.stringifyable data
next: nexts // Array of IPFS hashes
}
return false;
}
static create(ipfs, data, next) {
if(!ipfs) throw new Error("Entry requires ipfs instance")
if(data instanceof Entry) return Promise.resolve(data);
const entry = new Entry(data, next);
return Entry.getIpfsHash(ipfs, entry.asJson)
return Entry.toIpfsHash(ipfs, entry)
.then((hash) => {
entry.hash = hash;
return entry;
});
entry.hash = hash
return entry
})
}
static getIpfsHash(ipfs, entry) {
if(!ipfs) throw new Error("Entry requires ipfs instance")
// Returns a Promise<String>
// Example:
// Entry.toIpfsHash(ipfs, entry)
// .then((hash) => console.log(hash)) // "Qm...Foo"
static toIpfsHash(ipfs, entry) {
if (!ipfs) throw new Error("Entry requires ipfs instance")
const data = new Buffer(JSON.stringify(entry))
return ipfs.object.put(data)
.then((res) => res.toJSON().Hash);
.then((res) => res.toJSON().Hash)
}
// Returns a Promise<Entry>
// Example:
// Entry.fromIpfsHash(ipfs, "Qm...Foo")
// .then((entry) => console.log(entry)) // { hash: "Qm...Foo", payload: "hello", next: null }
static fromIpfsHash(ipfs, hash) {
if(!ipfs) throw new Error("Entry requires ipfs instance")
if(!hash) throw new Error("Invalid hash: " + hash)
if (!ipfs) throw new Error("Entry requires ipfs instance")
if (!hash) throw new Error("Invalid hash: " + hash)
return ipfs.object.get(hash, { enc: 'base58' })
.then((obj) => {
const f = JSON.parse(obj.toJSON().Data)
return Entry.create(ipfs, f.payload, f.next);
});
const data = JSON.parse(obj.toJSON().Data)
const entry = {
hash: hash,
payload: data.payload,
next: data.next
}
return entry
})
}
static equals(a, b) {
return a.hash === b.hash;
// Returns a boolean
// Example:
// const hasChild = Entry.hasChild(entry1, entry2)
// true|false
static hasChild(entry1, entry2) {
return entry1.next.includes(entry2.hash)
}
// Returns a boolean
// Example:
// const equal = Entry.compare(entry1, entry2)
// true|false
static compare(a, b) {
return a.hash === b.hash
}
}
module.exports = Entry;

@@ -1,2 +0,2 @@

'use strict';
'use strict'

@@ -6,26 +6,25 @@ const unionWith = require('lodash.unionwith')

const flatten = require('lodash.flatten')
const Lazy = require('lazy.js');
const Promise = require('bluebird');
const Entry = require('./entry');
const take = require('lodash.take')
const Promise = require('bluebird')
const Entry = require('./entry')
const MaxBatchSize = 10; // How many items to keep per local batch
const MaxHistory = 256; // How many items to fetch on join
const MaxBatchSize = 10 // How many items to keep per local batch
const MaxHistory = 256 // How many items to fetch on join
class Log {
constructor(ipfs, id, name, opts) {
this.id = id;
this.name = name;
this._ipfs = ipfs;
this._items = opts && opts.items ? opts.items : [];
constructor(ipfs, id, opts) {
this.id = id
this._ipfs = ipfs
this._items = opts && opts.items ? opts.items : []
this.options = { maxHistory: MaxHistory };
Object.assign(this.options, opts);
delete this.options.items;
this.options = { maxHistory: MaxHistory }
Object.assign(this.options, opts)
delete this.options.items
this._currentBatch = [];
this._heads = [];
this._currentBatch = []
this._heads = []
}
get items() {
return this._items.concat(this._currentBatch);
return this._items.concat(this._currentBatch)
}

@@ -41,37 +40,34 @@

add(data) {
if(this._currentBatch.length >= MaxBatchSize)
this._commit();
if (this._currentBatch.length >= MaxBatchSize)
this._commit()
return Entry.create(this._ipfs, data, this._heads)
.then((entry) => {
this._heads = [entry.hash];
this._currentBatch.push(entry);
return entry;
});
this._heads = [entry.hash]
this._currentBatch.push(entry)
return entry
})
}
join(other) {
if(!other.items) throw new Error("The log to join must be an instance of Log")
const diff = differenceWith(other.items, this.items, Entry.equals);
if (!other.items) throw new Error("The log to join must be an instance of Log")
const newItems = other.items.slice(0, Math.max(this.options.maxHistory, 1))
const diff = differenceWith(newItems, this.items, Entry.compare)
// TODO: need deterministic sorting for the union
const final = unionWith(this._currentBatch, diff, Entry.equals);
this._items = this._items.concat(final);
this._currentBatch = [];
const final = unionWith(this._currentBatch, diff, Entry.compare)
this._items = this._items.concat(final)
this._currentBatch = []
const nexts = Lazy(diff)
.map((f) => f.next)
.flatten()
.take(this.options.maxHistory)
.toArray();
const nexts = take(flatten(diff.map((f) => f.next)), this.options.maxHistory)
// Fetch history
return Promise.map(nexts, (f) => {
let all = this.items.map((a) => a.hash);
let all = this.items.map((a) => a.hash)
return this._fetchRecursive(this._ipfs, f, all, this.options.maxHistory - nexts.length, 0)
.then((history) => {
history.forEach((b) => this._insert(b));
return history;
});
history.forEach((b) => this._insert(b))
return history
})
}, { concurrency: 1 }).then((res) => {
this._heads = Log.findHeads(this);
this._heads = Log.findHeads(this)
return flatten(res).concat(diff)

@@ -82,20 +78,20 @@ })

_insert(entry) {
let indices = Lazy(entry.next).map((next) => Lazy(this._items).map((f) => f.hash).indexOf(next)) // Find the item's parent's indices
const index = indices.toArray().length > 0 ? Math.max(indices.max() + 1, 0) : 0; // find the largest index (latest parent)
this._items.splice(index, 0, entry);
return entry;
let indices = entry.next.map((next) => this._items.map((f) => f.hash).indexOf(next)) // Find the item's parent's indices
const index = indices.length > 0 ? Math.max(Math.max.apply(null, indices) + 1, 0) : 0 // find the largest index (latest parent)
this._items.splice(index, 0, entry)
return entry
}
_commit() {
this._items = this._items.concat(this._currentBatch);
this._currentBatch = [];
this._items = this._items.concat(this._currentBatch)
this._currentBatch = []
}
_fetchRecursive(ipfs, hash, all, amount, depth) {
const isReferenced = (list, item) => Lazy(list).reverse().find((f) => f === item) !== undefined;
let result = [];
const isReferenced = (list, item) => list.reverse().find((f) => f === item) !== undefined
let result = []
// If the given hash is in the given log (all) or if we're at maximum depth, return
if(isReferenced(all, hash) || depth >= amount)
return Promise.resolve(result);
if (isReferenced(all, hash) || depth >= amount)
return Promise.resolve(result)

@@ -105,43 +101,42 @@ // Create the entry and add it to the result

.then((entry) => {
result.push(entry);
all.push(hash);
depth ++;
result.push(entry)
all.push(hash)
depth ++
return Promise.map(entry.next, (f) => this._fetchRecursive(ipfs, f, all, amount, depth), { concurrency: 1 })
.then((res) => flatten(res.concat(result)))
});
})
}
static getIpfsHash(ipfs, log) {
if(!ipfs) throw new Error("Ipfs instance not defined")
const data = new Buffer(JSON.stringify(log.snapshot));
if (!ipfs) throw new Error("Ipfs instance not defined")
const data = new Buffer(JSON.stringify(log.snapshot))
return ipfs.object.put(data)
.then((res) => res.toJSON().Hash);
.then((res) => res.toJSON().Hash)
}
static fromIpfsHash(ipfs, hash, options) {
if(!ipfs) throw new Error("Ipfs instance not defined")
if(!hash) throw new Error("Invalid hash: " + hash)
if(!options) options = {};
let logData;
if (!ipfs) throw new Error("Ipfs instance not defined")
if (!hash) throw new Error("Invalid hash: " + hash)
if (!options) options = {}
let logData
return ipfs.object.get(hash, { enc: 'base58' })
.then((res) => logData = JSON.parse(res.toJSON().Data))
.then((res) => {
if(!logData.items) throw new Error("Not a Log instance")
if (!logData.items) throw new Error("Not a Log instance")
return Promise.all(logData.items.map((f) => Entry.fromIpfsHash(ipfs, f)))
})
.then((items) => Object.assign(options, { items: items }))
.then((items) => new Log(ipfs, logData.id, '', options))
.then((items) => new Log(ipfs, logData.id, options))
}
static findHeads(log) {
return Lazy(log.items)
return log.items
.reverse()
.filter((f) => !Log.isReferencedInChain(log, f))
.map((f) => f.hash)
.toArray();
}
static isReferencedInChain(log, item) {
return Lazy(log.items).reverse().find((e) => e.hasChild(item)) !== undefined;
return log.items.reverse().find((e) => Entry.hasChild(e, item)) !== undefined
}

@@ -154,2 +149,2 @@

module.exports = Log;
module.exports = Log

@@ -1,11 +0,11 @@

'use strict';
'use strict'
const _ = require('lodash');
const assert = require('assert');
const async = require('asyncawait/async');
const await = require('asyncawait/await');
const IpfsApis = require('./ipfs-test-apis');
const Entry = require('../src/entry');
const _ = require('lodash')
const assert = require('assert')
const async = require('asyncawait/async')
const await = require('asyncawait/await')
const IpfsApis = require('./ipfs-test-apis')
const Entry = require('../src/entry')
let ipfs, ipfsDaemon;
let ipfs, ipfsDaemon

@@ -15,217 +15,144 @@ IpfsApis.forEach(function(ipfsApi) {

describe('Entry with ' + ipfsApi.name, function() {
this.timeout(40000);
before(async((done) => {
this.timeout(20000)
before(async(() => {
try {
ipfs = await(ipfsApi.start());
ipfs = await(ipfsApi.start())
} catch(e) {
console.log(e);
assert.equal(e, null);
console.log(e)
assert.equal(e, null)
}
this.timeout(2000);
done();
}));
}))
after(async((done) => {
await(ipfsApi.stop());
done();
}));
after(async(() => {
await(ipfsApi.stop())
}))
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);
done();
}));
it('creates a an empty entry', async(() => {
const expectedHash = 'QmQf2q7RCqfs8G1nhow4MHqiRTg3fAAwgr9tKi5jhvsfuk'
const entry = await(Entry.create(ipfs))
assert.equal(entry.payload, null)
assert.equal(entry.next.length, 0)
assert.equal(entry.hash, expectedHash)
}))
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('creates a entry with payload', async(() => {
const expectedHash = 'QmTVyxLqh3qZkWZbpxkjX5hd4WXADWDxt2EamFApfYpsRv'
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)
}))
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('creates a entry with payload and next', async(() => {
const expectedHash = 'QmRzyeUuW5F8zxmEgJG3wRPH3i3W7iwPweza7UUHhXfK93'
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)
}))
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('`next` parameter can be a string', async(() => {
const entry1 = await(Entry.create(ipfs, null))
const entry2 = await(Entry.create(ipfs, null, entry1.hash))
assert.equal(typeof entry2.next[0] === 'string', true)
}))
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('`next` parameter can be an instance of Entry', async(() => {
const entry1 = await(Entry.create(ipfs, null))
const entry2 = await(Entry.create(ipfs, null, entry1))
assert.equal(typeof entry2.next[0] === 'string', true)
}))
it('throws an error if ipfs is not defined', async((done) => {
it('throws an error if ipfs is not defined', async(() => {
try {
const entry = await(Entry.create());
const entry = await(Entry.create())
} catch(e) {
assert.equal(e.message, 'Entry requires ipfs instance');
assert.equal(e.message, 'Entry requires ipfs instance')
}
done();
}));
});
}))
})
describe('toIpfsHash', () => {
it('returns an ipfs hash', async(() => {
const expectedHash = 'QmcNjhK93qwkFhGiPJ8kyPhPWagSoJoRBEx9BwSE5w8iLW'
const entry = await(Entry.create(ipfs))
const hash = await(Entry.toIpfsHash(ipfs, entry))
assert.equal(hash, expectedHash)
}))
})
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('creates a entry from ipfs hash', async(() => {
const expectedHash = 'QmRzyeUuW5F8zxmEgJG3wRPH3i3W7iwPweza7UUHhXfK93'
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)
}))
it('throws an error if ipfs is not present', async((done) => {
it('throws an error if ipfs is not present', async(() => {
try {
const entry = await(Entry.fromIpfsHash());
const entry = await(Entry.fromIpfsHash())
} catch(e) {
assert.equal(e.message, 'Entry requires ipfs instance');
assert.equal(e.message, 'Entry requires ipfs instance')
}
done();
}));
}))
it('throws an error if hash is undefined', async((done) => {
it('throws an error if hash is undefined', async(() => {
try {
const entry = await(Entry.fromIpfsHash(ipfs));
const entry = await(Entry.fromIpfsHash(ipfs))
} catch(e) {
assert.equal(e.message, 'Invalid hash: undefined');
assert.equal(e.message, 'Invalid hash: undefined')
}
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('returns true if entry has a child', async(() => {
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(Entry.hasChild(entry2, entry1), true)
}))
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 false if entry does not have a child', async(() => {
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(Entry.hasChild(entry2, entry1), false)
assert.equal(Entry.hasChild(entry3, entry1), false)
assert.equal(Entry.hasChild(entry3, entry2), true)
}))
})
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.asJson));
assert.equal(hash, expectedHash);
done();
}));
});
describe('compare', () => {
it('returns true if entries are the same', async(() => {
const payload1 = 'hello world'
const entry1 = await(Entry.create(ipfs, payload1))
const entry2 = await(Entry.create(ipfs, payload1))
assert.equal(Entry.compare(entry1, entry2), true)
}))
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 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('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('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 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();
}));
});
});
});
it('returns true if entries are not the same', async(() => {
const payload1 = 'hello world1'
const payload2 = 'hello world2'
const entry1 = await(Entry.create(ipfs, payload1))
const entry2 = await(Entry.create(ipfs, payload2))
assert.equal(Entry.compare(entry1, entry2), false)
}))
})
})
})

@@ -1,6 +0,6 @@

'use strict';
'use strict'
const IPFS = require('ipfs')
const ipfsd = require('ipfsd-ctl');
const MemIpfs = require('./mem-ipfs');
const ipfsd = require('ipfsd-ctl')
const MemIpfs = require('./mem-ipfs')

@@ -19,6 +19,6 @@ const IpfsApis = [

return new Promise((resolve, reject) => {
const ipfs = new IPFS();
// ipfs.goOnline(() => resolve(ipfs));
resolve(ipfs);
});
const ipfs = new IPFS()
// ipfs.goOnline(() => resolve(ipfs))
resolve(ipfs)
})
},

@@ -34,14 +34,14 @@ stop: () => Promise.resolve()

ipfsd.disposableApi((err, ipfs) => {
if(err) console.error(err);
resolve(ipfs);
});
if(err) console.error(err)
resolve(ipfs)
})
// ipfsd.local((err, node) => {
// if(err) reject(err);
// ipfsDaemon = node;
// if(err) reject(err)
// ipfsDaemon = node
// ipfsDaemon.startDaemon((err, ipfs) => {
// if(err) reject(err);
// resolve(ipfs);
// });
// });
});
// if(err) reject(err)
// resolve(ipfs)
// })
// })
})
},

@@ -51,4 +51,4 @@ stop: () => Promise.resolve()

}
];
]
module.exports = IpfsApis;
module.exports = IpfsApis

@@ -1,12 +0,12 @@

'use strict';
'use strict'
const _ = require('lodash');
const assert = require('assert');
const async = require('asyncawait/async');
const await = require('asyncawait/await');
const IpfsApis = require('./ipfs-test-apis');
const Log = require('../src/log');
const Entry = require('../src/entry');
const _ = require('lodash')
const assert = require('assert')
const async = require('asyncawait/async')
const await = require('asyncawait/await')
const IpfsApis = require('./ipfs-test-apis')
const Log = require('../src/log')
const Entry = require('../src/entry')
let ipfs, ipfsDaemon;
let ipfs, ipfsDaemon

@@ -16,658 +16,594 @@ IpfsApis.forEach(function(ipfsApi) {

describe('Log with ' + ipfsApi.name, function() {
this.timeout(40000);
before(async((done) => {
this.timeout(20000)
before(async(() => {
try {
ipfs = await(ipfsApi.start());
ipfs = await(ipfsApi.start())
} catch(e) {
console.log(e);
assert.equal(e, null);
console.log(e)
assert.equal(e, null)
}
this.timeout(2000);
done();
}));
}))
after(async((done) => {
await(ipfsApi.stop());
done();
}));
after(async(() => {
await(ipfsApi.stop())
}))
describe('create', async(() => {
it('creates an empty log', () => {
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);
});
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)
})
it('throws an error if ipfs is not defined', async((done) => {
it('throws an error if ipfs is not defined', async(() => {
try {
const log = new Log();
const log = new Log()
} catch(e) {
assert.equal(e.message, 'Ipfs instance not defined');
assert.equal(e.message, 'Ipfs instance not defined')
}
done();
}));
}))
it('throws an error if id is not defined', async((done) => {
it('throws an error if id is not defined', async(() => {
try {
const log = new Log(ipfs);
const log = new Log(ipfs)
} catch(e) {
assert.equal(e.message, 'id is not defined');
assert.equal(e.message, 'id is not defined')
}
done();
}));
}))
it('default maxHistory is 256', async((done) => {
const log = new Log(ipfs, 'A', 'db');
assert.equal(log.options.maxHistory, 256);
done();
}));
it('default maxHistory is 256', async(() => {
const log = new Log(ipfs, 'A')
assert.equal(log.options.maxHistory, 256)
}))
it('takes maxHistory as an option', async((done) => {
const log = new Log(ipfs, 'A', 'db', { maxHistory: 100 });
assert.equal(log.options.maxHistory, 100);
done();
}));
it('takes maxHistory as an option', async(() => {
const log = new Log(ipfs, 'A', { maxHistory: 100 })
assert.equal(log.options.maxHistory, 100)
}))
it('sets maxHistory if not provided in options', async((done) => {
const log = new Log(ipfs, 'A', 'db');
assert.equal(log.options.maxHistory, 256);
done();
}));
it('sets maxHistory if not provided in options', async(() => {
const log = new Log(ipfs, 'A')
assert.equal(log.options.maxHistory, 256)
}))
it('sets maxHistory if other options are provided', async((done) => {
const log = new Log(ipfs, 'A', 'db', { hello: "world" });
assert.equal(log.options.maxHistory, 256);
done();
}));
it('sets maxHistory if other options are provided', async(() => {
const log = new Log(ipfs, 'A', { hello: "world" })
assert.equal(log.options.maxHistory, 256)
}))
}));
}))
describe('serialize', async(() => {
let log;
let log
const expectedData = {
id: "A",
items: [
'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR',
'Qmcpgub1qRG5XHed1qNciwb74uasUhQVEhP35oaZZ7UWbi',
'QmQM4Xg6EGGGEKRYu3jX3cpTcXK53XvSgQpxZd2qGY1L2V'
'QmUrqiypsLPAWN24Y3gHarmDTgvW97bTUiXnqN53ySXM9V',
'QmTRF2oGMG7L5yP6LU1bpy2DEdLTzkRByS9nshRkMAFhBy',
'QmQG1rPMjt1RQPQTu6cJfSMSS8GddcSw9GxLkVtRB32pMD'
]
};
}
beforeEach(async((done) => {
log = new Log(ipfs, 'A');
await(log.add("one"));
await(log.add("two"));
await(log.add("three"));
done();
}));
beforeEach(async(() => {
log = new Log(ipfs, 'A')
await(log.add("one"))
await(log.add("two"))
await(log.add("three"))
}))
describe('snapshot', async(() => {
it('returns the current batch of items', async((done) => {
assert.equal(JSON.stringify(log.snapshot), JSON.stringify(expectedData));
done();
}));
}));
it('returns the current batch of items', async(() => {
assert.equal(JSON.stringify(log.snapshot), JSON.stringify(expectedData))
}))
}))
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('returns the log as ipfs hash', async(() => {
const expectedHash = 'QmaRz4njJX2W8QYwWLa1jhEbYUdJhhqibsBbnRYuWgr1r7'
const log = new Log(ipfs, 'A')
const hash = await(Log.getIpfsHash(ipfs, log))
assert.equal(hash, expectedHash)
}))
it('log serialized to ipfs contains the correct data', async((done) => {
const expectedData = { id: "A", items: [] };
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(result.id, expectedData.id);
assert.equal(result.items.length, expectedData.items.length);
done();
}));
it('log serialized to ipfs contains the correct data', async(() => {
const expectedData = { id: "A", items: [] }
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(result.id, expectedData.id)
assert.equal(result.items.length, expectedData.items.length)
}))
it('throws an error if ipfs is not defined', async((done) => {
it('throws an error if ipfs is not defined', async(() => {
try {
const log = new Log(ipfs, 'A');
const hash = await(Log.getIpfsHash(null, log));
const log = new Log(ipfs, 'A')
const hash = await(Log.getIpfsHash(null, log))
} catch(e) {
assert.equal(e.message, 'Ipfs instance not defined');
assert.equal(e.message, 'Ipfs instance not defined')
}
done();
}));
}));
}))
}))
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(ipfs, log));
const res = await(Log.fromIpfsHash(ipfs, hash));
assert.equal(JSON.stringify(res.snapshot), JSON.stringify(expectedData));
done();
}));
it('creates an empty log from ipfs hash', async(() => {
const expectedData = { id: "A", items: [] }
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))
}))
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();
}));
it('creates a log from ipfs hash', async(() => {
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('throws an error when data from hash is not instance of Log', async((done) => {
it('throws an error when data from hash is not instance of Log', async(() => {
try {
await(Log.fromIpfsHash(ipfs, 'QmRMUN4WJdpYydRLpbipaNoLQNXiw9ifRpPht5APaLFqrR'));
await(Log.fromIpfsHash(ipfs, 'QmUrqiypsLPAWN24Y3gHarmDTgvW97bTUiXnqN53ySXM9V'))
} catch(e) {
assert.equal(e.message, 'Not a Log instance');
done();
assert.equal(e.message, 'Not a Log instance')
}
}));
}))
}));
}));
}))
}))
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();
}));
it('returns all entrys in the log', async(() => {
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)
}))
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('returns all entrys from current batch and all known entrys', async(() => {
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();
}));
});
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)
}))
})
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('adds an item to an empty log', async(() => {
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')
}))
it('adds 100 items to a log', async((done) => {
const log = new Log(ipfs, 'A');
const amount = 100;
it('adds 100 items to a log', async(() => {
const log = new Log(ipfs, 'A')
const amount = 100
for(let i = 1; i <= amount; i ++) {
await(log.add("hello" + i));
await(log.add("hello" + i))
}
const last = _.last(log.items);
assert.equal(log.items.length, amount);
assert.equal(last.payload, 'hello' + amount);
assert.notEqual(last.next.length, 0);
const last = _.last(log.items)
assert.equal(log.items.length, amount)
assert.equal(last.payload, 'hello' + amount)
assert.notEqual(last.next.length, 0)
}))
done();
}));
it('commits the log after batch size was reached', async(() => {
const log = new Log(ipfs, 'A')
it('commits the log after batch size was reached', async((done) => {
const log = new Log(ipfs, 'A');
for(let i = 1; i <= Log.batchSize; i ++) {
await(log.add("hello" + i));
await(log.add("hello" + i))
}
assert.equal(log.items.length, Log.batchSize);
assert.equal(log._currentBatch.length, Log.batchSize);
assert.equal(log._items.length, 0);
assert.equal(log.items.length, Log.batchSize)
assert.equal(log._currentBatch.length, Log.batchSize)
assert.equal(log._items.length, 0)
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);
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)
}))
})
done();
}));
it('adds an Entry to the log', 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 log = new Log(ipfs, 'A');
await(log.add(entry1));
await(log.add(entry2));
assert.equal(log.items.length, 2);
assert.equal(log.items[0] instanceof Entry, true);
assert.equal(log.items[0].payload, payload1);
assert.equal(log.items[1] instanceof Entry, true);
assert.equal(log.items[1].payload, payload2);
done();
}));
});
describe('join', () => {
let log1, log2, log3, log4;
let log1, log2, log3, log4
beforeEach(async((done) => {
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
log4 = new Log(ipfs, 'D');
done();
}));
beforeEach(async(() => {
log1 = new Log(ipfs, 'A')
log2 = new Log(ipfs, 'B')
log3 = new Log(ipfs, 'C')
log4 = new Log(ipfs, 'D')
}))
it('throws an error if passed argument is not an instance of Log', async((done) => {
it('throws an error if passed argument is not an instance of Log', async(() => {
try {
await(log1.join({}));
await(log1.join({}))
} catch(e) {
assert.equal(e.message, 'The log to join must be an instance of Log');
done();
assert.equal(e.message, 'The log to join must be an instance of Log')
}
}));
}))
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 only unique items', async(() => {
await(log1.add("helloA1"))
await(log1.add("helloA2"))
await(log2.add("helloB1"))
await(log2.add("helloB2"))
await(log1.join(log2))
await(log1.join(log2))
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');
assert.equal(log1.items.length, 4)
assert.equal(log1.items[0].hash, 'QmQjjAwSt8qQQTQ52Kt3qMvS5squGiiEvrSRrkxYYMY3k2')
assert.equal(log1.items[1].hash, 'QmYFAWWAPXkyQuND7P8Fm2aLgTH7eAA44wYX8EeaYVGom9')
assert.equal(log1.items[2].hash, 'QmZDQ6FGJ1dAUogJK73Hm9TZmTe9GYx6VJYNgnh7C3cTD1')
assert.equal(log1.items[3].hash, 'Qmcn8T7WfjLd73tUpRRwYGtKc2UwdAD5sCfWYRepsbWUo3')
const last = _.last(log1.items);
assert.equal(last.next.length, 1);
assert.equal(last.next[0], 'QmdZwCR96sP61aaTbcLj9DXy9EaiMhTXLRrTxPSXpcZCct');
done();
}));
const last = _.last(log1.items)
assert.equal(last.next.length, 1)
assert.equal(last.next[0], 'QmZDQ6FGJ1dAUogJK73Hm9TZmTe9GYx6VJYNgnh7C3cTD1')
}))
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 two ways', async(() => {
await(log1.add("helloA1"))
await(log1.add("helloA2"))
await(log2.add("helloB1"))
await(log2.add("helloB2"))
await(log1.join(log2))
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 lastItem1 = _.last(log1.items)
assert.equal(log1._currentBatch.length, 0)
assert.equal(log1._items.length, 4)
assert.equal(lastItem1.payload, 'helloB2')
const lastItem2 = _.last(log2.items);
assert.equal(log2._currentBatch.length, 0);
assert.equal(log2._items.length, 4);
assert.equal(lastItem2.payload, 'helloA2');
done();
}));
const lastItem2 = _.last(log2.items)
assert.equal(log2._currentBatch.length, 0)
assert.equal(log2._items.length, 4)
assert.equal(lastItem2.payload, 'helloA2')
}))
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 logs twice', async(() => {
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 secondItem = log2.items[1];
const lastItem = _.last(log2.items);
const secondItem = log2.items[1]
const lastItem = _.last(log2.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(log2._currentBatch.length, 0)
assert.equal(log2._items.length, 4)
assert.equal(secondItem.payload, 'helloA1')
assert.equal(lastItem.payload, 'helloA2')
}))
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 4 logs to one', async(() => {
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 = log1.items[1];
const lastItem = _.last(log1.items);
const secondItem = log1.items[1]
const lastItem = _.last(log1.items)
assert.equal(log1._currentBatch.length, 0);
assert.equal(log1._items.length, 8);
assert.equal(secondItem.payload, 'helloA2');
assert.equal(lastItem.payload, 'helloD2');
done();
}));
assert.equal(log1._currentBatch.length, 0)
assert.equal(log1._items.length, 8)
assert.equal(secondItem.payload, 'helloA2')
assert.equal(lastItem.payload, 'helloD2')
}))
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();
}));
it('joins logs from 4 logs', async(() => {
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')
}))
it('fetches items from history on join', async((done) => {
const count = 32;
it('fetches items from history on join', async(() => {
const count = 32
for(let i = 1; i < count + 1; i ++) {
await(log1.add("first " + i));
await(log2.add("second " + i));
await(log1.add("first " + i))
await(log2.add("second " + i))
}
const hash1 = await(Log.getIpfsHash(ipfs, log1));
const hash2 = await(Log.getIpfsHash(ipfs, log2));
const hash1 = await(Log.getIpfsHash(ipfs, log1))
const hash2 = await(Log.getIpfsHash(ipfs, log2))
const other1 = await(Log.fromIpfsHash(ipfs, hash1));
const other2 = await(Log.fromIpfsHash(ipfs, hash2));
await(log3.join(other1));
const other1 = await(Log.fromIpfsHash(ipfs, hash1))
const other2 = await(Log.fromIpfsHash(ipfs, hash2))
await(log3.join(other1))
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);
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)
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();
}));
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)
}))
it('orders fetched items correctly', async((done) => {
const count = Log.batchSize * 3;
it('orders fetched items correctly', async(() => {
const count = Log.batchSize * 3
for(let i = 1; i < (count * 2) + 1; i ++)
await(log1.add("first " + i));
await(log1.add("first " + i))
const hash1 = await(Log.getIpfsHash(ipfs, log1));
const other1 = await(Log.fromIpfsHash(ipfs, hash1));
await(log3.join(other1));
const hash1 = await(Log.getIpfsHash(ipfs, log1))
const other1 = await(Log.fromIpfsHash(ipfs, hash1))
await(log3.join(other1))
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[0].payload, "first 1")
assert.equal(log3.items[log3.items.length - 1].payload, "first " + count * 2)
assert.equal(log3.items.length, count * 2)
// Second batch
for(let i = 1; i < count + 1; i ++)
await(log2.add("second " + i));
await(log2.add("second " + i))
const hash2 = await(Log.getIpfsHash(ipfs, log2));
const other2 = await(Log.fromIpfsHash(ipfs, hash2));
await(log3.join(other2));
const hash2 = await(Log.getIpfsHash(ipfs, log2))
const other2 = await(Log.fromIpfsHash(ipfs, hash2))
await(log3.join(other2))
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();
}));
});
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)
}))
})
describe('_fetchRecursive', () => {
it('returns two items when neither are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
it('returns two items when neither are in the log', async(() => {
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, entry2.hash, [], 1000, 0))
assert.equal(items.length, 2)
assert.equal(items[0].hash, 'QmUrqiypsLPAWN24Y3gHarmDTgvW97bTUiXnqN53ySXM9V')
assert.equal(items[1].hash, 'QmTRF2oGMG7L5yP6LU1bpy2DEdLTzkRByS9nshRkMAFhBy')
}))
it('returns three items when none are in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
it('returns three items when none are in the log', async(() => {
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();
}));
const items = await(log1._fetchRecursive(ipfs, entry3.hash, [], 1000, 0))
assert.equal(items.length, 3)
assert.equal(items[0].hash, 'QmUrqiypsLPAWN24Y3gHarmDTgvW97bTUiXnqN53ySXM9V')
assert.equal(items[1].hash, 'QmTRF2oGMG7L5yP6LU1bpy2DEdLTzkRByS9nshRkMAFhBy')
assert.equal(items[2].hash, 'QmQG1rPMjt1RQPQTu6cJfSMSS8GddcSw9GxLkVtRB32pMD')
}))
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;
it('returns all items when none are in the log', async(() => {
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);
const prev = _.last(entrys)
const n = await(Entry.create(ipfs, 'entry' + i, prev))
entrys.push(n)
}
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();
}));
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)
}))
it('returns only the items that are not in the log', async((done) => {
const log1 = new Log(ipfs, 'A');
it('returns only the items that are not in the log', async(() => {
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 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, 'QmTRF2oGMG7L5yP6LU1bpy2DEdLTzkRByS9nshRkMAFhBy')
assert.equal(items[1].hash, 'QmQG1rPMjt1RQPQTu6cJfSMSS8GddcSw9GxLkVtRB32pMD')
}))
})
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 one item', async(() => {
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"))
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], 'QmUEH5SEuRZhZ7RETwEX2df2BtTR2xUYZR3qBrhjnxqocb');
done();
}));
const heads = log1._heads
assert.equal(heads.length, 1)
assert.equal(heads[0], 'QmQjjAwSt8qQQTQ52Kt3qMvS5squGiiEvrSRrkxYYMY3k2')
}))
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 one head after two items', async(() => {
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(log1.add("helloA1"))
await(log1.add("helloA2"))
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], 'Qma1PaYbyW1rZA4npPnuJzA3ov5Je4N9cvAn2p6Ju1iPQS');
done();
}));
const heads = log1._heads
assert.equal(heads.length, 1)
assert.equal(heads[0], 'QmYFAWWAPXkyQuND7P8Fm2aLgTH7eAA44wYX8EeaYVGom9')
}))
it('finds two heads after a join', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
it('finds two heads after a join', async(() => {
const log1 = new Log(ipfs, 'A')
const log2 = new Log(ipfs, 'B')
await(log1.add("helloA1"));
const expectedHead1 = await(log1.add("helloA2"));
await(log1.add("helloA1"))
const expectedHead1 = await(log1.add("helloA2"))
await(log2.add("helloB1"));
const expectedHead2 = await(log2.add("helloB2"));
await(log2.add("helloB1"))
const expectedHead2 = await(log2.add("helloB2"))
await(log1.join(log2));
await(log1.join(log2))
const heads = log1._heads;
assert.equal(heads.length, 2);
assert.equal(heads[0], expectedHead2.hash);
assert.equal(heads[1], expectedHead1.hash);
done();
}));
const heads = log1._heads
assert.equal(heads.length, 2)
assert.equal(heads[0], expectedHead2.hash)
assert.equal(heads[1], expectedHead1.hash)
}))
it('finds one head after two joins', async((done) => {
const log1 = new Log(ipfs, 'A');
const log2 = new Log(ipfs, 'B');
it('finds one head after two joins', async(() => {
const log1 = new Log(ipfs, 'A')
const log2 = new Log(ipfs, 'B')
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 expectedHead = await(log1.add("helloA4"))
await(log1.join(log2))
const heads = log1._heads;
assert.equal(heads.length, 1);
assert.equal(heads[0], expectedHead.hash);
done();
}));
const heads = log1._heads
assert.equal(heads.length, 1)
assert.equal(heads[0], expectedHead.hash)
}))
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 two heads after three joins', async(() => {
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"))
await(log3.add("helloC2"))
await(log2.join(log3))
const expectedHead2 = await(log2.add("helloB3"))
await(log1.join(log2))
const heads = log1._heads;
assert.equal(heads.length, 2);
assert.equal(heads[0], expectedHead2.hash);
assert.equal(heads[1], expectedHead1.hash);
done();
}));
const heads = log1._heads
assert.equal(heads.length, 2)
assert.equal(heads[0], expectedHead2.hash)
assert.equal(heads[1], expectedHead1.hash)
}))
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');
it('finds three heads after three joins', async(() => {
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"));
const expectedHead2 = await(log2.add("helloB3"));
const expectedHead3 = await(log3.add("helloC2"));
await(log1.join(log2));
await(log1.join(log3));
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 = 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();
}));
});
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)
}))
})
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);
it('returns true if another entry in the log references the given entry', async(() => {
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();
}));
}))
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);
it('returns false if no other entry in the log references the given entry', async(() => {
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();
}));
});
}))
})
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'));
it('moves entrys from current batch to all known entrys', async(() => {
const log = new Log(ipfs, 'A')
const entry1 = await(log.add('one'))
const entry2 = await(log.add('two'))

@@ -677,17 +613,16 @@ assert.equal(log._items.length, 0)

log._commit();
log._commit()
assert.equal(log._items.length, 2)
assert.equal(log._currentBatch.length, 0)
done();
}));
});
}))
})
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'));
it('insert entry to the log before current batch if parent is in current bathc', async(() => {
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);
log._insert(entry3)
assert.equal(log.items.length, 3)

@@ -697,80 +632,76 @@ assert.equal(log.items[0].payload, 'three')

assert.equal(log._items[0].payload, 'three')
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'));
it('insert to the log after the parent when parent is not in the current batch', async(() => {
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);
log._commit()
log._insert(entry3)
assert.equal(log.items.length, 3)
assert.equal(log.items[1].payload, 'three')
done();
}));
});
}))
})
describe('is a CRDT', () => {
let log1, log2, log3;
let log1, log2, log3
beforeEach(async((done) => {
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log3 = new Log(ipfs, 'C');
done();
}));
beforeEach(async(() => {
log1 = new Log(ipfs, 'A')
log2 = new Log(ipfs, 'B')
log3 = new Log(ipfs, 'C')
}))
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"));
it('join is associative', async(() => {
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));
await(log2.join(log3))
await(log1.join(log2))
const res1 = log1.items.map((e) => e.hash).join(",");
const res1 = 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"));
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(log1.join(log2));
await(log1.join(log3));
await(log1.join(log2))
await(log1.join(log3))
const res2 = log1.items.map((e) => e.hash).join(",");
const res2 = log1.items.map((e) => e.hash).join(",")
// 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
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();
}));
assert.equal(res1, res2)
}))
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"));
it('join is commutative', async(() => {
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));
await(log2.join(log1))
const res1 = log2.items.map((e) => e.hash).join(",");
const res1 = log2.items.map((e) => e.hash).join(",")
log1 = new Log(ipfs, 'A');
log2 = new Log(ipfs, 'B');
log1 = new Log(ipfs, 'A')
log2 = new Log(ipfs, 'B')
await(log1.add("helloA1"))

@@ -783,33 +714,31 @@ await(log1.add("helloA2"))

// a + b
await(log1.join(log2));
await(log1.join(log2))
const res2 = log1.items.map((e) => e.hash).join(",");
const res2 = log1.items.map((e) => e.hash).join(",")
// 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
// commutativity: a + b + c == b + a + 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();
}));
assert.equal(res1, res2)
}))
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"));
it('join is idempotent', async(() => {
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));
await(log1.join(log2))
assert.equal(log1.id, 'A');
assert.equal(log1.items.length, 3);
done();
}));
});
});
assert.equal(log1.id, 'A')
assert.equal(log1.items.length, 3)
}))
})
})
});
})

@@ -1,2 +0,2 @@

const webpack = require('webpack');
const webpack = require('webpack')

@@ -17,3 +17,3 @@ module.exports = {

new webpack.optimize.UglifyJsPlugin({
mangle: true,
mangle: false,
compress: { warnings: false }

@@ -49,2 +49,2 @@ })

}
};
}

@@ -1,3 +0,3 @@

const webpack = require('webpack');
const path = require('path');
const webpack = require('webpack')
const path = require('path')

@@ -16,3 +16,3 @@ module.exports = {

new webpack.optimize.UglifyJsPlugin({
mangle: true,
mangle: false,
compress: { warnings: false }

@@ -55,2 +55,2 @@ })

}
};
}

Sorry, the diff of this file is too big to display

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