diff --git a/package.json b/package.json index 3589ecb..a6ff854 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "main": "src/Client.js", "dependencies": { "asyncawait": "^1.0.1", + "ipfs-log": "^1.0.1", "lazy.js": "^0.4.2", "lodash": "^4.3.0", "orbit-common": "^0.1.0", diff --git a/src/Client.js b/src/Client.js index b7e09fd..54a1eab 100644 --- a/src/Client.js +++ b/src/Client.js @@ -21,7 +21,7 @@ class Client { if(password === undefined) password = ''; if(subscribe === undefined) subscribe = true; - this.db.use(channel, this.user, password); + await(this.db.use(channel, this.user, password)); this.db.events[channel].on('write', this._onWrite.bind(this)); this.db.events[channel].on('sync', this._onSync.bind(this)); diff --git a/src/OrbitDB.js b/src/OrbitDB.js index 9d05e71..22c9a6a 100644 --- a/src/OrbitDB.js +++ b/src/OrbitDB.js @@ -4,7 +4,7 @@ const Lazy = require('lazy.js'); const EventEmitter = require('events').EventEmitter; const async = require('asyncawait/async'); const await = require('asyncawait/await'); -const OrbitList = require('./list/OrbitList'); +const Log = require('ipfs-log'); const DBOperation = require('./db/Operation'); const Post = require('./post/Post'); @@ -18,7 +18,7 @@ class OrbitDB { /* Public methods */ use(channel, user, password) { this.user = user; - this._logs[channel] = new OrbitList(this._ipfs, this.user.username); + this._logs[channel] = await(Log.create(this._ipfs, this.user.username)); this.events[channel] = new EventEmitter(); } @@ -26,7 +26,7 @@ class OrbitDB { // console.log("--> Head:", hash) if(hash && this._logs[channel]) { const oldCount = this._logs[channel].items.length; - const other = await(OrbitList.fromIpfsHash(this._ipfs, hash)); + const other = await(Log.fromIpfsHash(this._ipfs, hash)); await(this._logs[channel].join(other)); // Only emit the event if something was added @@ -102,7 +102,7 @@ class OrbitDB { // Find an items from the sequence (list of operations) return sequence - .map((f) => await(f.fetchPayload())) // IO - fetch the actual OP from ipfs. consider merging with LL. + .map((f) => await(OrbitDB.fetchPayload(this._ipfs, f.payload))) // IO - fetch the actual OP from ipfs. consider merging with LL. .skipWhile((f) => key && f.key !== key) // Drop elements until we have the first one requested .map(_createLWWSet) // Return items as LWW (ignore values after the first found) .compact() // Remove nulls @@ -113,33 +113,26 @@ class OrbitDB { // Write an op to the db _write(channel, password, operation, key, value) { const hash = await(DBOperation.create(this._ipfs, this._logs[channel], this.user, operation, key, value)); - const listHash = await(this._logs[channel].ipfsHash); + const listHash = await(Log.getIpfsHash(this._ipfs, this._logs[channel])); this.events[channel].emit('write', channel, listHash); return hash; } + + static fetchPayload(ipfs, hash) { + return new Promise((resolve, reject) => { + ipfs.object.get(hash) + .then((payload) => { + let data = JSON.parse(payload.Data); + Object.assign(data, { hash: hash }); + if(data.key === null) + Object.assign(data, { key: hash }); + resolve(data); + }) + .catch(reject); + }); + } } // TODO: move to where this is needed -// static fetchPayload(hash) { -// return new Promise(async((resolve, reject) => { -// if(hash) { -// this._ipfs.object.get(hash) -// .then((payload) => { -// this.Payload = JSON.parse(payload.Data); -// console.log(this.Payload, hash, this.hash) -// let res = this.Payload; -// Object.assign(res, { hash: hash }); -// if(this.Payload.key === null) -// Object.assign(res, { key: hash }); -// console.log(this.Payload) -// console.log(this) -// resolve(res); -// }) -// .catch(reject); -// } else { -// resolve(this.Payload); -// } -// })); -// } module.exports = OrbitDB; diff --git a/src/list/List.js b/src/list/List.js deleted file mode 100644 index 78fe7ee..0000000 --- a/src/list/List.js +++ /dev/null @@ -1,114 +0,0 @@ -'use strict'; - -const _ = require('lodash'); -const Lazy = require('lazy.js'); -const Node = require('./Node'); - -class List { - constructor(id, seq, ver, items) { - this.id = id; - // this.seq = seq || 0; - // this.ver = ver || 0; - this._items = items || []; - this._currentBatch = []; - } - - /* Methods */ - add(data) { - const heads = List.findHeads(this.items); - const node = new Node(this.id, -1, -1, data, heads); - this._currentBatch.push(node); - // this.ver ++; - } - - join(other) { - // this.seq = (other.seq && other.seq > this.seq ? other.seq : this.seq) + 1; - // this.ver = 0; - // TODO: figure out how to do real equality check with Lazy.js - // const current = Lazy(this._currentBatch).difference(this._items); - // const others = Lazy(other.items).difference(current.toA); - // const final = current.union(others).uniq((f) => f.compactId); - const current = _.differenceWith(this._currentBatch, this._items, Node.equals); - const others = _.differenceWith(other.items, this._items, Node.equals); - const final = _.unionWith(current, others, Node.equals); - - this._items = Lazy(this._items).concat(final).toArray(); - this._currentBatch = []; - } - - clear() { - this._items = []; - this._currentBatch = []; - // this.seq = 0; - // this.ver = 0; - } - - /* Private methods */ - _commit() { - const current = Lazy(this._currentBatch).difference(this._items).toArray(); - this._items = this._items.concat(current); - this._currentBatch = []; - // this.ver = 0; - // this.seq ++; - } - - /* Properties */ - get items() { - return this._items.concat(this._currentBatch); - } - - get compactId() { - // return "" + this.id + "." + this.seq + "." + this.ver; - return "" + this.id; - } - - get asJson() { - return { - id: this.id, - // seq: this.seq, - // ver: this.ver, - items: this._currentBatch.map((f) => f.asJson) - }; - } - - /* Static methods */ - static fromJson(json) { - let list = new List(json.id); - // list.seq = json.seq; - // list.ver = json.ver; - list._items = Lazy(json.items) - // .map((f) => new Node(f.id, f.seq, f.ver, f.data, f.next)) - .map((f) => new Node(f.id, -1, -1, f.data, f.next)) - .unique() - .toArray(); - return list; - } - - static findHeads(list) { - return Lazy(list) - .reverse() - .indexBy((f) => f.id) - .pairs() - .map((f) => f[1]) - .filter((f) => !List.isReferencedInChain(list, f)) - .toArray(); - } - - static isReferencedInChain(all, item) { - return Lazy(all).reverse().find((e) => e.hasChild(item)) !== undefined; - } - - printTree() { - const printCurrent = (f, padding) => { - padding += " |"; - let s = padding + "-" + f.compactId + " '" + f.data + "'\n"; - if(f.next.length > 0) { - s += f.next.map((e) => printCurrent(e, padding)).join(""); - } - return s; - } - console.log(" LIST\n" + this.items.reverse().map((e) => printCurrent(e, "")).join("")); - } -} - -module.exports = List; diff --git a/src/list/Node.js b/src/list/Node.js deleted file mode 100644 index 99a9d72..0000000 --- a/src/list/Node.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -class Node { - constructor(id, seq, ver, data, next) { - this.id = id; - this.seq = seq; - this.ver = ver; - this.data = data || null; - // this.next = next ? next.map((f) => f.compactId ? f.compactId : f) : []; - this.next = next ? next.map((f) => f.id ? f.id : f) : []; - } - - hasChild(a) { - // const id = a.compactId; - const id = a.id; - for(let i = 0; i < this.next.length; i++) { - if(this.next[i] === id) - return true; - } - return false; - } - - get compactId() { - return "" + this.id; - // return "" + this.id + "." + this.seq + "." + this.ver; - } - - get heads() { - // return Object.keys(this.next).map((e) => this.next[e]); - return this.next; - } - - get asJson() { - // return { id: this.id, seq: this.seq, ver: this.ver, data: this.data, next: this.next }; - return { id: this.id, data: this.data, next: this.next }; - } - - static equals(a, b) { - // return a.id === b.id && a.seq === b.seq && a.ver === b.ver; - return a.id === b.id; - } -} - -module.exports = Node; diff --git a/src/list/OrbitList.js b/src/list/OrbitList.js deleted file mode 100644 index cd705cf..0000000 --- a/src/list/OrbitList.js +++ /dev/null @@ -1,178 +0,0 @@ -'use strict'; - -const _ = require('lodash'); -const Lazy = require('lazy.js'); -const async = require('asyncawait/async'); -const await = require('asyncawait/await'); -const OrbitNode = require('./OrbitNode'); - -const MaxBatchSize = 10; // How many items per sequence. Saves a snapshot to ipfs in batches of this many items. -const MaxHistory = 256; // How many items to fetch in the chain per join - -class OrbitList { - constructor(ipfs, id, seq, ver, items) { - this.id = id; - this._ipfs = ipfs; - this._items = items || []; - this._currentBatch = []; - } - - add(data) { - if(this._currentBatch.length >= MaxBatchSize) - this._commit(); - - const heads = OrbitList.findHeads(this.items); - const node = new OrbitNode(this._ipfs, this.id, data, heads); - this._currentBatch.push(node); - } - - join(other) { - const current = _.differenceWith(this._currentBatch, this._items, OrbitNode.equals); - const others = _.differenceWith(other.items, this._items, OrbitNode.equals); - const final = _.unionWith(current, others, OrbitNode.equals); - this._items = Lazy(this._items).concat(final).toArray(); - this._currentBatch = []; - const history = _.flatten(await(this._fetchHistory(other.items))); - history.forEach((f) => this._insert(f)) // Insert to the list - } - - clear() { - this._items = []; - this._currentBatch = []; - } - - /* Private methods */ - _fetchHistory(items) { - var _fetchAsync = async(() => { - return new Promise(async((resolve, reject) => { - let allHashes = this._items.map((a) => a.hash); - const handle = Lazy(items) - .reverse() // Start from the latest item - .map((f) => f.next).flatten() // Go through all heads - .filter((f) => !(f instanceof OrbitNode === true)) // OrbitNode vs. {}, filter out instances (we already have them in mem) - .async() // Do the next map asynchronously - .map(async((f) => _.flatten(await(this._fetchRecursive(f, allHashes, MaxHistory, 0))))) // IO - fetch items recursively - .take(MaxHistory) // How many items from the history we should fetch - .toArray(); - // console.log("--> Fetched", res.length, "items from the history"); - - handle.onComplete(resolve); - })); - }) - return await(_fetchAsync()); - } - - // Fetch items in the linked list recursively - _fetchRecursive(hash, all, amount, depth) { - var _fetchAsync = async(() => { - return new Promise(async((resolve, reject) => { - const isReferenced = (list, item) => Lazy(list).reverse().find((f) => f === item) !== undefined; - let result = []; - - if(depth >= amount) { - resolve(result) - return; - } - - if(isReferenced(all, hash)) { - resolve(result); - return; - } - - const item = await(OrbitNode.fromIpfsHash(this._ipfs, hash)); // IO - get from IPFS - result.push(item); - all.push(hash); - depth ++; - - const handle = Lazy(item.next) - .async() - .map(async((f) => _.flatten(await(this._fetchRecursive(f, all, amount, depth))))) - .toArray() - - handle.onComplete((res) => { - result = result.concat(res); - resolve(result); - }); - })); - }) - return await(_fetchAsync()); - } - - // Insert to the list right after the latest parent - _insert(item) { - let indices = Lazy(item.next).map((next) => Lazy(this._items).map((f) => f.hash).indexOf(next)) // Find the item's parent's indices - const index = indices.length > 0 ? Math.max(indices.max() + 1, 0) : 0; // find the largest index (latest parent) - this._items.splice(index, 0, item); - return item; - } - - _commit() { - const current = Lazy(this._currentBatch).difference(this._items).toArray(); - this._items = this._items.concat(current); - this._currentBatch = []; - } - - /* Properties */ - get items() { - return this._items.concat(this._currentBatch); - } - - get ipfsHash() { - const toIpfs = async(() => { - return new Promise(async((resolve, reject) => { - var data = await(this.asJson) - const list = await(this._ipfs.object.put(new Buffer(JSON.stringify({ Data: JSON.stringify(data) })))); - resolve(list.Hash); - })); - }); - this.hash = await(toIpfs()); - return this.hash; - } - - get asJson() { - return { - id: this.id, - items: this._currentBatch.map((f) => await(f.ipfsHash)) - } - } - - static findHeads(list) { - return Lazy(list) - .reverse() - .indexBy((f) => f.id) - .pairs() - .map((f) => f[1]) - .filter((f) => !OrbitList.isReferencedInChain(list, f)) - .toArray(); - } - - static isReferencedInChain(all, item) { - return Lazy(all).reverse().find((e) => e.hasChild(item)) !== undefined; - } - - static fromIpfsHash(ipfs, hash) { - const fromIpfs = async(() => { - return new Promise(async((resolve, reject) => { - const l = await(ipfs.object.get(hash)); - const list = OrbitList.fromJson(ipfs, JSON.parse(l.Data)); - resolve(list); - })); - }); - return await(fromIpfs()); - } - - static fromJson(ipfs, json) { - const items = json.items.map((f) => await(OrbitNode.fromIpfsHash(ipfs, f))); - return new OrbitList(ipfs, json.id, -1, -1, items); - } - - static get batchSize() { - return MaxBatchSize; - } - - static get maxHistory() { - return MaxHistory; - } -} - -module.exports = OrbitList; diff --git a/src/list/OrbitNode.js b/src/list/OrbitNode.js deleted file mode 100644 index 1e11795..0000000 --- a/src/list/OrbitNode.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict'; - -const async = require('asyncawait/async'); -const await = require('asyncawait/await'); - -class OrbitNode { - constructor(ipfs, id, data, next, hash) { - this._ipfs = ipfs; - this.id = id; - this.data = data || null; - this.next = next || []; - this.hash = hash ? hash : this.ipfsHash; - } - - fetchPayload() { - return new Promise(async((resolve, reject) => { - if(!this.Payload) { - this._ipfs.object.get(this.data) - .then((payload) => { - this.Payload = JSON.parse(payload.Data); - let res = this.Payload; - Object.assign(res, { hash: this.data }); - if(this.Payload.key === null) - Object.assign(res, { key: this.data }); - resolve(res); - }) - .catch(reject); - } else { - resolve(this.Payload); - } - })); - } - - hasChild(a) { - const id = a; - for(let i = 0; i < this.next.length; i++) { - if(this.next[i] === id) - return true; - } - return false; - } - - get ipfsHash() { - if(!this.hash) { - const r = await(this._ipfs.object.put(new Buffer(JSON.stringify({ Data: JSON.stringify(this.asJson) })))); - this.hash = r.Hash; - } - return this.hash; - } - - get asJson() { - let res = { id: this.id, data: this.data } - let items = this.next.map((f) => f.hash); - Object.assign(res, { next: items }); - return res; - } - - static fromIpfsHash(ipfs, hash) { - return new Promise(async((resolve, reject) => { - ipfs.object.get(hash) - .then((obj) => { - const f = JSON.parse(obj.Data) - const node = new OrbitNode(ipfs, f.id, f.data, f.next, hash) - resolve(node); - }).catch(reject); - })); - } - - static equals(a, b) { - return a.hash === b.hash; - } -} - -module.exports = OrbitNode; diff --git a/test/list-node-tests.js b/test/list-node-tests.js deleted file mode 100644 index 1972f3c..0000000 --- a/test/list-node-tests.js +++ /dev/null @@ -1,67 +0,0 @@ -// 'use strict'; - -// const assert = require('assert'); -// const List = require('../src/list/List'); -// const Node = require('../src/list/Node'); - -// describe('Node', () => { -// describe('Constructor', () => { -// it('initializes member variables', (done) => { -// const node = new Node('A', 0, 0, 'hello', []); -// assert.equal(node.id, 'A'); -// assert.equal(node.seq, 0); -// assert.equal(node.ver, 0); -// assert.equal(node.data, 'hello'); -// assert.equal(node.next instanceof Array, true); -// done(); -// }); - -// it('initializes member variables without specified data and next', (done) => { -// const node = new Node('A', 0, 0); -// assert.equal(node.id, 'A'); -// assert.equal(node.seq, 0); -// assert.equal(node.ver, 0); -// assert.equal(node.data, null); -// assert.equal(node.next instanceof Array, true); -// done(); -// }); -// }); - -// describe('compactId', () => { -// it('presents the node as a string with id, sequence and version', (done) => { -// const node1 = new Node('A', 0, 0); -// const node2 = new Node('B', 123, 456); -// assert.equal(node1.compactId, 'A.0.0'); -// assert.equal(node2.compactId, 'B.123.456'); -// done(); -// }); -// }); - -// describe('equals', () => { -// it('check if nodes are equal', (done) => { -// const node1 = new Node('A', 0, 0); -// const node2 = new Node('A', 0, 0); -// const node3 = new Node('A', 1, 1); -// const node4 = new Node('B', 123, 456); -// assert.equal(Node.equals(node1, node1), true); -// assert.equal(Node.equals(node1, node2), true); -// assert.equal(Node.equals(node1, node3), false); -// assert.equal(Node.equals(node1, node4), false); -// assert.equal(Node.equals(node3, node4), false); -// done(); -// }); -// }); - -// describe('hasChild', () => { -// it('finds the child reference', (done) => { -// const a = new Node('A', 0, 0); -// const b = new Node('B', 0, 0, "hello", [a]); -// const c = new Node('C', 0, 0, "hello", [a, b]); -// assert.equal(b.hasChild(a), true) -// assert.equal(c.hasChild(a), true) -// assert.equal(c.hasChild(b), true) -// done(); -// }); -// }); - -// }); diff --git a/test/list-tests.js b/test/list-tests.js deleted file mode 100644 index 9708f5f..0000000 --- a/test/list-tests.js +++ /dev/null @@ -1,513 +0,0 @@ -// 'use strict'; - -// const _ = require('lodash'); -// var assert = require('assert'); -// var List = require('../src/list/List'); -// var Node = require('../src/list/Node'); - -// describe('List', () => { -// describe('Constructor', () => { -// it('initializes member variables', (done) => { -// const list = new List('A'); -// assert.equal(list.id, 'A'); -// assert.equal(list.seq, 0); -// assert.equal(list.ver, 0); -// assert.equal(list._items instanceof Array, true); -// assert.equal(list._currentBatch instanceof Array, true); -// assert.equal(list._items.length, 0); -// assert.equal(list._currentBatch.length, 0); -// done(); -// }); -// }); - -// describe('fromJson', () => { -// it('creates a list from parsed json', (done) => { -// const list = new List('A'); -// list.add("hello1") -// list.add("hello2") -// list.add("hello3") -// const str = JSON.stringify(list.asJson, null, 2) -// const res = List.fromJson(JSON.parse(str)); -// assert.equal(res.id, 'A'); -// assert.equal(res.seq, 0); -// assert.equal(res.ver, 3); -// assert.equal(res.items.length, 3); -// assert.equal(res.items[0].compactId, 'A.0.0'); -// assert.equal(res.items[1].compactId, 'A.0.1'); -// assert.equal(res.items[2].compactId, 'A.0.2'); -// done(); -// }); -// }); - -// describe('asJson', () => { -// it('presents the list as json', (done) => { -// const list = new List('A'); -// list.add("hello1") -// list.add("hello2") -// list.add("hello3") -// const expected = { -// id: 'A', -// seq: 0, -// ver: 3, -// items: [ -// { id: 'A', seq: 0, ver: 0, data: 'hello1', next: [] }, -// { id: 'A', seq: 0, ver: 1, data: 'hello2', next: ['A.0.0'] }, -// { id: 'A', seq: 0, ver: 2, data: 'hello3', next: ['A.0.1'] } -// ] -// }; -// assert.equal(_.isEqual(list.asJson, expected), true); -// done(); -// }); -// }); - -// describe('items', () => { -// it('returns items', (done) => { -// const list = new List('A'); -// let items = list.items; -// assert.equal(list.items instanceof Array, true); -// assert.equal(list.items.length, 0); -// list.add("hello1") -// list.add("hello2") -// assert.equal(list.items instanceof Array, true); -// assert.equal(list.items.length, 2); -// assert.equal(list.items[0].data, 'hello1'); -// assert.equal(list.items[1].data, 'hello2'); -// done(); -// }); -// }); - -// describe('add', () => { -// it('adds an item to an empty list', (done) => { -// const list = new List('A'); -// list.add("hello1") -// const item = list.items[0]; -// assert.equal(list.id, 'A'); -// assert.equal(list.seq, 0); -// assert.equal(list.ver, 1); -// assert.equal(list.items.length, 1); -// assert.equal(list._currentBatch.length, 1); -// assert.equal(list._items.length, 0); -// assert.equal(item, list._currentBatch[0]); -// assert.equal(item.id, 'A'); -// assert.equal(item.seq, 0); -// assert.equal(item.ver, 0); -// assert.equal(item.data, 'hello1'); -// done(); -// }); - -// it('adds 100 items to a list', (done) => { -// const list = new List('A'); - -// for(let i = 1; i < 101; i ++) { -// list.add("hello" + i); -// } - -// assert.equal(list.id, 'A'); -// assert.equal(list.seq, 0); -// assert.equal(list.ver, 100); -// assert.equal(list.items.length, 100); -// assert.equal(list._currentBatch.length, 100); -// assert.equal(list._items.length, 0); - -// const item = list.items[list.items.length - 1]; -// assert.equal(item, list._currentBatch[list._currentBatch.length - 1]); -// assert.equal(item.id, 'A'); -// assert.equal(item.seq, 0); -// assert.equal(item.ver, 99); -// assert.equal(item.data, 'hello100'); -// assert.equal(item.next, 'A.0.98'); - -// done(); -// }); -// }); - -// describe('join', () => { -// it('increases the sequence and resets the version if other list has the same or higher sequence', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); - -// list2.seq = 7; -// list1.add("helloA1") - -// assert.equal(list1.id, 'A'); -// assert.equal(list1.seq, 0); -// assert.equal(list1.ver, 1); - -// list2.add("helloB1") -// list1.join(list2); - -// assert.equal(list1.id, 'A'); -// assert.equal(list1.seq, 8); -// assert.equal(list1.ver, 0); -// done(); -// }); - -// it('increases the sequence by one if other list has lower sequence', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// list1.seq = 4; -// list2.seq = 1; -// list2.add("helloB1") -// list1.join(list2); -// assert.equal(list1.id, 'A'); -// assert.equal(list1.seq, 5); -// assert.equal(list1.ver, 0); -// done(); -// }); - -// it('finds the next head when adding a new element', (done) => { -// const list1 = new List('A'); -// list1.add("helloA1") -// list1.add("helloA2") -// list1.add("helloA3") - -// assert.equal(list1._currentBatch.length, 3); -// assert.equal(list1._currentBatch[2].next.length, 1); -// assert.equal(list1._currentBatch[2].next[0], 'A.0.1'); -// done(); -// }); - -// it('finds the next heads (two) after a join', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// list1.add("helloA1") -// list2.add("helloB1") -// list2.add("helloB2") -// list1.join(list2); -// list1.add("helloA2") - -// assert.equal(list1._currentBatch.length, 1); -// assert.equal(list1._currentBatch[0].next.length, 2); -// assert.equal(list1._currentBatch[0].next[1], 'A.0.0'); -// assert.equal(list1._currentBatch[0].next[0], 'B.0.1'); -// done(); -// }); - -// it('finds the next head (one) after a join', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// list1.add("helloA1") -// list2.add("helloB1") -// list2.add("helloB2") -// list1.join(list2); - -// list1.add("helloA2") -// list1.add("helloA3") - -// assert.equal(list1._currentBatch.length, 2); -// assert.equal(list1._currentBatch[1].next.length, 1); -// assert.equal(list1._currentBatch[1].next[0], 'A.1.0'); -// done(); -// }); - -// it('finds the next heads after two joins', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// list1.add("helloA1") -// list1.add("helloA2") -// list2.add("helloB1") -// list2.add("helloB2") -// list1.join(list2); - -// list1.add("helloA3") - -// list1.join(list2); - -// list1.add("helloA4") - -// const lastItem = list1.items[list1.items.length - 1]; - -// assert.equal(list1.items.length, 6); -// assert.equal(lastItem.next.length, 1); -// assert.equal(lastItem.next[0], 'A.1.0'); -// done(); -// }); - -// it('finds the next heads after multiple joins', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// const list3 = new List('C'); -// const list4 = new List('D'); -// list1.add("helloA1") -// list1.add("helloA2") -// list2.add("helloB1") -// list2.add("helloB2") -// list1.join(list2); - -// list3.add("helloC1") -// list4.add("helloD1") -// list1.join(list3); - -// list1.add("helloA3") -// list2.join(list1); -// list1.join(list2); -// list2.join(list4); - -// list4.add("helloD2") -// list4.add("helloD3") -// list1.add("helloA4") -// list1.join(list4); - -// list1.add("helloA5") - -// const lastItem = list1.items[list1.items.length - 1]; - -// assert.equal(lastItem.next[1], 'A.4.0'); -// assert.equal(lastItem.next[0], 'D.0.2'); -// assert.equal(list1.items.length, 11); -// assert.equal(lastItem.next.length, 2); -// done(); -// }); - -// it('joins list of one item with list of two items', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// list1.add("helloA1") -// list2.add("helloB1") -// list2.add("helloB2") -// list1.join(list2); - -// const firstItem = list1.items[0]; - -// assert.equal(list1.id, 'A'); -// assert.equal(list1.seq, 1); -// assert.equal(list1.ver, 0); -// assert.equal(list1._currentBatch.length, 0); -// assert.equal(list1._items.length, 3); -// assert.equal(firstItem.id, 'A'); -// assert.equal(firstItem.seq, 0); -// assert.equal(firstItem.ver, 0); -// assert.equal(firstItem.data, 'helloA1'); -// done(); -// }); - -// it('joins lists two ways', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// list1.add("helloA1") -// list1.add("helloA2") -// list2.add("helloB1") -// list2.add("helloB2") -// list1.join(list2); -// list2.join(list1); - -// const lastItem1 = list1.items[list1.items.length - 1]; - -// assert.equal(list1.id, 'A'); -// assert.equal(list1.seq, 1); -// assert.equal(list1.ver, 0); -// assert.equal(list1._currentBatch.length, 0); -// assert.equal(list1._items.length, 4); -// assert.equal(lastItem1.id, 'B'); -// assert.equal(lastItem1.seq, 0); -// assert.equal(lastItem1.ver, 1); -// assert.equal(lastItem1.data, 'helloB2'); - -// const lastItem2 = list2.items[list2.items.length - 1]; - -// assert.equal(list2.id, 'B'); -// assert.equal(list2.seq, 2); -// assert.equal(list2.ver, 0); -// assert.equal(list2._currentBatch.length, 0); -// assert.equal(list2._items.length, 4); -// assert.equal(lastItem2.id, 'A'); -// assert.equal(lastItem2.seq, 0); -// assert.equal(lastItem2.ver, 1); -// assert.equal(lastItem2.data, 'helloA2'); -// done(); -// }); - -// it('joins lists twice', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); - -// list1.add("helloA1") -// list2.add("helloB1") -// list2.join(list1); - -// list1.add("helloA2") -// list2.add("helloB2") -// list2.join(list1); - -// const secondItem = list2.items[list2.items.length - 2]; -// const lastItem = list2.items[list2.items.length - 1]; - -// assert.equal(list2.id, 'B'); -// assert.equal(list2.seq, 2); -// assert.equal(list2.ver, 0); -// assert.equal(list2._currentBatch.length, 0); -// assert.equal(list2._items.length, 4); -// assert.equal(secondItem.id, 'B'); -// assert.equal(secondItem.seq, 1); -// assert.equal(secondItem.ver, 0); -// assert.equal(secondItem.data, 'helloB2'); -// assert.equal(lastItem.id, 'A'); -// assert.equal(lastItem.seq, 0); -// assert.equal(lastItem.ver, 1); -// assert.equal(lastItem.data, 'helloA2'); -// done(); -// }); - -// it('joins 4 lists to one', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// const list3 = new List('C'); -// const list4 = new List('D'); - -// list1.add("helloA1") -// list2.add("helloB1") -// list1.add("helloA2") -// list2.add("helloB2") -// list3.add("helloC1") -// list4.add("helloD1") -// list3.add("helloC2") -// list4.add("helloD2") -// list1.join(list2); -// list1.join(list3); -// list1.join(list4); - -// const secondItem = list1.items[list1.items.length - 2]; -// const lastItem = list1.items[list1.items.length - 1]; - -// assert.equal(list1.id, 'A'); -// assert.equal(list1.seq, 3); -// assert.equal(list1.ver, 0); -// assert.equal(list1._currentBatch.length, 0); -// assert.equal(list1._items.length, 8); -// assert.equal(secondItem.id, 'D'); -// assert.equal(secondItem.seq, 0); -// assert.equal(secondItem.ver, 0); -// assert.equal(secondItem.data, 'helloD1'); -// assert.equal(lastItem.id, 'D'); -// assert.equal(lastItem.seq, 0); -// assert.equal(lastItem.ver, 1); -// assert.equal(lastItem.data, 'helloD2'); -// done(); -// }); - -// it('joins lists from 4 lists', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// const list3 = new List('C'); -// const list4 = new List('D'); - -// list1.add("helloA1") -// list1.join(list2); -// list2.add("helloB1") -// list2.join(list1); - -// list1.add("helloA2") -// list2.add("helloB2") -// list1.join(list3); -// list3.join(list1); - -// list3.add("helloC1") -// list4.add("helloD1") - -// list3.add("helloC2") -// list4.add("helloD2") - -// list1.join(list3); -// list1.join(list2); -// list4.join(list2); -// list4.join(list1); -// list4.join(list3); - -// list4.add("helloD3") -// list4.add("helloD4") - -// const secondItem = list4.items[1]; -// const lastItem1 = list4._items[list4._items.length - 1]; -// const lastItem2 = list4.items[list4.items.length - 1]; - -// assert.equal(list4.id, 'D'); -// assert.equal(list4.seq, 7); -// assert.equal(list4.ver, 2); -// assert.equal(list4._currentBatch.length, 2); -// assert.equal(list4._items.length, 8); -// assert.equal(secondItem.id, 'D'); -// assert.equal(secondItem.seq, 0); -// assert.equal(secondItem.ver, 1); -// assert.equal(secondItem.data, 'helloD2'); -// assert.equal(lastItem1.id, 'C'); -// assert.equal(lastItem1.seq, 3); -// assert.equal(lastItem1.ver, 1); -// assert.equal(lastItem1.data, 'helloC2'); -// assert.equal(lastItem2.id, 'D'); -// assert.equal(lastItem2.seq, 7); -// assert.equal(lastItem2.ver, 1); -// assert.equal(lastItem2.data, 'helloD4'); -// done(); -// }); - -// it('data is consistent after joining lists', (done) => { -// const list1 = new List('A'); -// const list2 = new List('B'); -// const list3 = new List('C'); - -// list1.add("helloA1") -// list2.add("helloB1") -// list3.add("helloC1") - -// list1.join(list2); -// list2.join(list1); - -// list1.add("helloA2") -// list1.add("helloA3") -// list2.add("helloB2") -// list2.add("helloB3") - -// list1.join(list2); -// list2.join(list1); - -// list1.add("helloA4") -// list1.add("helloA5") - -// list2.add("helloB4") -// list2.add("helloB5") -// list3.add("helloC2") -// list3.add("helloC3") - -// list1.add("helloA6") -// list2.join(list1); -// list1.join(list2); - -// list1.add("helloA7") -// list1.add("helloA8") - -// list2.join(list1); -// list1.join(list2); - -// list2.add("helloB6") -// list2.add("helloB7") -// list2.add("helloB8") - -// list1.join(list2); -// list2.join(list1); -// list1.join(list3); -// list2.join(list3); -// list3.join(list2); -// list3.join(list1); - -// assert.equal(list1._items.length, 19); -// assert.equal(list1.items.map((e) => e.compactId).join(", "), "A.0.0, B.0.0, A.1.0, A.1.1, B.2.0, B.2.1, A.3.0, A.3.1, A.3.2, B.4.0, B.4.1, A.6.0, A.6.1, B.7.0, B.7.1, B.7.2, C.0.0, C.0.1, C.0.2") -// assert.equal(list2.items.map((e) => e.compactId).join(", "), "B.0.0, A.0.0, B.2.0, B.2.1, A.1.0, A.1.1, B.4.0, B.4.1, A.3.0, A.3.1, A.3.2, A.6.0, A.6.1, B.7.0, B.7.1, B.7.2, C.0.0, C.0.1, C.0.2") -// assert.equal(list3.items.map((e) => e.compactId).join(", "), "C.0.0, C.0.1, C.0.2, B.0.0, A.0.0, B.2.0, B.2.1, A.1.0, A.1.1, B.4.0, B.4.1, A.3.0, A.3.1, A.3.2, A.6.0, A.6.1, B.7.0, B.7.1, B.7.2") -// done(); -// }); - -// }); - -// describe('_findHeads', () => { -// it('TODO', (done) => { -// done(); -// }); -// }); - -// describe('_isReferencedInChain', () => { -// it('TODO', (done) => { -// done(); -// }); -// }); - -// }); diff --git a/test/orbit-list-tests.js b/test/orbit-list-tests.js deleted file mode 100644 index 2c9b933..0000000 --- a/test/orbit-list-tests.js +++ /dev/null @@ -1,794 +0,0 @@ -'use strict'; - -const _ = require('lodash'); -const async = require('asyncawait/async'); -const await = require('asyncawait/await'); -const assert = require('assert'); -const ipfsDaemon = require('orbit-common/lib/ipfs-daemon'); -const ipfsAPI = require('orbit-common/lib/ipfs-api-promised'); -const List = require('../src/list/OrbitList'); -const List2 = require('../src/list/List'); -const Node = require('../src/list/OrbitNode'); - -const startIpfs = async (() => { - return new Promise(async((resolve, reject) => { - const ipfsd = await(ipfsDaemon()); - resolve(ipfsd.ipfs); - })); -}); - -let ipfs; - -describe('OrbitList', async(function() { - this.timeout(5000); - - before(async((done) => { - try { - ipfs = await(startIpfs()); - } catch(e) { - assert.equals(e, null); - } - done(); - })); - - describe('Constructor', async(() => { - it('initializes member variables', async((done) => { - const list = new List(ipfs, 'A'); - assert.equal(list.id, 'A'); - // assert.equal(list.seq, 0); - // assert.equal(list.ver, 0); - assert.equal(list._items instanceof Array, true); - assert.equal(list._currentBatch instanceof Array, true); - assert.equal(list._items.length, 0); - assert.equal(list._currentBatch.length, 0); - assert.equal(list._ipfs, ipfs); - assert.equal(list.hash, null); - done(); - })); - })); - - describe('ipfsHash', async(() => { - it('returns the list as ipfs hash', async((done) => { - const list = new List(ipfs, 'A'); - const hash = list.ipfsHash; - assert.equal(hash.startsWith('Qm'), true); - done(); - })); - - it('saves the list to ipfs', async((done) => { - const list = new List(ipfs, 'A'); - const hash = list.ipfsHash; - const l = await(ipfsAPI.getObject(ipfs, hash)); - assert.equal(l.toString(), ({ Links: [], Data: '{"id":"A","seq":0,"ver":0,"items":[]}' }).toString()); - done(); - })); - })); - - describe('fromIpfsHash', () => { - it('creates a list from ipfs hash', async((done) => { - const list = new List(ipfs, 'A'); - list.add("hello1") - list.add("hello2") - list.add("hello3") - const hash = list.ipfsHash; - const res = List.fromIpfsHash(ipfs, hash); - - assert.equal(res.id, 'A'); - // assert.equal(res.seq, 0); - // assert.equal(res.ver, 3); - assert.equal(res.items.length, 3); - // assert.equal(res.items[0].compactId, 'A.0.0'); - assert.equal(res.items[0].hash, 'QmQgLATYR4Af3oCVaQ8LHumvkwtjHfZ3Tumz8RfKMxHZfo'); - // assert.equal(res.items[1].compactId, 'A.0.1'); - assert.equal(res.items[1].hash, 'QmTLP2MccfhZGjXHZgLL1euh2d2PkEhLf7G1pGR2Hdg4h6'); - // assert.equal(res.items[2].compactId, 'A.0.2'); - assert.equal(res.items[2].hash, 'QmUX8qTWAqumSxzviV4YvWyWT727pqgZX6XdViWZdoL8fC'); - - done(); - })); - }); - - describe('serialize', async(() => { - - let list; - const expected = { - id: "A", - items: [ - "QmQgLATYR4Af3oCVaQ8LHumvkwtjHfZ3Tumz8RfKMxHZfo", - "QmTLP2MccfhZGjXHZgLL1euh2d2PkEhLf7G1pGR2Hdg4h6", - "QmUX8qTWAqumSxzviV4YvWyWT727pqgZX6XdViWZdoL8fC" - ] - }; - - before(async((done) => { - list = new List(ipfs, 'A'); - list.add("hello1") - list.add("hello2") - list.add("hello3") - done(); - })); - - describe('asJson', async(() => { - it('presents the list as json', async((done) => { - assert.equal(JSON.stringify(list.asJson), JSON.stringify(expected)); - done(); - })); - })); - - describe('fromJson', () => { - it('creates a list from parsed json', async((done) => { - const str = JSON.stringify(list.asJson, null, 2) - const res = List.fromJson(ipfs, JSON.parse(str)); - assert.equal(res.id, 'A'); - // assert.equal(res.seq, 0); - // assert.equal(res.ver, 3); - assert.equal(res.items.length, 3); - assert.equal(res.items[0].hash, 'QmQgLATYR4Af3oCVaQ8LHumvkwtjHfZ3Tumz8RfKMxHZfo'); - assert.equal(res.items[1].hash, 'QmTLP2MccfhZGjXHZgLL1euh2d2PkEhLf7G1pGR2Hdg4h6'); - assert.equal(res.items[2].hash, 'QmUX8qTWAqumSxzviV4YvWyWT727pqgZX6XdViWZdoL8fC'); - done(); - })); - }); - })); - - describe('items', () => { - it('returns items', async((done) => { - const list = new List(ipfs, 'A'); - let items = list.items; - assert.equal(list.items instanceof Array, true); - assert.equal(list.items.length, 0); - list.add("hello1") - list.add("hello2") - assert.equal(list.items instanceof Array, true); - assert.equal(list.items.length, 2); - assert.equal(list.items[0].data, 'hello1'); - assert.equal(list.items[1].data, 'hello2'); - done(); - })); - }); - - describe('add', () => { - it('adds an item to an empty list', async((done) => { - const list = new List(ipfs, 'A'); - list.add("hello1") - const item = list.items[0]; - assert.equal(list.id, 'A'); - // assert.equal(list.seq, 0); - // assert.equal(list.ver, 1); - assert.equal(list.items.length, 1); - assert.equal(list._currentBatch.length, 1); - assert.equal(list._items.length, 0); - assert.equal(item, list._currentBatch[0]); - assert.equal(item.id, 'A'); - // assert.equal(item.seq, 0); - // assert.equal(item.ver, 0); - assert.equal(item.data, 'hello1'); - done(); - })); - - it('adds 100 items to a list', async((done) => { - const list = new List(ipfs, 'A'); - const amount = 100; - - for(let i = 1; i <= amount; i ++) { - list.add("hello" + i); - } - - assert.equal(list.id, 'A'); - assert.equal(list.items.length, amount); - - const item = list.items[list.items.length - 1]; - assert.equal(item.id, 'A'); - assert.equal(item.data, 'hello' + amount); - assert.notEqual(item.next.length, 0); - - done(); - })); - - it('commits a list after batch size was reached', async((done) => { - const list = new List(ipfs, 'A'); - - for(let i = 1; i <= List.batchSize; i ++) { - list.add("hello" + i); - } - - assert.equal(list.id, 'A'); - // assert.equal(list.seq, 0); - // assert.equal(list.ver, List.batchSize); - assert.equal(list.items.length, List.batchSize); - assert.equal(list._currentBatch.length, List.batchSize); - assert.equal(list._items.length, 0); - - const item = list.items[list.items.length - 1]; - assert.equal(item.id, 'A'); - // assert.equal(item.seq, 0); - assert.equal(list.items.length, List.batchSize); - assert.equal(item.data, 'hello' + List.batchSize); - assert.notEqual(item.next.length, 0); - - done(); - })); - }); - - describe('join', () => { - it('joins unique items', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - - list1.add("helloA3") - - list1.join(list2); - list1.join(list2); - - list1.add("helloA4") - list1.add("helloA5") - - const lastItem = list1.items[list1.items.length - 1]; - - assert.equal(list1.items.length, 7); - assert.equal(lastItem.next.length, 1); - assert.equal(lastItem.next[0].hash, 'QmPT7qgkysupMuMf2k8yESBL8A55Cva9Y8pqTuA1AMWB4m'); - done(); - })); - - it('finds the next head when adding a new element', async((done) => { - const list1 = new List(ipfs, 'A'); - list1.add("helloA1") - list1.add("helloA2") - list1.add("helloA3") - - assert.equal(list1._currentBatch.length, 3); - assert.equal(list1._currentBatch[0].next.length, 0); - assert.equal(list1._currentBatch[1].next.length, 1); - assert.equal(list1._currentBatch[1].next[0].hash, 'QmQQhCyFHWAwNm7k5CbDF5iKuHfT2VJU5qUkncQDNAfTbL'); - assert.equal(list1._currentBatch[2].next.length, 1); - assert.equal(list1._currentBatch[2].next[0].hash, 'QmbKmxJv6mhGvvUQwU3A5BBWvpBMVvGkpFr5AMrrqib6EH'); - done(); - })); - - it('finds the next heads (two) after a join', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - list1.add("helloA2") - - assert.equal(list1._currentBatch.length, 1); - assert.equal(list1._currentBatch[0].next.length, 2); - // assert.equal(list1._currentBatch[0].next[1].compactId, 'A.0.0'); - assert.equal(list1._currentBatch[0].next[1].hash, 'QmQQhCyFHWAwNm7k5CbDF5iKuHfT2VJU5qUkncQDNAfTbL'); - // assert.equal(list1._currentBatch[0].next[0].compactId, 'B.0.1'); - assert.equal(list1._currentBatch[0].next[0].hash, 'QmUnaa1dT2FEYmK1nDD5fJ53Pd2iEDtGL3oLM5M7VLBqHJ'); - done(); - })); - - it('finds the next head (one) after a join', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - - list1.add("helloA2") - list1.add("helloA3") - - assert.equal(list1._currentBatch.length, 2); - assert.equal(list1._currentBatch[1].next.length, 1); - // assert.equal(list1._currentBatch[1].next[0].compactId, 'A.1.0'); - assert.equal(list1._currentBatch[1].next[0].hash, 'QmaGPFKz6qJLuLhUFN2J48FVZttVF2y2gmgU3666H21BWQ'); - assert.equal(list1._currentBatch[0].next.length, 2); - // assert.equal(list1._currentBatch[0].next[0].compactId, 'B.0.1'); - assert.equal(list1._currentBatch[0].next[0].hash, 'QmUnaa1dT2FEYmK1nDD5fJ53Pd2iEDtGL3oLM5M7VLBqHJ'); - // assert.equal(list1._currentBatch[0].next[1].compactId, 'A.0.0'); - assert.equal(list1._currentBatch[0].next[1].hash, 'QmQQhCyFHWAwNm7k5CbDF5iKuHfT2VJU5qUkncQDNAfTbL'); - done(); - })); - - it('finds the next heads after two joins', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - - list1.add("helloA3") - - list1.join(list2); - - list1.add("helloA4") - list1.add("helloA5") - - const lastItem = list1.items[list1.items.length - 1]; - - assert.equal(list1.items.length, 7); - assert.equal(lastItem.next.length, 1); - // assert.equal(lastItem.next[0].compactId, 'A.2.0'); - assert.equal(lastItem.next[0].hash, 'QmPT7qgkysupMuMf2k8yESBL8A55Cva9Y8pqTuA1AMWB4m'); - done(); - })); - - it('finds the next heads after multiple joins', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - const list3 = new List(ipfs, 'C'); - const list4 = new List(ipfs, 'D'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - - list3.add("helloC1") - list4.add("helloD1") - list1.join(list3); - - list1.add("helloA3") - list2.join(list1); - list1.join(list2); - list2.join(list4); - - list4.add("helloD2") - list4.add("helloD3") - list1.add("helloA4") - list1.join(list4); - - list1.add("helloA5") - - const lastItem = list1.items[list1.items.length - 1]; - - assert.equal(list1.items.length, 11); - assert.equal(lastItem.next.length, 2); - // assert.equal(lastItem.next[1].compactId, 'A.4.0'); - assert.equal(lastItem.next[1].hash, 'QmdyS6VUP5wAENpdT1sp6o1JJwMaKajPg1W441MD71r4pE'); - // assert.equal(lastItem.next[0].compactId, 'D.0.2'); - assert.equal(lastItem.next[0].hash, 'QmfWbsDTKd3zhRoJZ2oGeBYmgsnerK3SmFYXZtydgADec7'); - done(); - })); - - it('joins list of one item with list of two items', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - - const lastItem = list1.items[list1.items.length - 1]; - - assert.equal(list1.id, 'A'); - // assert.equal(list1.seq, 1); - // assert.equal(list1.ver, 0); - assert.equal(list1._currentBatch.length, 0); - assert.equal(list1._items.length, 3); - assert.equal(lastItem.id, 'B'); - // assert.equal(lastItem.seq, 0); - // assert.equal(lastItem.ver, 1); - assert.equal(lastItem.data, 'helloB2'); - done(); - })); - - it('joins lists two ways', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - list2.join(list1); - - const lastItem1 = list1.items[list1.items.length - 1]; - - assert.equal(list1.id, 'A'); - // assert.equal(list1.seq, 1); - // assert.equal(list1.ver, 0); - assert.equal(list1._currentBatch.length, 0); - assert.equal(list1._items.length, 4); - assert.equal(lastItem1.id, 'B'); - // assert.equal(lastItem1.seq, 0); - // assert.equal(lastItem1.ver, 1); - assert.equal(lastItem1.data, 'helloB2'); - - const lastItem2 = list2.items[list2.items.length - 1]; - - assert.equal(list2.id, 'B'); - // assert.equal(list2.seq, 2); - // assert.equal(list2.ver, 0); - assert.equal(list2._currentBatch.length, 0); - assert.equal(list2._items.length, 4); - assert.equal(lastItem2.id, 'A'); - // assert.equal(lastItem2.seq, 0); - // assert.equal(lastItem2.ver, 1); - assert.equal(lastItem2.data, 'helloA2'); - done(); - })); - - it('joins lists twice', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - - list1.add("helloA1") - list2.add("helloB1") - list2.join(list1); - - list1.add("helloA2") - list2.add("helloB2") - list2.join(list1); - - const secondItem = list2.items[1]; - const lastItem = list2.items[list2.items.length - 1]; - - assert.equal(list2.id, 'B'); - // assert.equal(list2.seq, 2); - // assert.equal(list2.ver, 0); - assert.equal(list2._currentBatch.length, 0); - assert.equal(list2._items.length, 4); - assert.equal(secondItem.id, 'A'); - // assert.equal(secondItem.seq, 0); - // assert.equal(secondItem.ver, 0); - assert.equal(secondItem.data, 'helloA1'); - assert.equal(lastItem.id, 'A'); - // assert.equal(lastItem.seq, 0); - // assert.equal(lastItem.ver, 1); - assert.equal(lastItem.data, 'helloA2'); - done(); - })); - - it('joins 4 lists to one', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - const list3 = new List(ipfs, 'C'); - const list4 = new List(ipfs, 'D'); - - list1.add("helloA1") - list2.add("helloB1") - list1.add("helloA2") - list2.add("helloB2") - list3.add("helloC1") - list4.add("helloD1") - list3.add("helloC2") - list4.add("helloD2") - list1.join(list2); - list1.join(list3); - list1.join(list4); - - const secondItem = list1.items[1]; - const lastItem = list1.items[list1.items.length - 1]; - - assert.equal(list1.id, 'A'); - // assert.equal(list1.seq, 3); - // assert.equal(list1.ver, 0); - assert.equal(list1._currentBatch.length, 0); - assert.equal(list1._items.length, 8); - assert.equal(secondItem.id, 'A'); - // assert.equal(secondItem.seq, 0); - // assert.equal(secondItem.ver, 1); - assert.equal(secondItem.data, 'helloA2'); - assert.equal(lastItem.id, 'D'); - // assert.equal(lastItem.seq, 0); - // assert.equal(lastItem.ver, 1); - assert.equal(lastItem.data, 'helloD2'); - done(); - })); - - it('joins lists from 4 lists', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - const list3 = new List(ipfs, 'C'); - const list4 = new List(ipfs, 'D'); - - list1.add("helloA1") - list1.join(list2); - list2.add("helloB1") - list2.join(list1); - - list1.add("helloA2") - list2.add("helloB2") - list1.join(list3); - list3.join(list1); - - list3.add("helloC1") - list4.add("helloD1") - - list3.add("helloC2") - list4.add("helloD2") - - list1.join(list3); - list1.join(list2); - list4.join(list2); - list4.join(list1); - list4.join(list3); - - list4.add("helloD3") - list4.add("helloD4") - - const secondItem = list4.items[1]; - const lastItem1 = list4._items[list4._items.length - 1]; - const lastItem2 = list4.items[list4.items.length - 1]; - - assert.equal(list4.id, 'D'); - // assert.equal(list4.seq, 7); - // assert.equal(list4.ver, 2); - assert.equal(list4._currentBatch.length, 2); - assert.equal(list4._items.length, 8); - assert.equal(secondItem.id, 'D'); - // assert.equal(secondItem.seq, 0); - // assert.equal(secondItem.ver, 1); - assert.equal(secondItem.data, 'helloD2'); - assert.equal(lastItem1.id, 'C'); - // assert.equal(lastItem1.seq, 3); - // assert.equal(lastItem1.ver, 1); - assert.equal(lastItem1.data, 'helloC2'); - assert.equal(lastItem2.id, 'D'); - // assert.equal(lastItem2.seq, 7); - // assert.equal(lastItem2.ver, 1); - assert.equal(lastItem2.data, 'helloD4'); - done(); - })); - - it('fetches items from history on join', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'AAA'); - - const count = 32; - for(let i = 1; i < count + 1; i ++) { - list1.add("first " + i); - list2.add("second " + i); - } - - const hash1 = list1.ipfsHash; - const hash2 = list2.ipfsHash; - - const final = new List(ipfs, 'B'); - const other1 = List.fromIpfsHash(ipfs, hash1); - const other2 = List.fromIpfsHash(ipfs, hash2); - final.join(other1); - - assert.equal(_.includes(final.items.map((a) => a.hash), undefined), false); - assert.equal(final.items.length, count); - assert.equal(final.items[0].data, "first 1"); - assert.equal(final.items[final.items.length - 1].data, "first " + count); - - final.join(other2); - assert.equal(final.items.length, count * 2); - assert.equal(final.items[0].data, "second 1"); - assert.equal(final.items[final.items.length - 1].data, "second " + count); - done(); - })); - - it('orders fetched items correctly', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'AAA'); - const final = new List(ipfs, 'B'); - - const count = List.batchSize * 3; - for(let i = 1; i < (count * 2) + 1; i ++) - list1.add("first " + i); - - const hash1 = list1.ipfsHash; - const other1 = List.fromIpfsHash(ipfs, hash1); - final.join(other1); - - assert.equal(final.items[0].data, "first 1"); - assert.equal(final.items[final.items.length - 1].data, "first " + count * 2); - assert.equal(final.items.length, count * 2); - - // Second batch - for(let i = 1; i < count + 1; i ++) - list2.add("second " + i); - - const hash2 = list2.ipfsHash; - const other2 = List.fromIpfsHash(ipfs, hash2); - final.join(other2); - - // console.log(final.items.map((e) => e.comptactId)) - assert.equal(final.items.length, count + count * 2); - assert.equal(final.items[0].data, "second 1"); - assert.equal(final.items[1].data, "second 2"); - assert.equal(final.items[final.items.length - 1].data, "second " + count); - done(); - })); - }); - - describe('findHeads', () => { - it('finds the next head', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - const list3 = new List(ipfs, 'C'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - list1.add("helloA3") - list1.add("helloA4") - list3.add("helloC1") - list3.add("helloC2") - list2.join(list3); - list2.add("helloB3") - list1.join(list2); - list1.add("helloA5") - list1.add("helloA6") - - const heads = List2.findHeads(list1.items) - assert.equal(heads.length, 1); - assert.equal(heads[0].hash, 'QmfUmywxAP8ZXNkxN1CJJ3UsbmEracdeDCzaZzid9zwoe9'); - done(); - })); - - it('finds the next heads', async((done) => { - const list1 = new List(ipfs, 'A'); - const list2 = new List(ipfs, 'B'); - const list3 = new List(ipfs, 'C'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list1.join(list2); - list1.add("helloA3") - list1.add("helloA4") - list3.add("helloC1") - list3.add("helloC2") - list2.join(list3); - list2.add("helloB3") - list1.join(list2); - - const heads = List2.findHeads(list1.items) - assert.equal(heads.length, 2); - assert.equal(heads[0].hash, 'QmT8oHPp2x5t5sKy2jw3ZXKihm1danLbmHMbQ6nnzWRdj6'); - assert.equal(heads[1].hash, 'QmPT7qgkysupMuMf2k8yESBL8A55Cva9Y8pqTuA1AMWB4m'); - done(); - })); - }); - - describe('is a CRDT', () => { - it('join is associative', async((done) => { - let list1 = new List(ipfs, 'A'); - let list2 = new List(ipfs, 'B'); - let list3 = new List(ipfs, 'C'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list3.add("helloC1") - list3.add("helloC2") - - // a + (b + c) - list2.join(list3); - list1.join(list2); - - const res1 = list1.items.map((e) => e.hash).join(","); - - list1 = new List(ipfs, 'A'); - list2 = new List(ipfs, 'B'); - list3 = new List(ipfs, 'C'); - list1.add("helloA1") - list1.add("helloA2") - list2.add("helloB1") - list2.add("helloB2") - list3.add("helloC1") - list3.add("helloC2") - - // (a + b) + c - list1.join(list2); - list1.join(list3); - - const res2 = list1.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 - assert.equal(res1.length, len) - assert.equal(res2.length, len) - assert.equal(res1, res2); - done(); - })); - - it('join is commutative', async((done) => { - let list1 = new List(ipfs, 'A'); - let list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list1.add("helloA2") - list2.join(list1); - list2.add("helloB1") - list2.add("helloB2") - - // b + a - list2.join(list1); - - const res1 = list2.items.map((e) => e.hash).join(","); - - list1 = new List(ipfs, 'A'); - list2 = new List(ipfs, 'B'); - list1.add("helloA1") - list1.add("helloA2") - list2.join(list1); - list2.add("helloB1") - list2.add("helloB2") - - // a + b - list1.join(list2); - - const res2 = list1.items.map((e) => e.hash).join(","); - - // commutativity: a + (b + c) == (a + b) + c - const len = (46 + 1) * 4 - 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(); - })); - - - it('join is idempotent', async((done) => { - const list1 = new List(ipfs, 'A'); - list1.add("helloA1") - list1.add("helloA2") - list1.add("helloA3") - - const list2 = new List(ipfs, 'A'); - list2.add("helloA1") - list2.add("helloA2") - list2.add("helloA3") - - // idempotence: a + a = a - list1.join(list2); - - assert.equal(list1.id, 'A'); - // assert.equal(list1.seq, 1); - // assert.equal(list1.ver, 0); - assert.equal(list1.items.length, 3); - // assert.equal(list1.items[0].ver, 0); - // assert.equal(list1.items[1].ver, 1); - // assert.equal(list1.items[2].ver, 2); - done(); - })); - }); - - describe('clear', () => { - it('TODO', (done) => { - done(); - }); - }); - - describe('_fetchHistory', () => { - it('TODO', (done) => { - done(); - }); - }); - - describe('_fetchRecursive', () => { - it('TODO', (done) => { - done(); - }); - }); - - describe('_insert', () => { - it('TODO', (done) => { - done(); - }); - }); - - describe('_commit', () => { - it('TODO', (done) => { - done(); - }); - }); - - describe('isReferencedInChain', () => { - it('TODO', (done) => { - done(); - }); - }); - - -})); diff --git a/test/orbitlist-node-tests.js b/test/orbitlist-node-tests.js deleted file mode 100644 index 293cc4a..0000000 --- a/test/orbitlist-node-tests.js +++ /dev/null @@ -1,98 +0,0 @@ -'use strict'; - -const _ = require('lodash'); -const async = require('asyncawait/async'); -const await = require('asyncawait/await'); -const assert = require('assert'); -const ipfsDaemon = require('orbit-common/lib/ipfs-daemon'); -const ipfsAPI = require('orbit-common/lib/ipfs-api-promised'); -const Node = require('../src/list/OrbitNode'); - -const startIpfs = async (() => { - return new Promise(async((resolve, reject) => { - const ipfsd = await(ipfsDaemon()); - resolve(ipfsd.ipfs); - })); -}); - -let ipfs; - -describe('OrbitNode', function() { - this.timeout(5000); - - before(async((done) => { - ipfs = await(startIpfs()); - done(); - })); - - describe('Constructor', () => { - it('initializes member variables', async((done) => { - const node = new Node(ipfs, 'A'); - assert.equal(node.id, 'A'); - assert.equal(node.data, null); - assert.equal(node.next.length, 0); - assert.equal(node.hash, 'QmbibmqvDT4LHo6oEFRMgRhKUBw6Fn7SLCp57GKu5eY1uY'); - assert.equal(node._ipfs, ipfs); - done(); - })); - - it('initializes member variables with data', async((done) => { - const node = new Node(ipfs, 'A', 'QmbibmqvDT4LHo6oEFRMgRhKUBw6Fn7SLCp57GKu5eY1uY'); - assert.equal(node.id, 'A'); - assert.equal(node.data, 'QmbibmqvDT4LHo6oEFRMgRhKUBw6Fn7SLCp57GKu5eY1uY'); - assert.equal(node.next.length, 0); - assert.equal(node.hash, 'Qme1c5GGCtkBLZV4dVsZtJj2ZREraupAfyJXrYrzfEVKN5'); - assert.equal(node._ipfs, ipfs); - done(); - })); - }); - - describe('fetchPayload', () => { - it('TODO', async((done) => { - done(); - })); - }); - - describe('hasChild', () => { - it('TODO', async((done) => { - done(); - })); - }); - - describe('fetchPayload', () => { - it('TODO', async((done) => { - done(); - })); - }); - - describe('heads', () => { - it('TODO', async((done) => { - done(); - })); - }); - - describe('ipfsHash', () => { - it('TODO', async((done) => { - done(); - })); - }); - - describe('asJson', () => { - it('TODO', async((done) => { - done(); - })); - }); - - describe('fromIpfsHash', () => { - it('TODO', async((done) => { - done(); - })); - }); - - describe('equals', () => { - it('TODO', async((done) => { - done(); - })); - }); - -});