diff --git a/src/db/event-store.js b/src/db/event-store.js index eef2ff0..5e1d43a 100644 --- a/src/db/event-store.js +++ b/src/db/event-store.js @@ -33,7 +33,7 @@ const Events = async ({ OpLog, Database, ipfs, identity, databaseId, accessContr return { ...database, - type: 'events', + type: 'eventstore', put, add, get, diff --git a/test/db/event-store.test.js b/test/db/event-store.test.js index 633c421..c51e085 100644 --- a/test/db/event-store.test.js +++ b/test/db/event-store.test.js @@ -1,281 +1,130 @@ import { deepStrictEqual, strictEqual } from 'assert' +import mapSeries from 'p-map-series' 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 { EventStore, Database } from '../src/db/index.js' -import { IPFSBlockStorage, LevelStorage } from '../src/storage/index.js' - -// Test utils -import { config, testAPIs, startIpfs, stopIpfs, getIpfsPeerId, waitForPeers } from 'orbit-db-test-utils' -import connectPeers from './utils/connect-nodes.js' -import waitFor from './utils/wait-for.js' -import { createTestIdentities, cleanUpTestIdentities } from './fixtures/orbit-db-identity-keys.js' +import { Log, Entry } from '../../src/oplog/index.js' +import { EventStore, Database } from '../../src/db/index.js' +import { IPFSBlockStorage, LevelStorage } from '../../src/storage/index.js' +import { config, testAPIs, startIpfs, stopIpfs } from 'orbit-db-test-utils' +import { createTestIdentities, cleanUpTestIdentities } from '../fixtures/orbit-db-identity-keys.js' const { sync: rmrf } = rimraf -const { createIdentity } = Identities const OpLog = { Log, Entry, IPFSBlockStorage, LevelStorage } Object.keys(testAPIs).forEach((IPFS) => { - describe('Events Database (' + IPFS + ')', function () { - this.timeout(config.timeout) + describe('DocumentStore Database (' + IPFS + ')', function () { + this.timeout(config.timeout * 2) - let ipfsd1, ipfsd2 - let ipfs1, ipfs2 - let keystore - let peerId1, peerId2 - let identities1, identities2 - let testIdentity1, testIdentity2 - let kv1, kv2 - - const databaseId = 'events-AAA' - - const accessController = { - canAppend: async (entry) => { - const identity = await identities1.getIdentity(entry.identity) - return identity.id === testIdentity1.id - } - } + let ipfsd + let ipfs + let keystore, signingKeyStore + let accessController + let identities1 + let testIdentity1 + let db + const databaseId = 'documentstore-AAA' before(async () => { // Start two IPFS instances - ipfsd1 = await startIpfs(IPFS, config.daemon1) - ipfsd2 = await startIpfs(IPFS, config.daemon2) - ipfs1 = ipfsd1.api - ipfs2 = ipfsd2.api + ipfsd = await startIpfs(IPFS, config.daemon1) + ipfs = ipfsd.api - await connectPeers(ipfs1, ipfs2) - - // Get the peer IDs - peerId1 = await getIpfsPeerId(ipfs1) - peerId2 = await getIpfsPeerId(ipfs2) - - const [identities, testIdentities] = await createTestIdentities(ipfs1, ipfs2) + const [identities, testIdentities] = await createTestIdentities([ipfs]) identities1 = identities[0] - identities2 = identities[1] testIdentity1 = testIdentities[0] - testIdentity2 = testIdentities[1] rmrf(testIdentity1.id) - rmrf(testIdentity2.id) - }) - - afterEach(async () => { - if (kv1) { - await kv1.drop() - await kv1.close() - } - if (kv2) { - await kv2.drop() - await kv2.close() - } }) after(async () => { - await cleanUpTestIdentities([identities1, identities2]) + await cleanUpTestIdentities([identities1]) - if (ipfsd1) { - await stopIpfs(ipfsd1) - } - if (ipfsd2) { - await stopIpfs(ipfsd2) + if (ipfsd) { + await stopIpfs(ipfsd) } if (keystore) { await keystore.close() } + if (signingKeyStore) { + await signingKeyStore.close() + } if (testIdentity1) { rmrf(testIdentity1.id) } - if (testIdentity2) { - rmrf(testIdentity2.id) + }) + + beforeEach(async () => { + db = await EventStore({ OpLog, Database, ipfs, identity: testIdentity1, databaseId, accessController }) + }) + + afterEach(async () => { + if (db) { + await db.drop() + await db.close() } }) - describe('using database', () => { - it('returns all entries in the database', async () => { - let updateCount = 0 - // let syncCount = 0 - - const onUpdate = (entry) => { - // console.log(".", updateCount, entry.payload) - ++updateCount - } - // const onSync = (entry) => { - // ++syncCount - // } - const onError = () => { - } - - kv1 = await EventStore({ OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) - kv2 = await EventStore({ OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) - - // kv1.events.on('update', onUpdate) - kv2.events.on('update', onUpdate) - // kv1.events.on('sync', onSync) - // kv2.events.on('sync', onSync) - // kv1.events.on('error', onError) - kv2.events.on('error', onError) - - strictEqual(kv1.type, 'events') - strictEqual(kv2.type, 'events') - - await waitForPeers(ipfs1, [peerId2], databaseId) - await waitForPeers(ipfs2, [peerId1], databaseId) - - // send a garbage message to pubsub to test onError firing - // await ipfs1.pubsub.publish(databaseId, Uint8Array.from([1, 2, 3, 4, 5])) - - await kv1.add('init') - await kv1.add(true) - await kv1.add('hello') - await kv1.add('friend') - await kv1.add(12345) - await kv1.add('empty') - await kv1.add('') - await kv1.add('friend33') - // const hash = await kv1.add('friend33') - // const lastEntry = await kv1.get(hash) - - // sync() test - // console.time('sync') - // await kv2.sync(lastEntry.bytes) - // console.timeEnd('sync') - - await waitFor(() => updateCount, () => 8) - - // onUpdate test - strictEqual(updateCount, 8) - - // // write access test - // let errorMessage - // try { - // await kv2.set('hello', 'friend4') - // } catch (e) { - // errorMessage = e.message - // } finally { - // const valueNotUpdated = await kv2.get('hello') - // strictEqual(valueNotUpdated, 'friend3') - // notStrictEqual(errorMessage, undefined) - // strictEqual(errorMessage.startsWith('Could not append entry:\nKey'), true) - // } - - // all() test - const all2 = [] - console.time('all2') - for await (const event of kv2.iterator()) { - all2.unshift(event) - } - console.timeEnd('all2') - deepStrictEqual(all2, [ - 'init', - true, - 'hello', - 'friend', - 12345, - 'empty', - '', - 'friend33' - ]) - - const all1 = await kv2.all() - deepStrictEqual(all1, [ - 'init', - true, - 'hello', - 'friend', - 12345, - 'empty', - '', - 'friend33' - ]) - - // onError test - // notStrictEqual(error, undefined) - // strictEqual(error.message, 'CBOR decode error: too many terminals, data makes no sense') - }) + it('creates a document store', async () => { + strictEqual(db.databaseId, databaseId) + strictEqual(db.type, 'eventstore') }) - describe('load database', () => { - it('returns all entries in the database', async () => { - let updateCount = 0 - // let syncCount = 0 + it('puts an event', async () => { + const expected = 'init' - const onUpdate = (entry) => { - ++updateCount + const hash = await db.put(null, expected) + + const actual = await db.get(hash) + strictEqual(actual, expected) + }) + + it('gets an event', async () => { + const expected = 'init' + + const hash = await db.add(expected) + + const actual = await db.get(hash) + strictEqual(actual, expected) + }) + + it('returns all events', async () => { + const events = [ + 'init', + true, + 'hello', + 'friend', + '12345', + 'empty', + 'friend33' + ] + + for (const ev of events) { + await db.add(ev) + } + + const all = await db.all() + + deepStrictEqual(all, events) + }) + + describe('Iterator', () => { + let hashes = [] + const last = arr => arr[arr.length - 1] + + beforeEach(async () => { + hashes = [] + hashes = await mapSeries([0, 1, 2, 3, 4], (i) => db.add('hello' + i)) + }) + + it('returns all items less than head', async () => { + const all = [] + for await (const ev of db.iterator({ lt: last(hashes) })) { + all.unshift(ev) } - // const onSync = (entry) => { - // ++syncCount - // } - kv1 = await EventStore({ OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) - kv2 = await EventStore({ OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) - - // kv1.events.on('update', onUpdate) - kv2.events.on('update', onUpdate) - // kv1.events.on('sync', onSync) - // kv2.events.on('sync', onSync) - - await waitForPeers(ipfs1, [peerId2], databaseId) - await waitForPeers(ipfs2, [peerId1], databaseId) - - await kv1.add('init') - await kv1.add(true) - await kv1.add('hello') - await kv1.add('friend') - await kv1.add(12345) - await kv1.add('empty') - await kv1.add('') - await kv1.add('friend33') - // const hash = await kv1.add('friend33') - // const lastEntry = await kv1.log.get(hash) - - // sync() test - // console.time('sync') - // await kv2.sync(lastEntry.bytes) - // console.timeEnd('sync') - - await waitFor(() => updateCount, () => 8) - - // onUpdate test - strictEqual(updateCount, 8) - - await kv1.close() - await kv2.close() - - kv1 = await EventStore({ OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) - kv2 = await EventStore({ OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) - - // all() test - const all2 = [] - console.time('all2') - for await (const event of kv2.iterator()) { - all2.unshift(event) - } - console.timeEnd('all2') - deepStrictEqual(all2, [ - 'init', - true, - 'hello', - 'friend', - 12345, - 'empty', - '', - 'friend33' - ]) - - const all1 = await kv2.all() - deepStrictEqual(all1, [ - 'init', - true, - 'hello', - 'friend', - 12345, - 'empty', - '', - 'friend33' - ]) + strictEqual(all.length, 4) + deepStrictEqual(all, ['hello0', 'hello1', 'hello2', 'hello3']) }) }) }) diff --git a/test/db/feed.spec.js b/test/db/feed.spec.js index 132841e..df74a4d 100644 --- a/test/db/feed.spec.js +++ b/test/db/feed.spec.js @@ -37,7 +37,6 @@ Object.keys(testAPIs).forEach((IPFS) => { } } - before(async () => { // Start two IPFS instances ipfsd1 = await startIpfs(IPFS, config.daemon1) diff --git a/test/db/kv.spec.js b/test/db/kv.spec.js index 03234dd..ff3c3a2 100644 --- a/test/db/kv.spec.js +++ b/test/db/kv.spec.js @@ -110,8 +110,8 @@ Object.keys(testAPIs).forEach((IPFS) => { // kv1 = await KeyValue({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) // kv2 = await KeyValue({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) - kv1 = await KeyValuePersisted({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) - kv2 = await KeyValuePersisted({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) + kv1 = await KeyValuePersisted({ KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) + kv2 = await KeyValuePersisted({ KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) // kv1.events.on('update', onUpdate) kv2.events.on('update', onUpdate) @@ -229,8 +229,8 @@ Object.keys(testAPIs).forEach((IPFS) => { // kv1 = await KeyValue({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) // kv2 = await KeyValue({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) - kv1 = await KeyValuePersisted({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) - kv2 = await KeyValuePersisted({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) + kv1 = await KeyValuePersisted({ KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) + kv2 = await KeyValuePersisted({ KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) // kv1.events.on('update', onUpdate) kv2.events.on('update', onUpdate) @@ -264,8 +264,8 @@ Object.keys(testAPIs).forEach((IPFS) => { // kv1 = await KeyValue({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) // kv2 = await KeyValue({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) - kv1 = await KeyValuePersisted({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) - kv2 = await KeyValuePersisted({ KeyValue: KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) + kv1 = await KeyValuePersisted({ KeyValue, OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) + kv2 = await KeyValuePersisted({ KeyValue, OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) console.time('get') const value0 = await kv2.get('init') diff --git a/test/db/replication/document-store.test.js b/test/db/replication/document-store.test.js index 65edb49..2a48a72 100644 --- a/test/db/replication/document-store.test.js +++ b/test/db/replication/document-store.test.js @@ -13,7 +13,7 @@ const { sync: rmrf } = rimraf const OpLog = { Log, Entry, IPFSBlockStorage, LevelStorage } Object.keys(testAPIs).forEach((IPFS) => { - describe('DocumentStore Database (' + IPFS + ')', function () { + describe('DocumentStore Replication (' + IPFS + ')', function () { this.timeout(config.timeout * 2) let ipfsd1, ipfsd2 diff --git a/test/db/replication/event-store.test.js b/test/db/replication/event-store.test.js new file mode 100644 index 0000000..b2e596b --- /dev/null +++ b/test/db/replication/event-store.test.js @@ -0,0 +1,144 @@ +import { deepStrictEqual } from 'assert' +import rimraf from 'rimraf' +import { Log, Entry } from '../../../src/oplog/index.js' +import { EventStore, Database } from '../../../src/db/index.js' +import { IPFSBlockStorage, LevelStorage } from '../../../src/storage/index.js' +import { getIpfsPeerId, waitForPeers, config, testAPIs, startIpfs, stopIpfs } from 'orbit-db-test-utils' +import connectPeers from '../../utils/connect-nodes.js' +import { createTestIdentities, cleanUpTestIdentities } from '../../fixtures/orbit-db-identity-keys.js' +import waitFor from '../../utils/wait-for.js' + +const { sync: rmrf } = rimraf + +const OpLog = { Log, Entry, IPFSBlockStorage, LevelStorage } + +Object.keys(testAPIs).forEach((IPFS) => { + describe('EventStore Replication (' + IPFS + ')', function () { + this.timeout(config.timeout * 2) + + let ipfsd1, ipfsd2 + let ipfs1, ipfs2 + let keystore, signingKeyStore + let peerId1, peerId2 + let accessController + let identities1, identities2 + let testIdentity1, testIdentity2 + let db1, db2 + + const databaseId = 'documentstore-AAA' + + 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) + + // Get the peer IDs + peerId1 = await getIpfsPeerId(ipfs1) + peerId2 = await getIpfsPeerId(ipfs2) + + const [identities, testIdentities] = await createTestIdentities([ipfs1, ipfs2]) + identities1 = identities[0] + identities2 = identities[1] + testIdentity1 = testIdentities[0] + testIdentity2 = testIdentities[1] + + accessController = { + canAppend: async (entry) => { + const identity1 = await identities1.getIdentity(entry.identity) + const identity2 = await identities2.getIdentity(entry.identity) + return identity1.id === testIdentity1.id || identity2.id === testIdentity2.id + } + } + + rmrf(testIdentity1.id) + rmrf(testIdentity2.id) + }) + + after(async () => { + await cleanUpTestIdentities([identities1, identities2]) + + if (ipfsd1) { + await stopIpfs(ipfsd1) + } + if (ipfsd2) { + await stopIpfs(ipfsd2) + } + if (keystore) { + await keystore.close() + } + if (signingKeyStore) { + await signingKeyStore.close() + } + if (testIdentity1) { + rmrf(testIdentity1.id) + } + if (testIdentity2) { + rmrf(testIdentity2.id) + } + }) + + beforeEach(async () => { + db1 = await EventStore({ OpLog, Database, ipfs: ipfs1, identity: testIdentity1, databaseId, accessController }) + db2 = await EventStore({ OpLog, Database, ipfs: ipfs2, identity: testIdentity2, databaseId, accessController }) + }) + + afterEach(async () => { + if (db1) { + await db1.drop() + await db1.close() + } + if (db2) { + await db2.drop() + await db2.close() + } + }) + + it('gets all documents', async () => { + let updateDB1Count = 0 + let updateDB2Count = 0 + + const onDB1Update = (entry) => { + ++updateDB1Count + } + + const onDB2Update = (entry) => { + ++updateDB2Count + } + + db1.events.on('update', onDB1Update) + db2.events.on('update', onDB2Update) + + await waitForPeers(ipfs1, [peerId2], databaseId) + await waitForPeers(ipfs2, [peerId1], databaseId) + + const puts = [] + puts.push(await db1.add('init')) + puts.push(await db2.add(true)) + puts.push(await db1.add('hello')) + puts.push(await db2.add('friend')) + puts.push(await db2.add('12345')) + puts.push(await db2.add('empty')) + puts.push(await db2.add('')) + puts.push(await db2.add('friend33')) + + await waitFor(() => updateDB1Count, () => puts.length) + await waitFor(() => updateDB2Count, () => puts.length) + + const all1 = [] + for await (const doc of db1.iterator()) { + all1.unshift(doc) + } + + const all2 = [] + for await (const doc of db2.iterator()) { + all2.unshift(doc) + } + + deepStrictEqual(all1, all2) + }) + }) +})