Merge pull request #18 from orbitdb/dev/fix-oplog-tests

Clean up oplog tests
This commit is contained in:
Haad 2023-03-02 07:10:46 +02:00 committed by GitHub
commit a4fb12c65b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 2034 additions and 2143 deletions

View File

@ -458,4 +458,4 @@ const Log = async (identity, { logId, logHeads, access, entryStorage, headsStora
}
}
export { Log as default, DefaultAccessController }
export { Log as default, DefaultAccessController, Clock }

View File

@ -11,7 +11,6 @@ Object.keys(testAPIs).forEach((IPFS) => {
describe('DocumentStore Database (' + IPFS + ')', function () {
let ipfsd
let ipfs
let keystore, signingKeyStore
let accessController
let identities1
let testIdentity1

View File

@ -13,7 +13,6 @@ Object.keys(testAPIs).forEach((IPFS) => {
describe('EventStore Database (' + IPFS + ')', function () {
let ipfsd
let ipfs
let keystore, signingKeyStore
let accessController
let identities1
let testIdentity1

View File

@ -1,8 +1,7 @@
import { deepStrictEqual } from 'assert'
import rmrf from 'rimraf'
import { Log, Entry } from '../../../src/index.js'
import { Log, Entry, Database } from '../../../src/index.js'
import { DocumentStore } from '../../../src/db/index.js'
import { Database } from '../../../src/index.js'
import { config, startIpfs, stopIpfs } from 'orbit-db-test-utils'
import connectPeers from '../../utils/connect-nodes.js'
import { createTestIdentities, cleanUpTestIdentities } from '../../fixtures/orbit-db-identity-keys.js'

View File

@ -1,8 +1,7 @@
import { deepStrictEqual } from 'assert'
import rmrf from 'rimraf'
import { Log, Entry } from '../../../src/index.js'
import { Log, Entry, Database } from '../../../src/index.js'
import { EventStore } from '../../../src/db/index.js'
import { Database } from '../../../src/index.js'
import { config, startIpfs, stopIpfs } from 'orbit-db-test-utils'
import connectPeers from '../../utils/connect-nodes.js'
import waitFor from '../../utils/wait-for.js'

View File

@ -1,8 +1,7 @@
import { deepStrictEqual } from 'assert'
import rmrf from 'rimraf'
import { Log, Entry } from '../../../src/index.js'
import { Log, Entry, Database } from '../../../src/index.js'
import { KeyValue, KeyValuePersisted } from '../../../src/db/index.js'
import { Database } from '../../../src/index.js'
import { config, startIpfs, stopIpfs } from 'orbit-db-test-utils'
import connectPeers from '../../utils/connect-nodes.js'
import waitFor from '../../utils/wait-for.js'

View File

@ -1,132 +1,117 @@
import { strictEqual, deepStrictEqual } from 'assert'
import rimraf from 'rimraf'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log } from '../../src/oplog/index.js'
import MemoryStorage from '../../src/storage/memory.js'
import LevelStorage from '../../src/storage/level.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import { Log, Identities, KeyStore } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
// Test utils
import { config, testAPIs } from 'orbit-db-test-utils'
const keysPath = './testkeys'
const { sync: rmrf } = rimraf
describe('Log - Append', function () {
this.timeout(5000)
let testIdentity
let keystore
let identities
let testIdentity
Object.keys(testAPIs).forEach((IPFS) => {
describe('Log - Append (' + IPFS + ')', function () {
this.timeout(config.timeout)
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities = await Identities({ keystore })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
const { identityKeyFixtures, signingKeyFixtures, identityKeysPath } = config
let keystore
let identities
before(async () => {
rmrf(identityKeysPath)
await copy(identityKeyFixtures, identityKeysPath)
await copy(signingKeyFixtures, identityKeysPath)
keystore = await KeyStore({ storage: await LevelStorage({ path: identityKeysPath }) })
const storage = await MemoryStorage()
identities = await Identities({ keystore, storage })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
after(async () => {
after(async () => {
if (keystore) {
await keystore.close()
rmrf(identityKeysPath)
})
}
await rmrf(keysPath)
})
describe('append', async () => {
describe('append one', async () => {
let log
let values = []
let heads = []
describe('append', async () => {
describe('append one', async () => {
let log
let values = []
let heads = []
before(async () => {
log = await Log(testIdentity, { logId: 'A' })
await log.append('hello1')
values = await log.values()
heads = await log.heads()
})
before(async () => {
log = await Log(testIdentity, { logId: 'A' })
await log.append('hello1')
values = await log.values()
heads = await log.heads()
})
it('added the correct amount of items', () => {
strictEqual(values.length, 1)
})
it('added the correct amount of items', () => {
strictEqual(values.length, 1)
})
it('added the correct values', async () => {
values.forEach((entry) => {
strictEqual(entry.payload, 'hello1')
})
})
it('added the correct amount of next pointers', async () => {
values.forEach((entry) => {
strictEqual(entry.next.length, 0)
})
})
it('has the correct heads', async () => {
heads.forEach((head) => {
strictEqual(head.hash, values[0].hash)
})
})
it('updated the clocks correctly', async () => {
values.forEach((entry) => {
strictEqual(entry.clock.id, testIdentity.publicKey)
strictEqual(entry.clock.time, 1)
})
it('added the correct values', async () => {
values.forEach((entry) => {
strictEqual(entry.payload, 'hello1')
})
})
describe('append 100 items to a log', async () => {
const amount = 100
const nextPointerAmount = 64
let log
let values = []
let heads = []
before(async () => {
log = await Log(testIdentity, { logId: 'A' })
for (let i = 0; i < amount; i++) {
await log.append('hello' + i, { pointerCount: nextPointerAmount })
}
values = await log.values()
heads = await log.heads()
it('added the correct amount of next pointers', async () => {
values.forEach((entry) => {
strictEqual(entry.next.length, 0)
})
})
it('set the correct heads', () => {
strictEqual(heads.length, 1)
deepStrictEqual(heads[0], values[values.length - 1])
it('has the correct heads', async () => {
heads.forEach((head) => {
strictEqual(head.hash, values[0].hash)
})
})
it('added the correct amount of items', () => {
strictEqual(values.length, amount)
it('updated the clocks correctly', async () => {
values.forEach((entry) => {
strictEqual(entry.clock.id, testIdentity.publicKey)
strictEqual(entry.clock.time, 1)
})
})
})
it('added the correct values', async () => {
values.forEach((entry, index) => {
strictEqual(entry.payload, 'hello' + index)
})
describe('append 100 items to a log', async () => {
const amount = 100
const nextPointerAmount = 64
let log
let values = []
let heads = []
before(async () => {
log = await Log(testIdentity, { logId: 'A' })
for (let i = 0; i < amount; i++) {
await log.append('hello' + i, { pointerCount: nextPointerAmount })
}
values = await log.values()
heads = await log.heads()
})
it('set the correct heads', () => {
strictEqual(heads.length, 1)
deepStrictEqual(heads[0], values[values.length - 1])
})
it('added the correct amount of items', () => {
strictEqual(values.length, amount)
})
it('added the correct values', async () => {
values.forEach((entry, index) => {
strictEqual(entry.payload, 'hello' + index)
})
})
it('updated the clocks correctly', async () => {
values.forEach((entry, index) => {
strictEqual(entry.clock.time, index + 1)
strictEqual(entry.clock.id, testIdentity.publicKey)
})
it('updated the clocks correctly', async () => {
values.forEach((entry, index) => {
strictEqual(entry.clock.time, index + 1)
strictEqual(entry.clock.id, testIdentity.publicKey)
})
})
it('added the correct amount of refs pointers', async () => {
values.forEach((entry, index) => {
strictEqual(entry.refs.length, index > 0 ? Math.floor(Math.log2(Math.min(nextPointerAmount, index))) : 0)
})
it('added the correct amount of refs pointers', async () => {
values.forEach((entry, index) => {
strictEqual(entry.refs.length, index > 0 ? Math.floor(Math.log2(Math.min(nextPointerAmount, index))) : 0)
})
})
})

View File

@ -1,246 +1,242 @@
import { strictEqual, deepStrictEqual } from 'assert'
import rimraf from 'rimraf'
import { Log } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import { config, testAPIs } from 'orbit-db-test-utils'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Identities, KeyStore } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
const { sync: rmrf } = rimraf
const keysPath = './testkeys'
let testIdentity, testIdentity2, testIdentity3
Object.keys(testAPIs).forEach((IPFS) => {
describe('Log - CRDT (' + IPFS + ')', function () {
this.timeout(config.timeout)
describe('Log - CRDT', function () {
this.timeout(5000)
const { identityKeysPath } = config
let keystore
let identities1
let keystore
let identities1
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities1 = await Identities({ keystore })
testIdentity = await identities1.createIdentity({ id: 'userA' })
testIdentity2 = await identities1.createIdentity({ id: 'userB' })
testIdentity3 = await identities1.createIdentity({ id: 'userC' })
})
before(async () => {
keystore = await KeyStore({ path: testKeysPath })
identities1 = await Identities({ keystore })
testIdentity = await identities1.createIdentity({ id: 'userA' })
testIdentity2 = await identities1.createIdentity({ id: 'userB' })
testIdentity3 = await identities1.createIdentity({ id: 'userC' })
})
after(async () => {
after(async () => {
if (keystore) {
await keystore.close()
rmrf(identityKeysPath)
}
await rmrf(keysPath)
})
describe('is a CRDT', async () => {
const logId = 'X'
let log1, log2, log3
beforeEach(async () => {
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
})
describe('is a CRDT', async () => {
const logId = 'X'
it('join is associative', async () => {
const expectedElementsCount = 6
let log1, log2, log3
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
beforeEach(async () => {
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
})
// a + (b + c)
await log2.join(log3)
await log1.join(log2)
it('join is associative', async () => {
const expectedElementsCount = 6
const res1 = await log1.values()
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
// a + (b + c)
await log2.join(log3)
await log1.join(log2)
// (a + b) + c
await log1.join(log2)
await log3.join(log1)
const res1 = await log1.values()
const res2 = await log3.values()
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
// associativity: a + (b + c) == (a + b) + c
strictEqual(res1.length, expectedElementsCount)
strictEqual(res2.length, expectedElementsCount)
deepStrictEqual(res1.map(e => e.hash), res2.map(e => e.hash))
})
// (a + b) + c
await log1.join(log2)
await log3.join(log1)
it('join is commutative', async () => {
const expectedElementsCount = 4
const res2 = await log3.values()
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
// associativity: a + (b + c) == (a + b) + c
strictEqual(res1.length, expectedElementsCount)
strictEqual(res2.length, expectedElementsCount)
deepStrictEqual(res1.map(e => e.hash), res2.map(e => e.hash))
})
// b + a
await log2.join(log1)
const res1 = await log2.values()
it('join is commutative', async () => {
const expectedElementsCount = 4
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
// a + b
await log1.join(log2)
const res2 = await log1.values()
// b + a
await log2.join(log1)
const res1 = await log2.values()
// commutativity: a + b == b + a
strictEqual(res1.length, expectedElementsCount)
strictEqual(res2.length, expectedElementsCount)
deepStrictEqual(res1.map(e => e.hash), res2.map(e => e.hash))
})
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
it('multiple joins are commutative', async () => {
// b + a == a + b
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log2.join(log1)
const resA1 = await log2.values()
// a + b
await log1.join(log2)
const res2 = await log1.values()
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
const resA2 = await log1.values()
// commutativity: a + b == b + a
strictEqual(res1.length, expectedElementsCount)
strictEqual(res2.length, expectedElementsCount)
deepStrictEqual(res1.map(e => e.hash), res2.map(e => e.hash))
})
deepStrictEqual(resA1.map(e => e.hash), resA2.map(e => e.hash))
it('multiple joins are commutative', async () => {
// b + a == a + b
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log2.join(log1)
const resA1 = await log2.values()
// a + b == b + a
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
const resB1 = await log1.values()
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
const resA2 = await log1.values()
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log2.join(log1)
const resB2 = await log2.values()
deepStrictEqual(resA1.map(e => e.hash), resA2.map(e => e.hash))
deepStrictEqual(resB1.map(e => e.hash), resB2.map(e => e.hash))
// a + b == b + a
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
const resB1 = await log1.values()
// a + c == c + a
log1 = await Log(testIdentity, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log3.append('helloC1')
await log3.append('helloC2')
await log3.join(log1)
const resC1 = await log3.values()
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log2.join(log1)
const resB2 = await log2.values()
log1 = await Log(testIdentity, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log3)
const resC2 = await log1.values()
deepStrictEqual(resB1.map(e => e.hash), resB2.map(e => e.hash))
deepStrictEqual(resC1.map(e => e.hash), resC2.map(e => e.hash))
// a + c == c + a
log1 = await Log(testIdentity, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log3.append('helloC1')
await log3.append('helloC2')
await log3.join(log1)
const resC1 = await log3.values()
// c + b == b + c
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
log1 = await Log(testIdentity, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log3)
const resC2 = await log1.values()
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log3.join(log2)
const resD1 = await log3.values()
deepStrictEqual(resC1.map(e => e.hash), resC2.map(e => e.hash))
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log2.join(log3)
const resD2 = await log2.values()
// c + b == b + c
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
deepStrictEqual(resD1.map(e => e.hash), resD2.map(e => e.hash))
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log3.join(log2)
const resD1 = await log3.values()
// a + b + c == c + b + a
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log2)
await log1.join(log3)
const logLeft = await log1.values()
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log2.join(log3)
const resD2 = await log2.values()
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log3.join(log2)
await log3.join(log1)
const logRight = await log3.values()
deepStrictEqual(resD1.map(e => e.hash), resD2.map(e => e.hash))
deepStrictEqual(logLeft.map(e => e.hash), logRight.map(e => e.hash))
})
// a + b + c == c + b + a
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log2)
await log1.join(log3)
const logLeft = await log1.values()
it('join is idempotent', async () => {
const expectedElementsCount = 3
log1 = await Log(testIdentity, { logId })
log2 = await Log(testIdentity2, { logId })
log3 = await Log(testIdentity3, { logId })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log3.join(log2)
await log3.join(log1)
const logRight = await log3.values()
const logA = await Log(testIdentity, { logId })
await logA.append('helloA1')
await logA.append('helloA2')
await logA.append('helloA3')
deepStrictEqual(logLeft.map(e => e.hash), logRight.map(e => e.hash))
})
// idempotence: a + a = a
await logA.join(logA)
const values = await logA.values()
it('join is idempotent', async () => {
const expectedElementsCount = 3
const logA = await Log(testIdentity, { logId })
await logA.append('helloA1')
await logA.append('helloA2')
await logA.append('helloA3')
// idempotence: a + a = a
await logA.join(logA)
const values = await logA.values()
strictEqual(values.length, expectedElementsCount)
})
strictEqual(values.length, expectedElementsCount)
})
})
})

View File

@ -1,201 +1,184 @@
import { strictEqual, deepStrictEqual } from 'assert'
import rimraf from 'rimraf'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Entry } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import { config, testAPIs, startIpfs, stopIpfs } from 'orbit-db-test-utils'
import { Entry, Identities, KeyStore } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
const { sync: rmrf } = rimraf
const { create, isEntry } = Entry
const keysPath = './testkeys'
Object.keys(testAPIs).forEach((IPFS) => {
describe('Entry (' + IPFS + ')', function () {
this.timeout(config.timeout)
describe('Entry', function () {
this.timeout(5000)
const { identityKeyFixtures, signingKeyFixtures, identityKeysPath } = config
let keystore
let identities
let testIdentity
let keystore
let identities
let testIdentity
let ipfsd, ipfs
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities = await Identities({ keystore })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
before(async () => {
ipfsd = await startIpfs(IPFS, config.daemon1)
ipfs = ipfsd.api
await copy(identityKeyFixtures, identityKeysPath)
await copy(signingKeyFixtures, identityKeysPath)
keystore = await KeyStore({ path: testKeysPath })
identities = await Identities({ keystore, ipfs })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
after(async () => {
after(async () => {
if (keystore) {
await keystore.close()
}
await rmrf(keysPath)
})
if (ipfsd) {
await stopIpfs(ipfsd)
describe('create', () => {
it('creates a an empty entry', async () => {
const expectedHash = 'zdpuApShn2wbu8aDWJhmzBtLWmoVF5VBbVVtuszMpscmiUgrH'
const entry = await create(testIdentity, 'A', 'hello')
strictEqual(entry.hash, expectedHash)
strictEqual(entry.id, 'A')
strictEqual(entry.clock.id, testIdentity.publicKey)
strictEqual(entry.clock.time, 0)
strictEqual(entry.v, 2)
strictEqual(entry.payload, 'hello')
strictEqual(entry.next.length, 0)
strictEqual(entry.refs.length, 0)
})
it('creates a entry with payload', async () => {
const expectedHash = 'zdpuApKrG9gBpxSqNRQ1Zq8zkkVTS1GQxYoCkXKtDvuNKv4WB'
const payload = 'hello world'
const entry = await create(testIdentity, 'A', payload)
strictEqual(entry.hash, expectedHash)
strictEqual(entry.payload, payload)
strictEqual(entry.id, 'A')
strictEqual(entry.clock.id, testIdentity.publicKey)
strictEqual(entry.clock.time, 0)
strictEqual(entry.v, 2)
strictEqual(entry.next.length, 0)
strictEqual(entry.refs.length, 0)
})
it('retrieves the identity from an entry', async () => {
const expected = {
id: testIdentity.id,
publicKey: testIdentity.publicKey,
signatures: testIdentity.signatures,
type: testIdentity.type,
hash: testIdentity.hash,
bytes: testIdentity.bytes,
sign: undefined,
verify: undefined
}
const payload = 'hello world'
const entry = await create(testIdentity, 'A', payload)
const entryIdentity = await identities.getIdentity(entry.identity)
rmrf(identityKeysPath)
deepStrictEqual(entryIdentity, expected)
})
describe('create', () => {
it('creates a an empty entry', async () => {
// const expectedHash = 'zdpuAsqjGLA4aAGiSNYeTE5zH6e5ayRpgiZrfN2d3UpmzEF76'
const entry = await create(testIdentity, 'A', 'hello')
// strictEqual(entry.hash, expectedHash)
strictEqual(entry.id, 'A')
strictEqual(entry.clock.id, testIdentity.publicKey)
strictEqual(entry.clock.time, 0)
strictEqual(entry.v, 2)
strictEqual(entry.payload, 'hello')
strictEqual(entry.next.length, 0)
strictEqual(entry.refs.length, 0)
})
it('creates a entry with payload', async () => {
// const expectedHash = 'zdpuB2uuvoKD9cmBV8ET5R9KeytY1Jq72LNQrjEpuEyZURP5Q'
const payload = 'hello world'
const entry = await create(testIdentity, 'A', payload)
strictEqual(entry.payload, payload)
strictEqual(entry.id, 'A')
strictEqual(entry.clock.id, testIdentity.publicKey)
strictEqual(entry.clock.time, 0)
strictEqual(entry.v, 2)
strictEqual(entry.next.length, 0)
strictEqual(entry.refs.length, 0)
// strictEqual(entry.hash, expectedHash)
})
it('retrieves the identity from an entry', async () => {
const expected = {
id: testIdentity.id,
publicKey: testIdentity.publicKey,
signatures: testIdentity.signatures,
type: testIdentity.type,
hash: testIdentity.hash,
bytes: testIdentity.bytes,
sign: undefined,
verify: undefined
}
const payload = 'hello world'
const entry = await create(testIdentity, 'A', payload)
const entryIdentity = await identities.getIdentity(entry.identity)
deepStrictEqual(entryIdentity, expected)
})
it('creates a entry with payload and next', async () => {
// const expectedHash = 'zdpuApstRF3DCyuuNhPks8sG2qXPf6BFbMA7EeaGrn9Y6ZEzQ'
const payload1 = 'hello world'
const payload2 = 'hello again'
const entry1 = await create(testIdentity, 'A', payload1)
entry1.clock.tick()
const entry2 = await create(testIdentity, 'A', payload2, entry1.clock, [entry1])
strictEqual(entry2.payload, payload2)
strictEqual(entry2.next.length, 1)
// strictEqual(entry2.hash, expectedHash)
strictEqual(entry2.clock.id, testIdentity.publicKey)
strictEqual(entry2.clock.time, 1)
})
it('`next` parameter can be an array of strings', async () => {
const entry1 = await create(testIdentity, 'A', 'hello1')
const entry2 = await create(testIdentity, 'A', 'hello2', null, [entry1.hash])
strictEqual(typeof entry2.next[0] === 'string', true)
})
it('throws an error if no params are defined', async () => {
let err
try {
await create()
} catch (e) {
err = e
}
strictEqual(err.message, 'Identity is required, cannot create entry')
})
it('throws an error if identity are not defined', async () => {
let err
try {
await create(null, 'A', 'hello2')
} catch (e) {
err = e
}
strictEqual(err.message, 'Identity is required, cannot create entry')
})
it('throws an error if id is not defined', async () => {
let err
try {
await create(testIdentity, null, 'hello')
} catch (e) {
err = e
}
strictEqual(err.message, 'Entry requires an id')
})
it('throws an error if payload is not defined', async () => {
let err
try {
await create(testIdentity, 'A', null)
} catch (e) {
err = e
}
strictEqual(err.message, 'Entry requires a payload')
})
it('throws an error if next is not an array', async () => {
let err
try {
await create(testIdentity, 'A', 'hello', null, {})
} catch (e) {
err = e
}
strictEqual(err.message, '\'next\' argument is not an array')
})
it('creates a entry with payload and next', async () => {
// const expectedHash = 'zdpuApstRF3DCyuuNhPks8sG2qXPf6BFbMA7EeaGrn9Y6ZEzQ'
const payload1 = 'hello world'
const payload2 = 'hello again'
const entry1 = await create(testIdentity, 'A', payload1)
entry1.clock.tick()
const entry2 = await create(testIdentity, 'A', payload2, entry1.clock, [entry1])
strictEqual(entry2.payload, payload2)
strictEqual(entry2.next.length, 1)
// strictEqual(entry2.hash, expectedHash)
strictEqual(entry2.clock.id, testIdentity.publicKey)
strictEqual(entry2.clock.time, 1)
})
describe('isEntry', () => {
it('is an Entry', async () => {
const entry = await create(testIdentity, 'A', 'hello')
strictEqual(isEntry(entry), true)
})
it('`next` parameter can be an array of strings', async () => {
const entry1 = await create(testIdentity, 'A', 'hello1')
const entry2 = await create(testIdentity, 'A', 'hello2', null, [entry1.hash])
strictEqual(typeof entry2.next[0] === 'string', true)
})
it('is not an Entry - no id', async () => {
const fakeEntry = { next: [], v: 1, hash: 'Foo', payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('throws an error if no params are defined', async () => {
let err
try {
await create()
} catch (e) {
err = e
}
strictEqual(err.message, 'Identity is required, cannot create entry')
})
it('is not an Entry - no seq', async () => {
const fakeEntry = { next: [], v: 1, hash: 'Foo', payload: 123 }
strictEqual(isEntry(fakeEntry), false)
})
it('throws an error if identity are not defined', async () => {
let err
try {
await create(null, 'A', 'hello2')
} catch (e) {
err = e
}
strictEqual(err.message, 'Identity is required, cannot create entry')
})
it('is not an Entry - no next', async () => {
const fakeEntry = { id: 'A', v: 1, hash: 'Foo', payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('throws an error if id is not defined', async () => {
let err
try {
await create(testIdentity, null, 'hello')
} catch (e) {
err = e
}
strictEqual(err.message, 'Entry requires an id')
})
it('is not an Entry - no version', async () => {
const fakeEntry = { id: 'A', next: [], payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('throws an error if payload is not defined', async () => {
let err
try {
await create(testIdentity, 'A', null)
} catch (e) {
err = e
}
strictEqual(err.message, 'Entry requires a payload')
})
it('is not an Entry - no hash', async () => {
const fakeEntry = { id: 'A', v: 1, next: [], payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('throws an error if next is not an array', async () => {
let err
try {
await create(testIdentity, 'A', 'hello', null, {})
} catch (e) {
err = e
}
strictEqual(err.message, '\'next\' argument is not an array')
})
})
it('is not an Entry - no payload', async () => {
const fakeEntry = { id: 'A', v: 1, next: [], hash: 'Foo', seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
describe('isEntry', () => {
it('is an Entry', async () => {
const entry = await create(testIdentity, 'A', 'hello')
strictEqual(isEntry(entry), true)
})
it('is not an Entry - no id', async () => {
const fakeEntry = { next: [], v: 1, hash: 'Foo', payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('is not an Entry - no seq', async () => {
const fakeEntry = { next: [], v: 1, hash: 'Foo', payload: 123 }
strictEqual(isEntry(fakeEntry), false)
})
it('is not an Entry - no next', async () => {
const fakeEntry = { id: 'A', v: 1, hash: 'Foo', payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('is not an Entry - no version', async () => {
const fakeEntry = { id: 'A', next: [], payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('is not an Entry - no hash', async () => {
const fakeEntry = { id: 'A', v: 1, next: [], payload: 123, seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
it('is not an Entry - no payload', async () => {
const fakeEntry = { id: 'A', v: 1, next: [], hash: 'Foo', seq: 0 }
strictEqual(isEntry(fakeEntry), false)
})
})
})

View File

@ -1,184 +1,171 @@
import { strictEqual, deepStrictEqual } from 'assert'
import rimraf from 'rimraf'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import MemoryStorage from '../../src/storage/memory.js'
import { config, testAPIs } from 'orbit-db-test-utils'
import { Log, Identities, KeyStore } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
const { sync: rmrf } = rimraf
let testIdentity
const keysPath = './testkeys'
const last = (arr) => {
return arr[arr.length - 1]
}
Object.keys(testAPIs).forEach((IPFS) => {
describe('Log - Heads (' + IPFS + ')', function () {
this.timeout(config.timeout)
describe('Log - Heads', function () {
this.timeout(5000)
const { identityKeyFixtures, signingKeyFixtures, identityKeysPath } = config
let keystore
let identities
let testIdentity
let keystore
let identities
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities = await Identities({ keystore })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
before(async () => {
rmrf(identityKeysPath)
await copy(identityKeyFixtures, identityKeysPath)
await copy(signingKeyFixtures, identityKeysPath)
keystore = await KeyStore({ path: testKeysPath })
const storage = await MemoryStorage()
identities = await Identities({ keystore, storage })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
after(async () => {
after(async () => {
if (keystore) {
await keystore.close()
rmrf(identityKeysPath)
})
}
await rmrf(keysPath)
})
it('finds one head after one entry', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
strictEqual((await log1.heads()).length, 1)
})
it('finds one head after one entry', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
strictEqual((await log1.heads()).length, 1)
})
it('finds one head after two entries', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
await log1.append('helloA2')
strictEqual((await log1.heads()).length, 1)
})
it('finds one head after two entries', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
await log1.append('helloA2')
strictEqual((await log1.heads()).length, 1)
})
it('latest entry is the the head', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
const entry = await log1.append('helloA2')
deepStrictEqual(entry.hash, (await log1.heads())[0].hash)
})
it('latest entry is the the head', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
const entry = await log1.append('helloA2')
deepStrictEqual(entry.hash, (await log1.heads())[0].hash)
})
it('finds head after a join and append', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
it('finds head after a join and append', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.join(log1)
await log2.append('helloB2')
const expectedHead = last(await log2.values())
await log2.join(log1)
await log2.append('helloB2')
const expectedHead = last(await log2.values())
const heads = await log2.heads()
strictEqual(heads.length, 1)
deepStrictEqual(heads[0].hash, expectedHead.hash)
})
const heads = await log2.heads()
strictEqual(heads.length, 1)
deepStrictEqual(heads[0].hash, expectedHead.hash)
})
it('finds two heads after a join', async () => {
const log2 = await Log(testIdentity, { logId: 'A' })
const log1 = await Log(testIdentity, { logId: 'A' })
it('finds two heads after a join', async () => {
const log2 = await Log(testIdentity, { logId: 'A' })
const log1 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
await log1.append('helloA2')
const expectedHead1 = last(await log1.values())
await log1.append('helloA1')
await log1.append('helloA2')
const expectedHead1 = last(await log1.values())
await log2.append('helloB1')
await log2.append('helloB2')
const expectedHead2 = last(await log2.values())
await log2.append('helloB1')
await log2.append('helloB2')
const expectedHead2 = last(await log2.values())
await log1.join(log2)
await log1.join(log2)
const heads = await log1.heads()
strictEqual(heads.length, 2)
strictEqual(heads[0].hash, expectedHead2.hash)
strictEqual(heads[1].hash, expectedHead1.hash)
})
const heads = await log1.heads()
strictEqual(heads.length, 2)
strictEqual(heads[0].hash, expectedHead2.hash)
strictEqual(heads[1].hash, expectedHead1.hash)
})
it('finds two heads after two joins', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
it('finds two heads after two joins', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
await log1.append('helloA2')
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log1.join(log2)
await log2.append('helloB3')
await log2.append('helloB3')
await log1.append('helloA3')
await log1.append('helloA4')
const expectedHead2 = last(await log2.values())
const expectedHead1 = last(await log1.values())
await log1.append('helloA3')
await log1.append('helloA4')
const expectedHead2 = last(await log2.values())
const expectedHead1 = last(await log1.values())
await log1.join(log2)
await log1.join(log2)
const heads = await log1.heads()
strictEqual(heads.length, 2)
strictEqual(heads[0].hash, expectedHead1.hash)
strictEqual(heads[1].hash, expectedHead2.hash)
})
const heads = await log1.heads()
strictEqual(heads.length, 2)
strictEqual(heads[0].hash, expectedHead1.hash)
strictEqual(heads[1].hash, expectedHead2.hash)
})
it('finds two heads after three joins', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
const log3 = await Log(testIdentity, { logId: 'A' })
it('finds two heads after three joins', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
const log3 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log1.append('helloA3')
await log1.append('helloA4')
const expectedHead1 = last(await log1.values())
await log3.append('helloC1')
await log3.append('helloC2')
await log2.join(log3)
await log2.append('helloB3')
const expectedHead2 = last(await log2.values())
await log1.join(log2)
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log1.append('helloA3')
await log1.append('helloA4')
const expectedHead1 = last(await log1.values())
await log3.append('helloC1')
await log3.append('helloC2')
await log2.join(log3)
await log2.append('helloB3')
const expectedHead2 = last(await log2.values())
await log1.join(log2)
const heads = await log1.heads()
strictEqual(heads.length, 2)
strictEqual(heads[0].hash, expectedHead1.hash)
strictEqual(heads[1].hash, expectedHead2.hash)
})
const heads = await log1.heads()
strictEqual(heads.length, 2)
strictEqual(heads[0].hash, expectedHead1.hash)
strictEqual(heads[1].hash, expectedHead2.hash)
})
it('finds three heads after three joins', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
const log3 = await Log(testIdentity, { logId: 'A' })
it('finds three heads after three joins', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity, { logId: 'A' })
const log3 = await Log(testIdentity, { logId: 'A' })
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log1.append('helloA3')
await log1.append('helloA4')
const expectedHead1 = last(await log1.values())
await log3.append('helloC1')
await log2.append('helloB3')
await log3.append('helloC2')
const expectedHead2 = last(await log2.values())
const expectedHead3 = last(await log3.values())
await log1.join(log2)
await log1.join(log3)
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log1.append('helloA3')
await log1.append('helloA4')
const expectedHead1 = last(await log1.values())
await log3.append('helloC1')
await log2.append('helloB3')
await log3.append('helloC2')
const expectedHead2 = last(await log2.values())
const expectedHead3 = last(await log3.values())
await log1.join(log2)
await log1.join(log3)
const heads = await log1.heads()
strictEqual(heads.length, 3)
deepStrictEqual(heads[0].hash, expectedHead1.hash)
deepStrictEqual(heads[1].hash, expectedHead2.hash)
deepStrictEqual(heads[2].hash, expectedHead3.hash)
})
const heads = await log1.heads()
strictEqual(heads.length, 3)
deepStrictEqual(heads[0].hash, expectedHead1.hash)
deepStrictEqual(heads[1].hash, expectedHead2.hash)
deepStrictEqual(heads[2].hash, expectedHead3.hash)
})
})

View File

@ -1,490 +1,466 @@
import { strictEqual, deepStrictEqual } from 'assert'
import rimraf from 'rimraf'
import { Log } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import LogCreator from './utils/log-creator.js'
import all from 'it-all'
import MemoryStorage from '../../src/storage/memory.js'
import LevelStorage from '../../src/storage/level.js'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Identities, KeyStore } from '../../src/index.js'
import LogCreator from './utils/log-creator.js'
import testKeysPath from '../fixtures/test-keys-path.js '
// Test utils
import { config, testAPIs, startIpfs, stopIpfs } from 'orbit-db-test-utils'
import { identityKeys, signingKeys } from '../fixtures/orbit-db-identity-keys.js'
const { sync: rmrf } = rimraf
const { createLogWithSixteenEntries } = LogCreator
Object.keys(testAPIs).forEach((IPFS) => {
describe('Log - Iterator (' + IPFS + ')', function () {
this.timeout(config.timeout)
const keysPath = './testkeys'
let ipfs
let ipfsd
let keystore
let identities1, identities2, identities3
let testIdentity, testIdentity2, testIdentity3
describe('Log - Iterator', function () {
this.timeout(5000)
let keystore
let identities1, identities2, identities3
let testIdentity, testIdentity2, testIdentity3
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities1 = await Identities({ keystore })
identities2 = await Identities({ keystore })
identities3 = await Identities({ keystore })
testIdentity = await identities1.createIdentity({ id: 'userC' })
testIdentity2 = await identities2.createIdentity({ id: 'userB' })
testIdentity3 = await identities3.createIdentity({ id: 'userC' })
})
after(async () => {
if (keystore) {
await keystore.close()
}
await rmrf(keysPath)
})
describe('Basic iterator functionality', async () => {
let log1
let startHash
const hashes = []
const logSize = 100
beforeEach(async () => {
log1 = await Log(testIdentity, { logId: 'X' })
for (let i = 0; i < logSize; i++) {
const entry = await log1.append('entry' + i)
hashes.push([entry.hash, hashes.length])
}
// entry67
// startHash = 'zdpuAxCuaH2R7AYKZ6ZBeeA94v3FgmHZ8wCfDy7pLVcoc3zSo'
startHash = hashes[67][0]
strictEqual(startHash, hashes[67][0])
})
it('returns length with lte and amount', async () => {
const amount = 10
const it = log1.iterator({
lte: startHash,
amount
})
const result = await all(it)
strictEqual([...result].length, 10)
strictEqual(result[0].hash, startHash)
})
it('returns entries with lte and amount', async () => {
const amount = 10
const it = log1.iterator({
lte: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (67 - i++))
}
strictEqual(i, amount)
})
it('returns length with lt and amount', async () => {
const amount = 10
const it = log1.iterator({
lt: startHash,
amount
})
const result = await all(it)
strictEqual([...result].length, amount)
})
it('returns entries with lt and amount', async () => {
const amount = 10
const it = log1.iterator({
lt: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (66 - i++))
}
strictEqual(i, amount)
})
it('returns correct length with gt and amount', async () => {
const amount = 5
const it = log1.iterator({
gt: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (72 - i++))
}
strictEqual(i, amount)
})
it('returns length with gte and amount', async () => {
const amount = 12
const it = log1.iterator({
gte: startHash,
amount
})
const result = await all(it)
strictEqual([...result].length, amount)
strictEqual(result[result.length - 1].hash, startHash)
})
it('returns entries with gte and amount', async () => {
const amount = 12
const it = log1.iterator({
gte: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (78 - i++))
}
strictEqual(i, amount)
})
it('iterates with lt and gt', async () => {
const expectedHashes = hashes.slice().slice(0, 12).map(e => e[0])
const it = log1.iterator({
gt: expectedHashes[0],
lt: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result.reverse()].map(e => e.hash))
strictEqual(hashes_.length, 10)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[i + 1], h)
i++
}
strictEqual(i, 10)
})
it('iterates with lt and gte', async () => {
const expectedHashes = hashes.slice().slice(0, 26).map(e => e[0])
const it = log1.iterator({
gte: expectedHashes[0],
lt: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, 25)
strictEqual(hashes_.indexOf(expectedHashes[0]), 24)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 1]), -1)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 2]), 0)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 2 - i], h)
i++
}
strictEqual(i, 25)
})
it('iterates with lte and gt', async () => {
const expectedHashes = hashes.slice().slice(0, 5).map(e => e[0])
const it = log1.iterator({
gt: expectedHashes[0],
lte: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, 4)
strictEqual(hashes_.indexOf(expectedHashes[0]), -1)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 1]), 0)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 2]), 1)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 3]), 2)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 4]), 3)
})
it('iterates with lte and gte', async () => {
const expectedHashes = hashes.slice().slice(0, 10).map(e => e[0])
const it = log1.iterator({
gte: expectedHashes[0],
lte: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, 10)
strictEqual(hashes_.indexOf(expectedHashes[0]), 9)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 1]), 0)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 1 - i], h)
i++
}
strictEqual(i, 10)
})
it('iterates the full log by default', async () => {
const expectedHashes = hashes.slice().map(e => e[0])
const it = log1.iterator({})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, logSize)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 1 - i], h)
i++
}
strictEqual(i, logSize)
})
it('iterates the full log with gte and lte and amount', async () => {
const expectedHashes = hashes.slice().map(e => e[0])
const it = log1.iterator({
gte: expectedHashes[0],
lte: expectedHashes[expectedHashes.length - 1],
amount: logSize
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, logSize)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 1 - i], h)
i++
}
strictEqual(i, logSize)
})
it('returns length with gt and default amount', async () => {
const it = log1.iterator({
gt: startHash
})
const result = await all(it)
strictEqual([...result].length, 32)
})
it('returns entries with gt and default amount', async () => {
const it = log1.iterator({
gt: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (logSize - 1 - i++))
}
strictEqual(i, 32)
})
it('returns length with gte and default amount', async () => {
const it = await log1.iterator({
gte: startHash
})
const result = await all(it)
strictEqual([...result].length, 33)
})
it('returns entries with gte and default amount', async () => {
const it = log1.iterator({
gte: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (logSize - 1 - i++))
}
strictEqual(i, 33)
})
it('returns length with lt and default amount value', async () => {
const it = log1.iterator({
lt: startHash
})
const result = await all(it)
strictEqual([...result].length, 67)
})
it('returns entries with lt and default amount value', async () => {
const it = log1.iterator({
lt: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (66 - i++))
}
strictEqual(i, 67)
})
it('returns length with lte and default amount value', async () => {
const it = log1.iterator({
lte: startHash
})
const result = await all(it)
strictEqual([...result].length, 68)
})
it('returns entries with lte and default amount value', async () => {
const it = log1.iterator({
lte: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (67 - i++))
}
strictEqual(i, 68)
})
it('returns zero entries when amount is 0', async () => {
const it = log1.iterator({
amount: 0
})
let i = 0
for await (const entry of it) { // eslint-disable-line no-unused-vars
i++
}
strictEqual(i, 0)
})
})
describe('Iteration over forked/joined logs', async () => {
let fixture, identities, heads
before(async () => {
keystore = await KeyStore({ storage: await LevelStorage({ path: './keys_1', valueEncoding: 'json' }) })
for (const [key, value] of Object.entries(identityKeys)) {
await keystore.addKey(key, value)
}
for (const [key, value] of Object.entries(signingKeys)) {
await keystore.addKey(key, value)
}
const storage = await MemoryStorage()
identities1 = await Identities({ keystore, storage })
identities2 = await Identities({ keystore, storage })
identities3 = await Identities({ keystore, storage })
testIdentity = await identities1.createIdentity({ id: 'userA' })
testIdentity2 = await identities2.createIdentity({ id: 'userB' })
testIdentity3 = await identities3.createIdentity({ id: 'userC' })
ipfsd = await startIpfs(IPFS, config.defaultIpfsConfig)
ipfs = ipfsd.api
identities = [testIdentity3, testIdentity2, testIdentity3, testIdentity]
fixture = await createLogWithSixteenEntries(Log, null, identities)
heads = await fixture.log.heads()
})
after(async () => {
if (ipfsd) {
await stopIpfs(ipfsd)
}
if (keystore) {
await keystore.close()
}
rmrf('./keys_1')
it('returns the full length from all heads', async () => {
const it = fixture.log.iterator({
lte: heads
})
const result = await all(it)
strictEqual([...result].length, 16)
})
describe('Basic iterator functionality', async () => {
let log1
let startHash
const hashes = []
const logSize = 100
beforeEach(async () => {
log1 = await Log(testIdentity, { logId: 'X' })
for (let i = 0; i < logSize; i++) {
const entry = await log1.append('entry' + i)
hashes.push([entry.hash, hashes.length])
}
// entry67
// startHash = 'zdpuAxCuaH2R7AYKZ6ZBeeA94v3FgmHZ8wCfDy7pLVcoc3zSo'
startHash = hashes[67][0]
strictEqual(startHash, hashes[67][0])
it('returns partial entries from all heads', async () => {
const it = fixture.log.iterator({
lte: heads,
amount: 6
})
it('returns length with lte and amount', async () => {
const amount = 10
const result = await all(it)
const it = log1.iterator({
lte: startHash,
amount
})
const result = await all(it)
strictEqual([...result].length, 10)
strictEqual(result[0].hash, startHash)
})
it('returns entries with lte and amount', async () => {
const amount = 10
const it = log1.iterator({
lte: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (67 - i++))
}
strictEqual(i, amount)
})
it('returns length with lt and amount', async () => {
const amount = 10
const it = log1.iterator({
lt: startHash,
amount
})
const result = await all(it)
strictEqual([...result].length, amount)
})
it('returns entries with lt and amount', async () => {
const amount = 10
const it = log1.iterator({
lt: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (66 - i++))
}
strictEqual(i, amount)
})
it('returns correct length with gt and amount', async () => {
const amount = 5
const it = log1.iterator({
gt: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (72 - i++))
}
strictEqual(i, amount)
})
it('returns length with gte and amount', async () => {
const amount = 12
const it = log1.iterator({
gte: startHash,
amount
})
const result = await all(it)
strictEqual([...result].length, amount)
strictEqual(result[result.length - 1].hash, startHash)
})
it('returns entries with gte and amount', async () => {
const amount = 12
const it = log1.iterator({
gte: startHash,
amount
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (78 - i++))
}
strictEqual(i, amount)
})
it('iterates with lt and gt', async () => {
const expectedHashes = hashes.slice().slice(0, 12).map(e => e[0])
const it = log1.iterator({
gt: expectedHashes[0],
lt: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result.reverse()].map(e => e.hash))
strictEqual(hashes_.length, 10)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[i + 1], h)
i++
}
strictEqual(i, 10)
})
it('iterates with lt and gte', async () => {
const expectedHashes = hashes.slice().slice(0, 26).map(e => e[0])
const it = log1.iterator({
gte: expectedHashes[0],
lt: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, 25)
strictEqual(hashes_.indexOf(expectedHashes[0]), 24)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 1]), -1)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 2]), 0)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 2 - i], h)
i++
}
strictEqual(i, 25)
})
it('iterates with lte and gt', async () => {
const expectedHashes = hashes.slice().slice(0, 5).map(e => e[0])
const it = log1.iterator({
gt: expectedHashes[0],
lte: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, 4)
strictEqual(hashes_.indexOf(expectedHashes[0]), -1)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 1]), 0)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 2]), 1)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 3]), 2)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 4]), 3)
})
it('iterates with lte and gte', async () => {
const expectedHashes = hashes.slice().slice(0, 10).map(e => e[0])
const it = log1.iterator({
gte: expectedHashes[0],
lte: expectedHashes[expectedHashes.length - 1]
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, 10)
strictEqual(hashes_.indexOf(expectedHashes[0]), 9)
strictEqual(hashes_.indexOf(expectedHashes[expectedHashes.length - 1]), 0)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 1 - i], h)
i++
}
strictEqual(i, 10)
})
it('iterates the full log by default', async () => {
const expectedHashes = hashes.slice().map(e => e[0])
const it = log1.iterator({})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, logSize)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 1 - i], h)
i++
}
strictEqual(i, logSize)
})
it('iterates the full log with gte and lte and amount', async () => {
const expectedHashes = hashes.slice().map(e => e[0])
const it = log1.iterator({
gte: expectedHashes[0],
lte: expectedHashes[expectedHashes.length - 1],
amount: logSize
})
const result = await all(it)
const hashes_ = await Promise.all([...result].map(e => e.hash))
strictEqual(hashes_.length, logSize)
let i = 0
for (const h of hashes_) {
strictEqual(expectedHashes[expectedHashes.length - 1 - i], h)
i++
}
strictEqual(i, logSize)
})
it('returns length with gt and default amount', async () => {
const it = log1.iterator({
gt: startHash
})
const result = await all(it)
strictEqual([...result].length, 32)
})
it('returns entries with gt and default amount', async () => {
const it = log1.iterator({
gt: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (logSize - 1 - i++))
}
strictEqual(i, 32)
})
it('returns length with gte and default amount', async () => {
const it = await log1.iterator({
gte: startHash
})
const result = await all(it)
strictEqual([...result].length, 33)
})
it('returns entries with gte and default amount', async () => {
const it = log1.iterator({
gte: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (logSize - 1 - i++))
}
strictEqual(i, 33)
})
it('returns length with lt and default amount value', async () => {
const it = log1.iterator({
lt: startHash
})
const result = await all(it)
strictEqual([...result].length, 67)
})
it('returns entries with lt and default amount value', async () => {
const it = log1.iterator({
lt: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (66 - i++))
}
strictEqual(i, 67)
})
it('returns length with lte and default amount value', async () => {
const it = log1.iterator({
lte: startHash
})
const result = await all(it)
strictEqual([...result].length, 68)
})
it('returns entries with lte and default amount value', async () => {
const it = log1.iterator({
lte: startHash
})
let i = 0
for await (const entry of it) {
strictEqual(entry.payload, 'entry' + (67 - i++))
}
strictEqual(i, 68)
})
it('returns zero entries when amount is 0', async () => {
const it = log1.iterator({
amount: 0
})
let i = 0
for await (const entry of it) { // eslint-disable-line no-unused-vars
i++
}
strictEqual(i, 0)
})
deepStrictEqual([...result].map(e => e.payload),
['entryA10', 'entryA9', 'entryA8', 'entryA7', 'entryC0', 'entryA6'])
})
describe('Iteration over forked/joined logs', async () => {
let fixture, identities, heads
before(async () => {
identities = [testIdentity3, testIdentity2, testIdentity3, testIdentity]
fixture = await createLogWithSixteenEntries(Log, ipfs, identities)
heads = await fixture.log.heads()
it('returns partial logs from single heads #1', async () => {
const it = fixture.log.iterator({
lte: [heads[0]]
})
it('returns the full length from all heads', async () => {
const result = await all(it)
strictEqual([...result].length, 10)
})
it('returns partial logs from single heads #2', async () => {
const it = fixture.log.iterator({
lte: [heads[1]]
})
const result = await all(it)
strictEqual([...result].length, 11)
})
it('throws error if lte not a string or array of entries', async () => {
let errMsg
try {
const it = fixture.log.iterator({
lte: heads
lte: false
})
await all(it)
} catch (e) {
errMsg = e.message
}
const result = await all(it)
strictEqual(errMsg, 'lte must be a string or an array of Entries')
})
strictEqual([...result].length, 16)
})
it('throws error if lt not a string or array of entries', async () => {
let errMsg
it('returns partial entries from all heads', async () => {
try {
const it = fixture.log.iterator({
lte: heads,
amount: 6
lt: {}
})
await all(it)
} catch (e) {
errMsg = e.message
}
const result = await all(it)
deepStrictEqual([...result].map(e => e.payload),
['entryA10', 'entryA9', 'entryA8', 'entryA7', 'entryC0', 'entryA6'])
})
it('returns partial logs from single heads #1', async () => {
const it = fixture.log.iterator({
lte: [heads[0]]
})
const result = await all(it)
strictEqual([...result].length, 10)
})
it('returns partial logs from single heads #2', async () => {
const it = fixture.log.iterator({
lte: [heads[1]]
})
const result = await all(it)
strictEqual([...result].length, 11)
})
it('throws error if lte not a string or array of entries', async () => {
let errMsg
try {
const it = fixture.log.iterator({
lte: false
})
await all(it)
} catch (e) {
errMsg = e.message
}
strictEqual(errMsg, 'lte must be a string or an array of Entries')
})
it('throws error if lt not a string or array of entries', async () => {
let errMsg
try {
const it = fixture.log.iterator({
lt: {}
})
await all(it)
} catch (e) {
errMsg = e.message
}
strictEqual(errMsg, 'lt must be a string or an array of Entries')
})
strictEqual(errMsg, 'lt must be a string or an array of Entries')
})
})
})

View File

@ -1,86 +1,87 @@
import { strictEqual, deepStrictEqual } from 'assert'
import { Log } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import { config, testAPIs } from 'orbit-db-test-utils'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Identities, KeyStore } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
let testIdentity, testIdentity2
const keysPath = './testkeys'
Object.keys(testAPIs).forEach(IPFS => {
describe('Log - Join Concurrent Entries (' + IPFS + ')', function () {
this.timeout(config.timeout)
describe('Log - Join Concurrent Entries', function () {
this.timeout(5000)
let keystore
let identities1
let keystore
let identities1
let testIdentity, testIdentity2
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities1 = await Identities({ keystore })
testIdentity = await identities1.createIdentity({ id: 'userA' })
testIdentity2 = await identities1.createIdentity({ id: 'userB' })
})
after(async () => {
if (keystore) {
await keystore.close()
}
await rmrf(keysPath)
})
describe('join ', async () => {
let log1, log2
before(async () => {
keystore = await KeyStore({ path: testKeysPath })
identities1 = await Identities({ keystore })
testIdentity = await identities1.createIdentity({ id: 'userA' })
testIdentity2 = await identities1.createIdentity({ id: 'userB' })
log1 = await Log(testIdentity, { logId: 'A' })
log2 = await Log(testIdentity2, { logId: 'A' })
})
after(async () => {
await keystore.close()
it('joins consistently', async () => {
for (let i = 0; i < 10; i++) {
await log1.append('hello1-' + i)
await log2.append('hello2-' + i)
}
await log1.join(log2)
await log2.join(log1)
const values1 = await log1.values()
const values2 = await log2.values()
strictEqual(values1.length, 20)
strictEqual(values2.length, 20)
deepStrictEqual(values1.map(e => e.payload && e.hash), values2.map(e => e.payload && e.hash))
})
describe('join ', async () => {
let log1, log2
it('Concurrently appending same payload after join results in same state', async () => {
for (let i = 10; i < 20; i++) {
await log1.append('hello1-' + i)
await log2.append('hello2-' + i)
}
before(async () => {
log1 = await Log(testIdentity, { logId: 'A' })
log2 = await Log(testIdentity2, { logId: 'A' })
})
await log1.join(log2)
await log2.join(log1)
it('joins consistently', async () => {
for (let i = 0; i < 10; i++) {
await log1.append('hello1-' + i)
await log2.append('hello2-' + i)
}
await log1.append('same')
await log2.append('same')
await log1.join(log2)
await log2.join(log1)
const values1 = await log1.values()
const values2 = await log2.values()
const values1 = await log1.values()
const values2 = await log2.values()
strictEqual(values1.length, 41)
strictEqual(values2.length, 41)
})
strictEqual(values1.length, 20)
strictEqual(values2.length, 20)
deepStrictEqual(values1.map(e => e.payload && e.hash), values2.map(e => e.payload && e.hash))
})
it('Joining after concurrently appending same payload joins entry once', async () => {
await log1.join(log2)
await log2.join(log1)
it('Concurrently appending same payload after join results in same state', async () => {
for (let i = 10; i < 20; i++) {
await log1.append('hello1-' + i)
await log2.append('hello2-' + i)
}
const values1 = await log1.values()
const values2 = await log2.values()
await log1.join(log2)
await log2.join(log1)
await log1.append('same')
await log2.append('same')
const values1 = await log1.values()
const values2 = await log2.values()
strictEqual(values1.length, 41)
strictEqual(values2.length, 41)
})
it('Joining after concurrently appending same payload joins entry once', async () => {
await log1.join(log2)
await log2.join(log1)
const values1 = await log1.values()
const values2 = await log2.values()
strictEqual(values1.length, 42)
strictEqual(values2.length, 42)
deepStrictEqual(values1.map(e => e.payload && e.hash), values2.map(e => e.payload && e.hash))
})
strictEqual(values1.length, 42)
strictEqual(values2.length, 42)
deepStrictEqual(values1.map(e => e.payload && e.hash), values2.map(e => e.payload && e.hash))
})
})
})

View File

@ -1,444 +1,428 @@
import { strictEqual, notStrictEqual, deepStrictEqual } from 'assert'
import rimraf from 'rimraf'
import { Log, Clock } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import LevelStorage from '../../src/storage/level.js'
import MemoryStorage from '../../src/storage/memory.js'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Identities, KeyStore } from '../../src/index.js'
import { Clock } from '../../src/oplog/log.js'
import testKeysPath from '../fixtures/test-keys-path.js '
// Test utils
import { config, testAPIs } from 'orbit-db-test-utils'
import { identityKeys, signingKeys } from '../fixtures/orbit-db-identity-keys.js'
const { sync: rmrf } = rimraf
const keysPath = './testkeys'
const last = (arr) => {
return arr[arr.length - 1]
}
Object.keys(testAPIs).forEach((IPFS) => {
describe('Log - Join (' + IPFS + ')', async function () {
this.timeout(config.timeout)
describe('Log - Join', async function () {
this.timeout(5000)
let keystore
let log1, log2, log3, log4
let identities1, identities2, identities3, identities4
let testIdentity, testIdentity2, testIdentity3, testIdentity4
let keystore
let log1, log2, log3, log4
let identities1, identities2, identities3, identities4
let testIdentity, testIdentity2, testIdentity3, testIdentity4
before(async () => {
keystore = await KeyStore({ storage: await LevelStorage({ path: './keys_1', valueEncoding: 'json' }) })
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities1 = await Identities({ keystore })
identities2 = await Identities({ keystore })
identities3 = await Identities({ keystore })
identities4 = await Identities({ keystore })
testIdentity = await identities1.createIdentity({ id: 'userX' })
testIdentity2 = await identities2.createIdentity({ id: 'userA' })
testIdentity3 = await identities3.createIdentity({ id: 'userB' })
testIdentity4 = await identities4.createIdentity({ id: 'userC' })
})
for (const [key, value] of Object.entries(identityKeys)) {
await keystore.addKey(key, value)
}
for (const [key, value] of Object.entries(signingKeys)) {
await keystore.addKey(key, value)
}
after(async () => {
if (keystore) {
await keystore.close()
}
await rmrf(keysPath)
})
const storage = await MemoryStorage()
beforeEach(async () => {
log1 = await Log(testIdentity, { logId: 'X' })
log2 = await Log(testIdentity2, { logId: 'X' })
log3 = await Log(testIdentity3, { logId: 'X' })
log4 = await Log(testIdentity4, { logId: 'X' })
})
identities1 = await Identities({ keystore, storage })
identities2 = await Identities({ keystore, storage })
identities3 = await Identities({ keystore, storage })
identities4 = await Identities({ keystore, storage })
testIdentity = await identities1.createIdentity({ id: 'userC' })
testIdentity2 = await identities2.createIdentity({ id: 'userB' })
testIdentity3 = await identities3.createIdentity({ id: 'userD' })
testIdentity4 = await identities4.createIdentity({ id: 'userA' })
it('joins logs', async () => {
const items1 = []
const items2 = []
const amount = 20
for (let i = 1; i <= amount; i++) {
const n1 = await log1.append('entryA' + i)
const n2 = await log2.append('entryB' + i)
items1.push(n1)
items2.push(n2)
}
strictEqual(items1.length, amount)
strictEqual(items2.length, amount)
const valuesA = await log1.values()
const valuesB = await log2.values()
strictEqual(valuesA.length, amount)
strictEqual(valuesB.length, amount)
await log1.join(log2)
const valuesC = await log1.values()
strictEqual(valuesC.length, amount * 2)
strictEqual((await log1.heads()).length, 2)
})
it('throws an error if first log is not defined', async () => {
let err
try {
await log1.join()
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, 'Log instance not defined')
})
it('throws an error if passed argument is not an instance of Log', async () => {
let err
try {
await log1.join({})
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, 'Given argument is not an instance of Log')
})
it('throws an error if trying to join an entry from a different log', async () => {
const logIdA = 'AAA'
const logIdB = 'BBB'
let err
try {
const logA = await Log(testIdentity, { logId: logIdA })
await logA.append('entryA')
const logB = await Log(testIdentity, { logId: logIdB })
await logB.append('entryB')
const valuesB = await logB.values()
await logA.joinEntry(last(valuesB))
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, `Entry's id (${logIdB}) doesn't match the log's id (${logIdA}).`)
})
it('throws an error if trying to join a different log', async () => {
const logIdA = 'AAA'
const logIdB = 'BBB'
let err
try {
const logA = await Log(testIdentity, { logId: logIdA })
await logA.append('entryA')
const logB = await Log(testIdentity, { logId: logIdB })
await logB.append('entryB')
await logA.join(logB)
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, `Entry's id (${logIdB}) doesn't match the log's id (${logIdA}).`)
})
it('joins only unique items', async () => {
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log1.join(log2)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values = await log1.values()
strictEqual(values.length, 4)
deepStrictEqual(values.map((e) => e.payload), expectedData)
const item = last(values)
strictEqual(item.next.length, 1)
})
it('joins logs two ways', async () => {
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log2.join(log1)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values1 = await log1.values()
const values2 = await log2.values()
deepStrictEqual(values1.map((e) => e.hash), values2.map((e) => e.hash))
deepStrictEqual(values1.map((e) => e.payload), expectedData)
deepStrictEqual(values2.map((e) => e.payload), expectedData)
})
it('joins logs twice', async () => {
await log1.append('helloA1')
await log2.append('helloB1')
await log2.join(log1)
await log1.append('helloA2')
await log2.append('helloB2')
await log2.join(log1)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values = await log2.values()
strictEqual(values.length, 4)
deepStrictEqual(values.map((e) => e.payload), expectedData)
})
it('joins 2 logs two ways', async () => {
await log1.append('helloA1')
await log2.append('helloB1')
await log2.join(log1)
await log1.join(log2)
await log1.append('helloA2')
await log2.append('helloB2')
await log2.join(log1)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values = await log2.values()
strictEqual(values.length, 4)
deepStrictEqual(values.map((e) => e.payload), expectedData)
})
it('joins 2 logs two ways and has the right heads at every step', async () => {
await log1.append('helloA1')
const heads1 = await log1.heads()
strictEqual(heads1.length, 1)
strictEqual(heads1[0].payload, 'helloA1')
await log2.append('helloB1')
const heads2 = await log2.heads()
strictEqual(heads2.length, 1)
strictEqual(heads2[0].payload, 'helloB1')
await log2.join(log1)
const heads3 = await log2.heads()
strictEqual(heads3.length, 2)
strictEqual(heads3[0].payload, 'helloB1')
strictEqual(heads3[1].payload, 'helloA1')
await log1.join(log2)
const heads4 = await log1.heads()
strictEqual(heads4.length, 2)
strictEqual(heads4[0].payload, 'helloB1')
strictEqual(heads4[1].payload, 'helloA1')
await log1.append('helloA2')
const heads5 = await log1.heads()
strictEqual(heads5.length, 1)
strictEqual(heads5[0].payload, 'helloA2')
await log2.append('helloB2')
const heads6 = await log2.heads()
strictEqual(heads6.length, 1)
strictEqual(heads6[0].payload, 'helloB2')
await log2.join(log1)
const heads7 = await log2.heads()
strictEqual(heads7.length, 2)
strictEqual(heads7[0].payload, 'helloB2')
strictEqual(heads7[1].payload, 'helloA2')
})
it('joins 4 logs to one', async () => {
// order determined by identity's publicKey
await log1.append('helloA1')
await log1.append('helloA2')
await log3.append('helloB1')
await log3.append('helloB2')
await log2.append('helloC1')
await log2.append('helloC2')
await log4.append('helloD1')
await log4.append('helloD2')
await log1.join(log2)
await log1.join(log3)
await log1.join(log4)
const expectedData = [
'helloA1',
'helloB1',
'helloC1',
'helloD1',
'helloA2',
'helloB2',
'helloC2',
'helloD2'
]
const values = await log1.values()
strictEqual(values.length, 8)
deepStrictEqual(values.map(e => e.payload), expectedData)
})
it('joins 4 logs to one is commutative', async () => {
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log4.append('helloD1')
await log4.append('helloD2')
await log1.join(log2)
await log1.join(log3)
await log1.join(log4)
await log2.join(log1)
await log2.join(log3)
await log2.join(log4)
const values1 = await log1.values()
const values2 = await log1.values()
strictEqual(values1.length, 8)
strictEqual(values2.length, 8)
deepStrictEqual(values1.map(e => e.payload), values2.map(e => e.payload))
})
it('joins logs and updates clocks', async () => {
await log1.append('helloA1')
await log2.append('helloB1')
await log2.join(log1)
await log1.append('helloA2')
await log2.append('helloB2')
strictEqual((await log1.clock()).id, testIdentity.publicKey)
strictEqual((await log2.clock()).id, testIdentity2.publicKey)
strictEqual((await log1.clock()).time, 2)
strictEqual((await log2.clock()).time, 2)
await log3.join(log1)
strictEqual(log3.id, 'X')
strictEqual((await log3.clock()).id, testIdentity3.publicKey)
strictEqual((await log3.clock()).time, 2)
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log3)
await log1.join(log2)
await log4.append('helloD1')
await log4.append('helloD2')
await log4.join(log2)
await log4.join(log1)
await log4.join(log3)
await log4.append('helloD3')
await log4.append('helloD4')
await log1.join(log4)
await log4.join(log1)
await log4.append('helloD5')
await log1.append('helloA5')
await log4.join(log1)
strictEqual((await log4.clock()).id, testIdentity4.publicKey)
strictEqual((await log4.clock()).time, 7)
await log4.append('helloD6')
strictEqual((await log4.clock()).time, 8)
const expectedData = [
{ payload: 'helloA1', id: 'X', clock: new Clock(testIdentity.publicKey, 1) },
{ payload: 'helloB1', id: 'X', clock: new Clock(testIdentity2.publicKey, 1) },
{ payload: 'helloD1', id: 'X', clock: new Clock(testIdentity4.publicKey, 1) },
{ payload: 'helloA2', id: 'X', clock: new Clock(testIdentity.publicKey, 2) },
{ payload: 'helloB2', id: 'X', clock: new Clock(testIdentity2.publicKey, 2) },
{ payload: 'helloD2', id: 'X', clock: new Clock(testIdentity4.publicKey, 2) },
{ payload: 'helloC1', id: 'X', clock: new Clock(testIdentity3.publicKey, 3) },
{ payload: 'helloC2', id: 'X', clock: new Clock(testIdentity3.publicKey, 4) },
{ payload: 'helloD3', id: 'X', clock: new Clock(testIdentity4.publicKey, 5) },
{ payload: 'helloD4', id: 'X', clock: new Clock(testIdentity4.publicKey, 6) },
{ payload: 'helloA5', id: 'X', clock: new Clock(testIdentity.publicKey, 7) },
{ payload: 'helloD5', id: 'X', clock: new Clock(testIdentity4.publicKey, 7) },
{ payload: 'helloD6', id: 'X', clock: new Clock(testIdentity4.publicKey, 8) }
]
const values = await log4.values()
const transformed = values.map((e) => {
return { payload: e.payload, id: e.id, clock: e.clock }
})
after(async () => {
if (keystore) {
await keystore.close()
}
rmrf('./keys_1')
})
beforeEach(async () => {
log1 = await Log(testIdentity, { logId: 'X' })
log2 = await Log(testIdentity2, { logId: 'X' })
log3 = await Log(testIdentity3, { logId: 'X' })
log4 = await Log(testIdentity4, { logId: 'X' })
})
it('joins logs', async () => {
const items1 = []
const items2 = []
const amount = 20
for (let i = 1; i <= amount; i++) {
const n1 = await log1.append('entryA' + i)
const n2 = await log2.append('entryB' + i)
items1.push(n1)
items2.push(n2)
}
strictEqual(items1.length, amount)
strictEqual(items2.length, amount)
const valuesA = await log1.values()
const valuesB = await log2.values()
strictEqual(valuesA.length, amount)
strictEqual(valuesB.length, amount)
await log1.join(log2)
const valuesC = await log1.values()
strictEqual(valuesC.length, amount * 2)
strictEqual((await log1.heads()).length, 2)
})
it('throws an error if first log is not defined', async () => {
let err
try {
await log1.join()
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, 'Log instance not defined')
})
it('throws an error if passed argument is not an instance of Log', async () => {
let err
try {
await log1.join({})
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, 'Given argument is not an instance of Log')
})
it('throws an error if trying to join an entry from a different log', async () => {
const logIdA = 'AAA'
const logIdB = 'BBB'
let err
try {
const logA = await Log(testIdentity, { logId: logIdA })
await logA.append('entryA')
const logB = await Log(testIdentity, { logId: logIdB })
await logB.append('entryB')
const valuesB = await logB.values()
await logA.joinEntry(last(valuesB))
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, `Entry's id (${logIdB}) doesn't match the log's id (${logIdA}).`)
})
it('throws an error if trying to join a different log', async () => {
const logIdA = 'AAA'
const logIdB = 'BBB'
let err
try {
const logA = await Log(testIdentity, { logId: logIdA })
await logA.append('entryA')
const logB = await Log(testIdentity, { logId: logIdB })
await logB.append('entryB')
await logA.join(logB)
} catch (e) {
err = e
}
notStrictEqual(err, null)
strictEqual(err.message, `Entry's id (${logIdB}) doesn't match the log's id (${logIdA}).`)
})
it('joins only unique items', async () => {
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log1.join(log2)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values = await log1.values()
strictEqual(values.length, 4)
deepStrictEqual(values.map((e) => e.payload), expectedData)
const item = last(values)
strictEqual(item.next.length, 1)
})
it('joins logs two ways', async () => {
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log1.join(log2)
await log2.join(log1)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values1 = await log1.values()
const values2 = await log2.values()
deepStrictEqual(values1.map((e) => e.hash), values2.map((e) => e.hash))
deepStrictEqual(values1.map((e) => e.payload), expectedData)
deepStrictEqual(values2.map((e) => e.payload), expectedData)
})
it('joins logs twice', async () => {
await log1.append('helloA1')
await log2.append('helloB1')
await log2.join(log1)
await log1.append('helloA2')
await log2.append('helloB2')
await log2.join(log1)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values = await log2.values()
strictEqual(values.length, 4)
deepStrictEqual(values.map((e) => e.payload), expectedData)
})
it('joins 2 logs two ways', async () => {
await log1.append('helloA1')
await log2.append('helloB1')
await log2.join(log1)
await log1.join(log2)
await log1.append('helloA2')
await log2.append('helloB2')
await log2.join(log1)
const expectedData = [
'helloA1', 'helloB1', 'helloA2', 'helloB2'
]
const values = await log2.values()
strictEqual(values.length, 4)
deepStrictEqual(values.map((e) => e.payload), expectedData)
})
it('joins 2 logs two ways and has the right heads at every step', async () => {
await log1.append('helloA1')
const heads1 = await log1.heads()
strictEqual(heads1.length, 1)
strictEqual(heads1[0].payload, 'helloA1')
await log2.append('helloB1')
const heads2 = await log2.heads()
strictEqual(heads2.length, 1)
strictEqual(heads2[0].payload, 'helloB1')
await log2.join(log1)
const heads3 = await log2.heads()
strictEqual(heads3.length, 2)
strictEqual(heads3[0].payload, 'helloB1')
strictEqual(heads3[1].payload, 'helloA1')
await log1.join(log2)
const heads4 = await log1.heads()
strictEqual(heads4.length, 2)
strictEqual(heads4[0].payload, 'helloB1')
strictEqual(heads4[1].payload, 'helloA1')
await log1.append('helloA2')
const heads5 = await log1.heads()
strictEqual(heads5.length, 1)
strictEqual(heads5[0].payload, 'helloA2')
await log2.append('helloB2')
const heads6 = await log2.heads()
strictEqual(heads6.length, 1)
strictEqual(heads6[0].payload, 'helloB2')
await log2.join(log1)
const heads7 = await log2.heads()
strictEqual(heads7.length, 2)
strictEqual(heads7[0].payload, 'helloB2')
strictEqual(heads7[1].payload, 'helloA2')
})
it('joins 4 logs to one', async () => {
// order determined by identity's publicKey
await log1.append('helloA1')
await log1.append('helloA2')
await log3.append('helloB1')
await log3.append('helloB2')
await log2.append('helloC1')
await log2.append('helloC2')
await log4.append('helloD1')
await log4.append('helloD2')
await log1.join(log2)
await log1.join(log3)
await log1.join(log4)
const expectedData = [
'helloA1',
'helloB1',
'helloC1',
'helloD1',
'helloA2',
'helloB2',
'helloC2',
'helloD2'
]
const values = await log1.values()
strictEqual(values.length, 8)
deepStrictEqual(values.map(e => e.payload), expectedData)
})
it('joins 4 logs to one is commutative', async () => {
await log1.append('helloA1')
await log1.append('helloA2')
await log2.append('helloB1')
await log2.append('helloB2')
await log3.append('helloC1')
await log3.append('helloC2')
await log4.append('helloD1')
await log4.append('helloD2')
await log1.join(log2)
await log1.join(log3)
await log1.join(log4)
await log2.join(log1)
await log2.join(log3)
await log2.join(log4)
const values1 = await log1.values()
const values2 = await log1.values()
strictEqual(values1.length, 8)
strictEqual(values2.length, 8)
deepStrictEqual(values1.map(e => e.payload), values2.map(e => e.payload))
})
it('joins logs and updates clocks', async () => {
await log1.append('helloA1')
await log2.append('helloB1')
await log2.join(log1)
await log1.append('helloA2')
await log2.append('helloB2')
strictEqual((await log1.clock()).id, testIdentity.publicKey)
strictEqual((await log2.clock()).id, testIdentity2.publicKey)
strictEqual((await log1.clock()).time, 2)
strictEqual((await log2.clock()).time, 2)
await log3.join(log1)
strictEqual(log3.id, 'X')
strictEqual((await log3.clock()).id, testIdentity3.publicKey)
strictEqual((await log3.clock()).time, 2)
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log3)
await log1.join(log2)
await log4.append('helloD1')
await log4.append('helloD2')
await log4.join(log2)
await log4.join(log1)
await log4.join(log3)
await log4.append('helloD3')
await log4.append('helloD4')
await log1.join(log4)
await log4.join(log1)
await log4.append('helloD5')
await log1.append('helloA5')
await log4.join(log1)
strictEqual((await log4.clock()).id, testIdentity4.publicKey)
strictEqual((await log4.clock()).time, 7)
await log4.append('helloD6')
strictEqual((await log4.clock()).time, 8)
const expectedData = [
{ payload: 'helloA1', id: 'X', clock: new Clock(testIdentity.publicKey, 1) },
{ payload: 'helloB1', id: 'X', clock: new Clock(testIdentity2.publicKey, 1) },
{ payload: 'helloD1', id: 'X', clock: new Clock(testIdentity4.publicKey, 1) },
{ payload: 'helloA2', id: 'X', clock: new Clock(testIdentity.publicKey, 2) },
{ payload: 'helloB2', id: 'X', clock: new Clock(testIdentity2.publicKey, 2) },
{ payload: 'helloD2', id: 'X', clock: new Clock(testIdentity4.publicKey, 2) },
{ payload: 'helloC1', id: 'X', clock: new Clock(testIdentity3.publicKey, 3) },
{ payload: 'helloC2', id: 'X', clock: new Clock(testIdentity3.publicKey, 4) },
{ payload: 'helloD3', id: 'X', clock: new Clock(testIdentity4.publicKey, 5) },
{ payload: 'helloD4', id: 'X', clock: new Clock(testIdentity4.publicKey, 6) },
{ payload: 'helloA5', id: 'X', clock: new Clock(testIdentity.publicKey, 7) },
{ payload: 'helloD5', id: 'X', clock: new Clock(testIdentity4.publicKey, 7) },
{ payload: 'helloD6', id: 'X', clock: new Clock(testIdentity4.publicKey, 8) }
]
const values = await log4.values()
const transformed = values.map((e) => {
return { payload: e.payload, id: e.id, clock: e.clock }
})
strictEqual(values.length, 13)
deepStrictEqual(transformed, expectedData)
})
it('joins logs from 4 logs', async () => {
await log1.append('helloA1')
await log1.join(log2)
await log2.append('helloB1')
await log2.join(log1)
await log1.append('helloA2')
await log2.append('helloB2')
await log1.join(log3)
strictEqual(log1.id, 'X')
strictEqual((await log1.clock()).id, testIdentity.publicKey)
strictEqual((await log1.clock()).time, 2)
await log3.join(log1)
strictEqual(log3.id, 'X')
strictEqual((await log3.clock()).id, testIdentity3.publicKey)
strictEqual((await log3.clock()).time, 2)
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log3)
await log1.join(log2)
await log4.append('helloD1')
await log4.append('helloD2')
await log4.join(log2)
await log4.join(log1)
await log4.join(log3)
await log4.append('helloD3')
await log4.append('helloD4')
strictEqual((await log4.clock()).id, testIdentity4.publicKey)
strictEqual((await log4.clock()).time, 6)
const expectedData = [
'helloA1',
'helloB1',
'helloD1',
'helloA2',
'helloB2',
'helloD2',
'helloC1',
'helloC2',
'helloD3',
'helloD4'
]
const values = await log4.values()
strictEqual(values.length, 10)
deepStrictEqual(values.map((e) => e.payload), expectedData)
})
strictEqual(values.length, 13)
deepStrictEqual(transformed, expectedData)
})
it('joins logs from 4 logs', async () => {
await log1.append('helloA1')
await log1.join(log2)
await log2.append('helloB1')
await log2.join(log1)
await log1.append('helloA2')
await log2.append('helloB2')
await log1.join(log3)
strictEqual(log1.id, 'X')
strictEqual((await log1.clock()).id, testIdentity.publicKey)
strictEqual((await log1.clock()).time, 2)
await log3.join(log1)
strictEqual(log3.id, 'X')
strictEqual((await log3.clock()).id, testIdentity3.publicKey)
strictEqual((await log3.clock()).time, 2)
await log3.append('helloC1')
await log3.append('helloC2')
await log1.join(log3)
await log1.join(log2)
await log4.append('helloD1')
await log4.append('helloD2')
await log4.join(log2)
await log4.join(log1)
await log4.join(log3)
await log4.append('helloD3')
await log4.append('helloD4')
strictEqual((await log4.clock()).id, testIdentity4.publicKey)
strictEqual((await log4.clock()).time, 6)
const expectedData = [
'helloA1',
'helloB1',
'helloD1',
'helloA2',
'helloB2',
'helloD2',
'helloC1',
'helloC2',
'helloD3',
'helloD4'
]
const values = await log4.values()
strictEqual(values.length, 10)
deepStrictEqual(values.map((e) => e.payload), expectedData)
})
})

View File

@ -2,9 +2,8 @@ import { strictEqual, deepStrictEqual, notStrictEqual, throws } from 'assert'
import rimraf from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Entry, Sorting } from '../../src/oplog/index.js'
import { Identities, KeyStore } from '../../src/index.js'
import bigLogString from '../fixtures/big-log.fixture.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import LogCreator from './utils/log-creator.js'
import testKeysPath from '../fixtures/test-keys-path.js '
import { config, testAPIs, startIpfs, stopIpfs } from 'orbit-db-test-utils'

View File

@ -1,157 +1,146 @@
import { notStrictEqual, deepStrictEqual, strictEqual } from 'assert'
import rimraf from 'rimraf'
import { Log, Entry } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import MemoryStorage from '../../src/storage/memory.js'
import { config, testAPIs } from 'orbit-db-test-utils'
import { Log, Entry, Identities, KeyStore, MemoryStorage } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
const { sync: rmrf } = rimraf
const { create } = Entry
let testIdentity
const keysPath = './testkeys'
Object.keys(testAPIs).forEach((IPFS) => {
describe('Log (' + IPFS + ')', function () {
this.timeout(config.timeout)
describe('Log', function () {
this.timeout(5000)
const { identityKeyFixtures, signingKeyFixtures, identityKeysPath } = config
let keystore
let identities
let testIdentity
let keystore
let identities
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities = await Identities({ keystore })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
before(async () => {
await copy(identityKeyFixtures, identityKeysPath)
await copy(signingKeyFixtures, identityKeysPath)
keystore = await KeyStore({ path: testKeysPath })
const storage = await MemoryStorage()
identities = await Identities({ keystore, storage })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
after(async () => {
after(async () => {
if (keystore) {
await keystore.close()
rmrf(identityKeysPath)
}
await rmrf(keysPath)
})
describe('create', async () => {
it('creates an empty log with default params', async () => {
const log = await Log(testIdentity)
notStrictEqual(log.heads, undefined)
notStrictEqual(log.id, undefined)
notStrictEqual(log.id, undefined)
notStrictEqual(log.clock(), undefined)
notStrictEqual(await log.heads(), undefined)
deepStrictEqual(await log.heads(), [])
const values = await log.values()
deepStrictEqual(values, [])
})
describe('create', async () => {
it('creates an empty log with default params', async () => {
const log = await Log(testIdentity)
notStrictEqual(log.heads, undefined)
notStrictEqual(log.id, undefined)
notStrictEqual(log.id, undefined)
notStrictEqual(log.clock(), undefined)
notStrictEqual(await log.heads(), undefined)
deepStrictEqual(await log.heads(), [])
const values = await log.values()
deepStrictEqual(values, [])
})
it('sets an id', async () => {
const log = await Log(testIdentity, { logId: 'ABC' })
strictEqual(log.id, 'ABC')
})
it('sets the clock id', async () => {
const log = await Log(testIdentity, { logId: 'ABC' })
strictEqual(log.id, 'ABC')
strictEqual((await log.clock()).id, testIdentity.publicKey)
})
it('generates id string if id is not passed as an argument', async () => {
const log = await Log(testIdentity)
strictEqual(typeof log.id === 'string', true)
})
it('sets one head if multiple are given as params', async () => {
const one = await create(testIdentity, 'A', 'entryA', null, [])
const two = await create(testIdentity, 'A', 'entryB', null, [one.hash])
const three = await create(testIdentity, 'A', 'entryC', null, [two.hash])
const four = await create(testIdentity, 'A', 'entryD', null, [two.hash])
const entryStorage = await MemoryStorage()
await entryStorage.put(one.hash, one.bytes)
await entryStorage.put(two.hash, two.bytes)
await entryStorage.put(three.hash, three.bytes)
await entryStorage.put(four.hash, four.bytes)
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, three, two, two], entryStorage })
const values = await log.values()
const heads = await log.heads()
strictEqual(heads.length, 1)
strictEqual(heads[0].hash, three.hash)
strictEqual(values.length, 3)
})
it('sets two heads if two given as params', async () => {
const one = await create(testIdentity, 'A', 'entryA', null, [])
const two = await create(testIdentity, 'A', 'entryB', null, [one.hash])
const three = await create(testIdentity, 'A', 'entryC', null, [two.hash])
const four = await create(testIdentity, 'A', 'entryD', null, [two.hash])
const entryStorage = await MemoryStorage()
await entryStorage.put(one.hash, one.bytes)
await entryStorage.put(two.hash, two.bytes)
await entryStorage.put(three.hash, three.bytes)
await entryStorage.put(four.hash, four.bytes)
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, four, two], entryStorage })
const values = await log.values()
const heads = await log.heads()
strictEqual(heads.length, 2)
strictEqual(heads[1].hash, three.hash)
strictEqual(heads[0].hash, four.hash)
strictEqual(values.length, 4)
})
it('throws an error if heads is not an array', async () => {
let err
try {
await Log(testIdentity, { logId: 'A', entries: [], logHeads: {} })
} catch (e) {
err = e
}
notStrictEqual(err, undefined)
strictEqual(err.message, '\'logHeads\' argument must be an array')
})
it('creates default public AccessController if not defined', async () => {
const log = await Log(testIdentity)
const anyoneCanAppend = await log.access.canAppend('any')
notStrictEqual(log.access, undefined)
strictEqual(anyoneCanAppend, true)
})
it('throws an error if identity is not defined', async () => {
let err
try {
await Log()
} catch (e) {
err = e
}
notStrictEqual(err, undefined)
strictEqual(err.message, 'Identity is required')
})
it('sets an id', async () => {
const log = await Log(testIdentity, { logId: 'ABC' })
strictEqual(log.id, 'ABC')
})
describe('values', () => {
it('returns all entries in the log', async () => {
const log = await Log(testIdentity)
let values = await log.values()
strictEqual(values instanceof Array, true)
strictEqual(values.length, 0)
await log.append('hello1')
await log.append('hello2')
await log.append('hello3')
values = await log.values()
strictEqual(values instanceof Array, true)
strictEqual(values.length, 3)
strictEqual(values[0].payload, 'hello1')
strictEqual(values[1].payload, 'hello2')
strictEqual(values[2].payload, 'hello3')
})
it('sets the clock id', async () => {
const log = await Log(testIdentity, { logId: 'ABC' })
strictEqual(log.id, 'ABC')
strictEqual((await log.clock()).id, testIdentity.publicKey)
})
it('generates id string if id is not passed as an argument', async () => {
const log = await Log(testIdentity)
strictEqual(typeof log.id === 'string', true)
})
it('sets one head if multiple are given as params', async () => {
const one = await create(testIdentity, 'A', 'entryA', null, [])
const two = await create(testIdentity, 'A', 'entryB', null, [one.hash])
const three = await create(testIdentity, 'A', 'entryC', null, [two.hash])
const four = await create(testIdentity, 'A', 'entryD', null, [two.hash])
const entryStorage = await MemoryStorage()
await entryStorage.put(one.hash, one.bytes)
await entryStorage.put(two.hash, two.bytes)
await entryStorage.put(three.hash, three.bytes)
await entryStorage.put(four.hash, four.bytes)
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, three, two, two], entryStorage })
const values = await log.values()
const heads = await log.heads()
strictEqual(heads.length, 1)
strictEqual(heads[0].hash, three.hash)
strictEqual(values.length, 3)
})
it('sets two heads if two given as params', async () => {
const one = await create(testIdentity, 'A', 'entryA', null, [])
const two = await create(testIdentity, 'A', 'entryB', null, [one.hash])
const three = await create(testIdentity, 'A', 'entryC', null, [two.hash])
const four = await create(testIdentity, 'A', 'entryD', null, [two.hash])
const entryStorage = await MemoryStorage()
await entryStorage.put(one.hash, one.bytes)
await entryStorage.put(two.hash, two.bytes)
await entryStorage.put(three.hash, three.bytes)
await entryStorage.put(four.hash, four.bytes)
const log = await Log(testIdentity, { logId: 'A', logHeads: [three, four, two], entryStorage })
const values = await log.values()
const heads = await log.heads()
strictEqual(heads.length, 2)
strictEqual(heads[1].hash, three.hash)
strictEqual(heads[0].hash, four.hash)
strictEqual(values.length, 4)
})
it('throws an error if heads is not an array', async () => {
let err
try {
await Log(testIdentity, { logId: 'A', entries: [], logHeads: {} })
} catch (e) {
err = e
}
notStrictEqual(err, undefined)
strictEqual(err.message, '\'logHeads\' argument must be an array')
})
it('creates default public AccessController if not defined', async () => {
const log = await Log(testIdentity)
const anyoneCanAppend = await log.access.canAppend('any')
notStrictEqual(log.access, undefined)
strictEqual(anyoneCanAppend, true)
})
it('throws an error if identity is not defined', async () => {
let err
try {
await Log()
} catch (e) {
err = e
}
notStrictEqual(err, undefined)
strictEqual(err.message, 'Identity is required')
})
})
describe('values', () => {
it('returns all entries in the log', async () => {
const log = await Log(testIdentity)
let values = await log.values()
strictEqual(values instanceof Array, true)
strictEqual(values.length, 0)
await log.append('hello1')
await log.append('hello2')
await log.append('hello3')
values = await log.values()
strictEqual(values instanceof Array, true)
strictEqual(values.length, 3)
strictEqual(values[0].payload, 'hello1')
strictEqual(values[1].payload, 'hello2')
strictEqual(values[2].payload, 'hello3')
})
})
})

View File

@ -1,172 +1,159 @@
import { strictEqual } from 'assert'
import rimraf from 'rimraf'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log } from '../../src/oplog/index.js'
import { Identities } from '../../src/identities/index.js'
import KeyStore from '../../src/key-store.js'
import MemoryStorage from '../../src/storage/memory.js'
import { Identities, KeyStore, MemoryStorage } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
import { config, testAPIs } from 'orbit-db-test-utils'
const { sync: rmrf } = rimraf
const keysPath = './testkeys'
let testIdentity
describe('Log - References', function () {
this.timeout(60000)
Object.keys(testAPIs).forEach((IPFS) => {
describe('Log - References (' + IPFS + ')', function () {
this.timeout(config.timeout)
let keystore
let identities
let testIdentity
const { identityKeyFixtures, signingKeyFixtures, identityKeysPath } = config
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
identities = await Identities({ keystore })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
let keystore
let identities
before(async () => {
rmrf(identityKeysPath)
await copy(identityKeyFixtures, identityKeysPath)
await copy(signingKeyFixtures, identityKeysPath)
keystore = await KeyStore({ path: testKeysPath })
const storage = await MemoryStorage()
identities = await Identities({ keystore, storage })
testIdentity = await identities.createIdentity({ id: 'userA' })
})
after(async () => {
after(async () => {
if (keystore) {
await keystore.close()
rmrf(identityKeysPath)
}
await rmrf(keysPath)
})
describe('References', async () => {
const amount = 64
it('creates entries with 2 references', async () => {
const maxReferenceDistance = 2
const log1 = await Log(testIdentity, { logId: 'A' })
for (let i = 0; i < amount; i++) {
await log1.append(i.toString(), { pointerCount: maxReferenceDistance })
}
const values1 = await log1.values()
strictEqual(values1[values1.length - 1].refs.length, 1)
})
describe('References', async () => {
const amount = 64
it('creates entries with 4 references', async () => {
const maxReferenceDistance = 2
const log2 = await Log(testIdentity, { logId: 'B' })
it('creates entries with 2 references', async () => {
const maxReferenceDistance = 2
const log1 = await Log(testIdentity, { logId: 'A' })
for (let i = 0; i < amount * 2; i++) {
await log2.append(i.toString(), { pointerCount: Math.pow(maxReferenceDistance, 2) })
}
for (let i = 0; i < amount; i++) {
await log1.append(i.toString(), { pointerCount: maxReferenceDistance })
}
const values2 = await log2.values()
const values1 = await log1.values()
strictEqual(values2[values2.length - 1].refs.length, 2)
})
strictEqual(values1[values1.length - 1].refs.length, 1)
})
it('creates entries with 8 references', async () => {
const maxReferenceDistance = 2
const log3 = await Log(testIdentity, { logId: 'C' })
it('creates entries with 4 references', async () => {
const maxReferenceDistance = 2
const log2 = await Log(testIdentity, { logId: 'B' })
for (let i = 0; i < amount * 3; i++) {
await log3.append(i.toString(), { pointerCount: Math.pow(maxReferenceDistance, 3) })
}
for (let i = 0; i < amount * 2; i++) {
await log2.append(i.toString(), { pointerCount: Math.pow(maxReferenceDistance, 2) })
}
const values3 = await log3.values()
const values2 = await log2.values()
strictEqual(values3[values3.length - 1].refs.length, 3)
})
strictEqual(values2[values2.length - 1].refs.length, 2)
})
it('creates entries with 16 references', async () => {
const maxReferenceDistance = 2
const log4 = await Log(testIdentity, { logId: 'D' })
it('creates entries with 8 references', async () => {
const maxReferenceDistance = 2
const log3 = await Log(testIdentity, { logId: 'C' })
for (let i = 0; i < amount * 4; i++) {
await log4.append(i.toString(), { pointerCount: Math.pow(maxReferenceDistance, 4) })
}
for (let i = 0; i < amount * 3; i++) {
await log3.append(i.toString(), { pointerCount: Math.pow(maxReferenceDistance, 3) })
}
const values4 = await log4.values()
const values3 = await log3.values()
strictEqual(values4[values4.length - 1].refs.length, 4)
})
strictEqual(values3[values3.length - 1].refs.length, 3)
})
const inputs = [
{ amount: 1, referenceCount: 1, refLength: 0 },
{ amount: 1, referenceCount: 2, refLength: 0 },
{ amount: 2, referenceCount: 1, refLength: 1 },
{ amount: 2, referenceCount: 2, refLength: 1 },
{ amount: 3, referenceCount: 2, refLength: 1 },
{ amount: 3, referenceCount: 4, refLength: 1 },
{ amount: 4, referenceCount: 4, refLength: 2 },
{ amount: 4, referenceCount: 4, refLength: 2 },
{ amount: 32, referenceCount: 4, refLength: 2 },
{ amount: 32, referenceCount: 8, refLength: 3 },
{ amount: 32, referenceCount: 16, refLength: 4 },
{ amount: 18, referenceCount: 32, refLength: 5 },
{ amount: 128, referenceCount: 32, refLength: 5 },
{ amount: 63, referenceCount: 64, refLength: 5 },
{ amount: 64, referenceCount: 64, refLength: 6 },
{ amount: 65, referenceCount: 64, refLength: 6 },
{ amount: 91, referenceCount: 64, refLength: 6 },
{ amount: 128, referenceCount: 64, refLength: 6 },
{ amount: 128, referenceCount: 1, refLength: 0 },
{ amount: 128, referenceCount: 2, refLength: 1 },
{ amount: 256, referenceCount: 1, refLength: 0 },
{ amount: 256, referenceCount: 4, refLength: 2 },
{ amount: 256, referenceCount: 8, refLength: 3 },
{ amount: 256, referenceCount: 16, refLength: 4 },
{ amount: 256, referenceCount: 32, refLength: 5 },
{ amount: 1024, referenceCount: 2, refLength: 1 }
]
it('creates entries with 16 references', async () => {
const maxReferenceDistance = 2
const log4 = await Log(testIdentity, { logId: 'D' })
for (let i = 0; i < amount * 4; i++) {
await log4.append(i.toString(), { pointerCount: Math.pow(maxReferenceDistance, 4) })
}
const values4 = await log4.values()
strictEqual(values4[values4.length - 1].refs.length, 4)
})
const inputs = [
{ amount: 1, referenceCount: 1, refLength: 0 },
{ amount: 1, referenceCount: 2, refLength: 0 },
{ amount: 2, referenceCount: 1, refLength: 1 },
{ amount: 2, referenceCount: 2, refLength: 1 },
{ amount: 3, referenceCount: 2, refLength: 1 },
{ amount: 3, referenceCount: 4, refLength: 1 },
{ amount: 4, referenceCount: 4, refLength: 2 },
{ amount: 4, referenceCount: 4, refLength: 2 },
{ amount: 32, referenceCount: 4, refLength: 2 },
{ amount: 32, referenceCount: 8, refLength: 3 },
{ amount: 32, referenceCount: 16, refLength: 4 },
{ amount: 18, referenceCount: 32, refLength: 5 },
{ amount: 128, referenceCount: 32, refLength: 5 },
{ amount: 63, referenceCount: 64, refLength: 5 },
{ amount: 64, referenceCount: 64, refLength: 6 },
{ amount: 65, referenceCount: 64, refLength: 6 },
{ amount: 91, referenceCount: 64, refLength: 6 },
{ amount: 128, referenceCount: 64, refLength: 6 },
{ amount: 128, referenceCount: 1, refLength: 0 },
{ amount: 128, referenceCount: 2, refLength: 1 },
{ amount: 256, referenceCount: 1, refLength: 0 },
{ amount: 256, referenceCount: 4, refLength: 2 },
{ amount: 256, referenceCount: 8, refLength: 3 },
{ amount: 256, referenceCount: 16, refLength: 4 },
{ amount: 256, referenceCount: 32, refLength: 5 },
{ amount: 1024, referenceCount: 2, refLength: 1 }
]
inputs.forEach(input => {
it(`has ${input.refLength} references, max distance ${input.referenceCount}, total of ${input.amount} entries`, async () => {
const test = async (amount, referenceCount, refLength) => {
const storage = await MemoryStorage()
const log1 = await Log(testIdentity, { logId: 'A', storage })
for (let i = 0; i < amount; i++) {
await log1.append((i + 1).toString(), { pointerCount: referenceCount })
}
const values = await log1.values()
strictEqual(values.length, input.amount)
strictEqual(values[values.length - 1].clock.time, input.amount)
for (let k = 0; k < input.amount; k++) {
const idx = values.length - k - 1
strictEqual(values[idx].clock.time, idx + 1)
// Check the first ref (distance 2)
if (values[idx].refs.length > 0) { strictEqual(values[idx].refs[0], values[idx - 2].hash) }
// Check the second ref (distance 4)
if (values[idx].refs.length > 1 && idx > referenceCount) { strictEqual(values[idx].refs[1], values[idx - 4].hash) }
// Check the third ref (distance 8)
if (values[idx].refs.length > 2 && idx > referenceCount) { strictEqual(values[idx].refs[2], values[idx - 8].hash) }
// Check the fourth ref (distance 16)
if (values[idx].refs.length > 3 && idx > referenceCount) { strictEqual(values[idx].refs[3], values[idx - 16].hash) }
// Check the fifth ref (distance 32)
if (values[idx].refs.length > 4 && idx > referenceCount) { strictEqual(values[idx].refs[4], values[idx - 32].hash) }
// Check the fifth ref (distance 64)
if (values[idx].refs.length > 5 && idx > referenceCount) { strictEqual(values[idx].refs[5], values[idx - 64].hash) }
// Check the reference of each entry
if (idx > referenceCount) { strictEqual(values[idx].refs.length, refLength) }
}
inputs.forEach(input => {
it(`has ${input.refLength} references, max distance ${input.referenceCount}, total of ${input.amount} entries`, async () => {
const test = async (amount, referenceCount, refLength) => {
const storage = await MemoryStorage()
const log1 = await Log(testIdentity, { logId: 'A', storage })
for (let i = 0; i < amount; i++) {
await log1.append((i + 1).toString(), { pointerCount: referenceCount })
}
await test(input.amount, input.referenceCount, input.refLength)
})
const values = await log1.values()
strictEqual(values.length, input.amount)
strictEqual(values[values.length - 1].clock.time, input.amount)
for (let k = 0; k < input.amount; k++) {
const idx = values.length - k - 1
strictEqual(values[idx].clock.time, idx + 1)
// Check the first ref (distance 2)
if (values[idx].refs.length > 0) { strictEqual(values[idx].refs[0], values[idx - 2].hash) }
// Check the second ref (distance 4)
if (values[idx].refs.length > 1 && idx > referenceCount) { strictEqual(values[idx].refs[1], values[idx - 4].hash) }
// Check the third ref (distance 8)
if (values[idx].refs.length > 2 && idx > referenceCount) { strictEqual(values[idx].refs[2], values[idx - 8].hash) }
// Check the fourth ref (distance 16)
if (values[idx].refs.length > 3 && idx > referenceCount) { strictEqual(values[idx].refs[3], values[idx - 16].hash) }
// Check the fifth ref (distance 32)
if (values[idx].refs.length > 4 && idx > referenceCount) { strictEqual(values[idx].refs[4], values[idx - 32].hash) }
// Check the fifth ref (distance 64)
if (values[idx].refs.length > 5 && idx > referenceCount) { strictEqual(values[idx].refs[5], values[idx - 64].hash) }
// Check the reference of each entry
if (idx > referenceCount) { strictEqual(values[idx].refs.length, refLength) }
}
}
await test(input.amount, input.referenceCount, input.refLength)
})
})
})

View File

@ -1,153 +1,156 @@
import { strictEqual } from 'assert'
import { Log, Entry } from '../../src/index.js'
import { IPFSBlockStorage } from '../../src/storage/index.js'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Entry, Identities, KeyStore, IPFSBlockStorage } from '../../src/index.js'
import { config, startIpfs, stopIpfs, getIpfsPeerId, waitForPeers, connectPeers } from 'orbit-db-test-utils'
import testKeysPath from '../fixtures/test-keys-path.js '
// Test utils
import { config, testAPIs, startIpfs, stopIpfs, getIpfsPeerId, waitForPeers, connectPeers } from 'orbit-db-test-utils'
import { createTestIdentities, cleanUpTestIdentities } from '../fixtures/orbit-db-identity-keys.js'
const keysPath = './testkeys'
const IPFS = 'js-ipfs'
Object.keys(testAPIs).forEach((IPFS) => {
describe('ipfs-log - Replication (' + IPFS + ')', function () {
this.timeout(config.timeout * 2)
describe('Log - Replication', function () {
this.timeout(60000)
let ipfsd1, ipfsd2
let ipfs1, ipfs2
let id1, id2
let ipfsd1, ipfsd2
let ipfs1, ipfs2
let id1, id2
let keystore
let identities1, identities2
let testIdentity1, testIdentity2
let storage1, storage2
let identities1, identities2
let testIdentity1, testIdentity2
let storage1, storage2
before(async () => {
ipfsd1 = await startIpfs(IPFS, config.daemon1)
ipfsd2 = await startIpfs(IPFS, config.daemon2)
ipfs1 = ipfsd1.api
ipfs2 = ipfsd2.api
before(async () => {
// Start two IPFS instances
ipfsd1 = await startIpfs(IPFS, config.daemon1)
ipfsd2 = await startIpfs(IPFS, config.daemon2)
ipfs1 = ipfsd1.api
ipfs2 = ipfsd2.api
await connectPeers(ipfs1, ipfs2)
await connectPeers(ipfs1, ipfs2)
id1 = await getIpfsPeerId(ipfs1)
id2 = await getIpfsPeerId(ipfs2)
// Get the peer IDs
id1 = await getIpfsPeerId(ipfs1)
id2 = await getIpfsPeerId(ipfs2)
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
const [identities, testIdentities] = await createTestIdentities(ipfs1, ipfs2)
identities1 = identities[0]
identities2 = identities[1]
testIdentity2 = testIdentities[0]
testIdentity1 = testIdentities[1]
identities1 = await Identities({ keystore, ipfs: ipfs1 })
identities2 = await Identities({ keystore, ipfs: ipfs2 })
testIdentity1 = await identities1.createIdentity({ id: 'userB' })
testIdentity2 = await identities2.createIdentity({ id: 'userA' })
storage1 = await IPFSBlockStorage({ ipfs: ipfs1 })
storage2 = await IPFSBlockStorage({ ipfs: ipfs2 })
storage1 = await IPFSBlockStorage({ ipfs: ipfs1 })
storage2 = await IPFSBlockStorage({ ipfs: ipfs2 })
})
after(async () => {
await stopIpfs(ipfsd1)
await stopIpfs(ipfsd2)
if (keystore) {
await keystore.close()
}
await storage1.close()
await storage2.close()
await rmrf(keysPath)
})
describe('replicates logs deterministically', async function () {
const amount = 128 + 1
const logId = 'A'
let log1, log2, input1, input2
const handleMessage1 = async (message) => {
const { id: peerId } = await ipfs1.id()
const messageIsFromMe = (message) => String(peerId) === String(message.from)
try {
if (!messageIsFromMe(message)) {
const entry = await Entry.decode(message.data)
await storage1.put(entry.hash, entry.bytes)
await log1.joinEntry(entry)
}
} catch (e) {
console.error(e)
}
}
const handleMessage2 = async (message) => {
const { id: peerId } = await ipfs2.id()
const messageIsFromMe = (message) => String(peerId) === String(message.from)
try {
if (!messageIsFromMe(message)) {
const entry = await Entry.decode(message.data)
await storage2.put(entry.hash, entry.bytes)
await log2.joinEntry(entry)
}
} catch (e) {
console.error(e)
}
}
beforeEach(async () => {
log1 = await Log(testIdentity1, { logId, storage: storage1 })
log2 = await Log(testIdentity2, { logId, storage: storage2 })
input1 = await Log(testIdentity1, { logId, storage: storage1 })
input2 = await Log(testIdentity2, { logId, storage: storage2 })
await ipfs1.pubsub.subscribe(logId, handleMessage1)
await ipfs2.pubsub.subscribe(logId, handleMessage2)
})
after(async () => {
await cleanUpTestIdentities([identities1, identities2])
await stopIpfs(ipfsd1)
await stopIpfs(ipfsd2)
await storage1.close()
await storage2.close()
afterEach(async () => {
await ipfs1.pubsub.unsubscribe(logId, handleMessage1)
await ipfs2.pubsub.unsubscribe(logId, handleMessage2)
})
describe('replicates logs deterministically', async function () {
const amount = 128 + 1
const logId = 'A'
it('replicates logs', async () => {
await waitForPeers(ipfs1, [id2], logId)
await waitForPeers(ipfs2, [id1], logId)
let log1, log2, input1, input2
const handleMessage1 = async (message) => {
const { id: peerId } = await ipfs1.id()
const messageIsFromMe = (message) => String(peerId) === String(message.from)
try {
if (!messageIsFromMe(message)) {
const entry = await Entry.decode(message.data)
await storage1.put(entry.hash, entry.bytes)
await log1.joinEntry(entry)
}
} catch (e) {
console.error(e)
}
for (let i = 1; i <= amount; i++) {
const entry1 = await input1.append('A' + i)
const entry2 = await input2.append('B' + i)
await ipfs1.pubsub.publish(logId, entry1.bytes)
await ipfs2.pubsub.publish(logId, entry2.bytes)
}
const handleMessage2 = async (message) => {
const { id: peerId } = await ipfs2.id()
const messageIsFromMe = (message) => String(peerId) === String(message.from)
try {
if (!messageIsFromMe(message)) {
const entry = await Entry.decode(message.data)
await storage2.put(entry.hash, entry.bytes)
await log2.joinEntry(entry)
}
} catch (e) {
console.error(e)
}
console.log('Messages sent')
const whileProcessingMessages = (timeoutMs) => {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error('timeout')), timeoutMs)
const timer = setInterval(async () => {
const valuesA = await log1.values()
const valuesB = await log2.values()
if (valuesA.length + valuesB.length === amount * 2) {
clearInterval(timer)
clearTimeout(timeout)
console.log('Messages received')
resolve()
}
}, 200)
})
}
beforeEach(async () => {
log1 = await Log(testIdentity1, { logId, storage: storage1 })
log2 = await Log(testIdentity2, { logId, storage: storage2 })
input1 = await Log(testIdentity1, { logId, storage: storage1 })
input2 = await Log(testIdentity2, { logId, storage: storage2 })
await ipfs1.pubsub.subscribe(logId, handleMessage1)
await ipfs2.pubsub.subscribe(logId, handleMessage2)
})
await whileProcessingMessages(config.timeout)
afterEach(async () => {
await ipfs1.pubsub.unsubscribe(logId, handleMessage1)
await ipfs2.pubsub.unsubscribe(logId, handleMessage2)
})
const result = await Log(testIdentity1, { logId, storage: storage1 })
await result.join(log1)
await result.join(log2)
it('replicates logs', async () => {
await waitForPeers(ipfs1, [id2], logId)
await waitForPeers(ipfs2, [id1], logId)
const values1 = await log1.values()
const values2 = await log2.values()
const values3 = await result.values()
for (let i = 1; i <= amount; i++) {
const entry1 = await input1.append('A' + i)
const entry2 = await input2.append('B' + i)
await ipfs1.pubsub.publish(logId, entry1.bytes)
await ipfs2.pubsub.publish(logId, entry2.bytes)
}
console.log('Messages sent')
const whileProcessingMessages = (timeoutMs) => {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error('timeout')), timeoutMs)
const timer = setInterval(async () => {
const valuesA = await log1.values()
const valuesB = await log2.values()
if (valuesA.length + valuesB.length === amount * 2) {
clearInterval(timer)
clearTimeout(timeout)
console.log('Messages received')
resolve()
}
}, 200)
})
}
await whileProcessingMessages(config.timeout)
const result = await Log(testIdentity1, { logId, storage: storage1 })
await result.join(log1)
await result.join(log2)
const values1 = await log1.values()
const values2 = await log2.values()
const values3 = await result.values()
strictEqual(values1.length, amount)
strictEqual(values2.length, amount)
strictEqual(values3.length, amount * 2)
strictEqual(values3[0].payload, 'A1')
strictEqual(values3[1].payload, 'B1')
strictEqual(values3[2].payload, 'A2')
strictEqual(values3[3].payload, 'B2')
strictEqual(values3[99].payload, 'B50')
strictEqual(values3[100].payload, 'A51')
strictEqual(values3[198].payload, 'A100')
strictEqual(values3[199].payload, 'B100')
})
strictEqual(values1.length, amount)
strictEqual(values2.length, amount)
strictEqual(values3.length, amount * 2)
strictEqual(values3[0].payload, 'A1')
strictEqual(values3[1].payload, 'B1')
strictEqual(values3[2].payload, 'A2')
strictEqual(values3[3].payload, 'B2')
strictEqual(values3[99].payload, 'B50')
strictEqual(values3[100].payload, 'A51')
strictEqual(values3[198].payload, 'A100')
strictEqual(values3[199].payload, 'B100')
})
})
})

View File

@ -1,167 +1,173 @@
import { notStrictEqual, strictEqual } from 'assert'
import { Log } from '../../src/oplog/index.js'
import { config, testAPIs } from 'orbit-db-test-utils'
import { createTestIdentities, cleanUpTestIdentities } from '../fixtures/orbit-db-identity-keys.js'
import rmrf from 'rimraf'
import { copy } from 'fs-extra'
import { Log, Identities, KeyStore } from '../../src/index.js'
import testKeysPath from '../fixtures/test-keys-path.js '
Object.keys(testAPIs).forEach((IPFS) => {
describe('Signed Log (' + IPFS + ')', function () {
this.timeout(config.timeout)
const keysPath = './testkeys'
let identities1, identities2
let testIdentity, testIdentity2
describe('Signed Log', function () {
this.timeout(5000)
before(async () => {
const [identities, testIdentities] = await createTestIdentities()
identities1 = identities[0]
identities2 = identities[1]
testIdentity = testIdentities[0]
testIdentity2 = testIdentities[1]
})
let keystore
let identities
let testIdentity1, testIdentity2
after(async () => {
await cleanUpTestIdentities([identities1, identities2])
})
before(async () => {
await copy(testKeysPath, keysPath)
keystore = await KeyStore({ path: keysPath })
it('creates a signed log', async () => {
const logId = 'A'
const log = await Log(testIdentity, { logId })
notStrictEqual(log.id, null)
strictEqual(log.id, logId)
})
identities = await Identities({ keystore })
testIdentity1 = await identities.createIdentity({ id: 'userB' })
testIdentity2 = await identities.createIdentity({ id: 'userA' })
})
// it('has the correct identity', () => {
// const log = await Log(testIdentity, { logId: 'A' })
// notStrictEqual(log.id, null)
// strictEqual(log.id, 'A')
// strictEqual(log.identity.id, '03e0480538c2a39951d054e17ff31fde487cb1031d0044a037b53ad2e028a3e77c')
// strictEqual(log.identity.publicKey, '048bef2231e64d5c7147bd4b8afb84abd4126ee8d8335e4b069ac0a65c7be711cea5c1b8d47bc20ebaecdca588600ddf2894675e78b2ef17cf49e7bbaf98080361')
// strictEqual(log.identity.signatures.id, '3045022100f5f6f10571d14347aaf34e526ce3419fd64d75ffa7aa73692cbb6aeb6fbc147102203a3e3fa41fa8fcbb9fc7c148af5b640e2f704b20b3a4e0b93fc3a6d44dffb41e')
// strictEqual(log.identity.signatures.publicKey, '3044022020982b8492be0c184dc29de0a3a3bd86a86ba997756b0bf41ddabd24b47c5acf02203745fda39d7df650a5a478e52bbe879f0cb45c074025a93471414a56077640a4')
// })
after(async () => {
if (keystore) {
await keystore.close()
}
await rmrf(keysPath)
})
it('has the correct public key', async () => {
const log = await Log(testIdentity, { logId: 'A' })
strictEqual(log.identity.publicKey, testIdentity.publicKey)
})
it('creates a signed log', async () => {
const logId = 'A'
const log = await Log(testIdentity1, { logId })
notStrictEqual(log.id, null)
strictEqual(log.id, logId)
})
it('has the correct pkSignature', async () => {
const log = await Log(testIdentity, { logId: 'A' })
strictEqual(log.identity.signatures.id, testIdentity.signatures.id)
})
// it('has the correct identity', () => {
// const log = await Log(testIdentity, { logId: 'A' })
// notStrictEqual(log.id, null)
// strictEqual(log.id, 'A')
// strictEqual(log.identity.id, '03e0480538c2a39951d054e17ff31fde487cb1031d0044a037b53ad2e028a3e77c')
// strictEqual(log.identity.publicKey, '048bef2231e64d5c7147bd4b8afb84abd4126ee8d8335e4b069ac0a65c7be711cea5c1b8d47bc20ebaecdca588600ddf2894675e78b2ef17cf49e7bbaf98080361')
// strictEqual(log.identity.signatures.id, '3045022100f5f6f10571d14347aaf34e526ce3419fd64d75ffa7aa73692cbb6aeb6fbc147102203a3e3fa41fa8fcbb9fc7c148af5b640e2f704b20b3a4e0b93fc3a6d44dffb41e')
// strictEqual(log.identity.signatures.publicKey, '3044022020982b8492be0c184dc29de0a3a3bd86a86ba997756b0bf41ddabd24b47c5acf02203745fda39d7df650a5a478e52bbe879f0cb45c074025a93471414a56077640a4')
// })
it('has the correct signature', async () => {
const log = await Log(testIdentity, { logId: 'A' })
strictEqual(log.identity.signatures.publicKey, testIdentity.signatures.publicKey)
})
it('has the correct public key', async () => {
const log = await Log(testIdentity1, { logId: 'A' })
strictEqual(log.identity.publicKey, testIdentity1.publicKey)
})
// it('entries contain an identity', async () => {
// const log = await Log(testIdentity, { logId: 'A' })
// await log.append('one')
// const values = await log.values()
// notStrictEqual(values[0].sig, null)
// deepStrictEqual(values[0].identity, testIdentity.toJSON())
// })
it('has the correct pkSignature', async () => {
const log = await Log(testIdentity1, { logId: 'A' })
strictEqual(log.identity.signatures.id, testIdentity1.signatures.id)
})
it('doesn\'t sign entries when identity is not defined', async () => {
let err
try {
await Log(null)
} catch (e) {
err = e
it('has the correct signature', async () => {
const log = await Log(testIdentity1, { logId: 'A' })
strictEqual(log.identity.signatures.publicKey, testIdentity1.signatures.publicKey)
})
// it('entries contain an identity', async () => {
// const log = await Log(testIdentity, { logId: 'A' })
// await log.append('one')
// const values = await log.values()
// notStrictEqual(values[0].sig, null)
// deepStrictEqual(values[0].identity, testIdentity.toJSON())
// })
it('doesn\'t sign entries when identity is not defined', async () => {
let err
try {
await Log(null)
} catch (e) {
err = e
}
strictEqual(err.message, 'Identity is required')
})
it('throws an error if log is signed but trying to merge with an entry that doesn\'t have public signing key', async () => {
const log1 = await Log(testIdentity1, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A' })
let err
try {
await log1.append('one')
const entry = await log2.append('two')
delete entry.key
await log1.joinEntry(entry)
} catch (e) {
err = e.toString()
}
strictEqual(err, 'Error: Entry doesn\'t have a key')
})
it('throws an error if log is signed but trying to merge an entry that doesn\'t have a signature', async () => {
const log1 = await Log(testIdentity1, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A' })
let err
try {
await log1.append('one')
const entry = await log2.append('two')
delete entry.sig
await log1.joinEntry(entry)
} catch (e) {
err = e.toString()
}
strictEqual(err, 'Error: Entry doesn\'t have a signature')
})
it('throws an error if log is signed but the signature doesn\'t verify', async () => {
const log1 = await Log(testIdentity1, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A' })
let err
try {
const entry1 = await log1.append('one')
const entry2 = await log2.append('two')
entry2.sig = entry1.sig
await log1.joinEntry(entry2)
} catch (e) {
err = e.toString()
}
const entry = (await log2.values())[0]
const values = await log1.values()
strictEqual(err, `Error: Could not validate signature for entry "${entry.hash}"`)
strictEqual(values.length, 1)
strictEqual(values[0].payload, 'one')
})
it('throws an error if entry doesn\'t have append access', async () => {
const denyAccess = { canAppend: () => false }
const log1 = await Log(testIdentity1, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A', access: denyAccess })
let err
try {
await log1.append('one')
await log2.append('two')
await log1.join(log2)
} catch (e) {
err = e.toString()
}
strictEqual(err, `Error: Could not append entry:\nKey "${testIdentity2.hash}" is not allowed to write to the log`)
})
it('throws an error upon join if entry doesn\'t have append access', async () => {
const testACL = {
canAppend: async (entry) => {
const identity = await identities.getIdentity(entry.identity)
return identity && identity.id !== testIdentity2.id
}
strictEqual(err.message, 'Identity is required')
})
}
const log1 = await Log(testIdentity1, { logId: 'A', access: testACL })
const log2 = await Log(testIdentity2, { logId: 'A' })
it('throws an error if log is signed but trying to merge with an entry that doesn\'t have public signing key', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A' })
let err
try {
await log1.append('one')
await log2.append('two')
await log1.join(log2)
} catch (e) {
err = e.toString()
}
let err
try {
await log1.append('one')
const entry = await log2.append('two')
delete entry.key
await log1.joinEntry(entry)
} catch (e) {
err = e.toString()
}
strictEqual(err, 'Error: Entry doesn\'t have a key')
})
it('throws an error if log is signed but trying to merge an entry that doesn\'t have a signature', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A' })
let err
try {
await log1.append('one')
const entry = await log2.append('two')
delete entry.sig
await log1.joinEntry(entry)
} catch (e) {
err = e.toString()
}
strictEqual(err, 'Error: Entry doesn\'t have a signature')
})
it('throws an error if log is signed but the signature doesn\'t verify', async () => {
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A' })
let err
try {
const entry1 = await log1.append('one')
const entry2 = await log2.append('two')
entry2.sig = entry1.sig
await log1.joinEntry(entry2)
} catch (e) {
err = e.toString()
}
const entry = (await log2.values())[0]
const values = await log1.values()
strictEqual(err, `Error: Could not validate signature for entry "${entry.hash}"`)
strictEqual(values.length, 1)
strictEqual(values[0].payload, 'one')
})
it('throws an error if entry doesn\'t have append access', async () => {
const denyAccess = { canAppend: () => false }
const log1 = await Log(testIdentity, { logId: 'A' })
const log2 = await Log(testIdentity2, { logId: 'A', access: denyAccess })
let err
try {
await log1.append('one')
await log2.append('two')
await log1.join(log2)
} catch (e) {
err = e.toString()
}
strictEqual(err, `Error: Could not append entry:\nKey "${testIdentity2.hash}" is not allowed to write to the log`)
})
it('throws an error upon join if entry doesn\'t have append access', async () => {
const testACL = {
canAppend: async (entry) => {
const identity = await identities1.getIdentity(entry.identity)
return identity && identity.id !== testIdentity2.id
}
}
const log1 = await Log(testIdentity, { logId: 'A', access: testACL })
const log2 = await Log(testIdentity2, { logId: 'A' })
let err
try {
await log1.append('one')
await log2.append('two')
await log1.join(log2)
} catch (e) {
err = e.toString()
}
strictEqual(err, `Error: Could not append entry:\nKey "${testIdentity2.hash}" is not allowed to write to the log`)
})
strictEqual(err, `Error: Could not append entry:\nKey "${testIdentity2.hash}" is not allowed to write to the log`)
})
})