diff --git a/src/feed-store.test.js b/src/feed-store.test.js index 4e1bc77..07ff375 100644 --- a/src/feed-store.test.js +++ b/src/feed-store.test.js @@ -12,17 +12,24 @@ import eos from 'end-of-stream-promise'; import { FeedStore } from './feed-store'; -describe('FeedStore', () => { - let booksFeed; - let usersFeed; - let groupsFeed; - let feedStore; +async function createDefault () { const directory = tempy.directory(); - function createDefault () { - return FeedStore.create(directory, { feedOptions: { valueEncoding: 'utf-8' } }); - } + return { + directory, + feedStore: await FeedStore.create(directory, { feedOptions: { valueEncoding: 'utf-8' } }) + }; +} + +async function defaultFeeds (feedStore) { + return { + booksFeed: await feedStore.openFeed('/books', { metadata: { topic: 'books' } }), + usersFeed: await feedStore.openFeed('/users'), + groupsFeed: await feedStore.openFeed('/groups') + }; +} +describe('FeedStore', () => { test('Config default', async () => { const feedStore = await FeedStore.create(ram); expect(feedStore).toBeInstanceOf(FeedStore); @@ -33,111 +40,133 @@ describe('FeedStore', () => { const feedStore2 = new FeedStore(ram); expect(feedStore2).toBeInstanceOf(FeedStore); expect(feedStore2.opened).toBeFalsy(); - feedStore2.initialize(); + feedStore2.open(); await expect(feedStore2.ready()).resolves.toBeUndefined(); expect(feedStore2.opened).toBeTruthy(); }); - test('Should throw an assert error creating without storage.', async () => { - await expect(FeedStore.create()).rejects.toThrow(/storage is required/); - }); + test('Config default + custom database + custom hypercore', async () => { + const customHypercore = jest.fn((...args) => { + return hypercore(...args); + }); - test('Config default and valueEncoding utf-8', async () => { - feedStore = await createDefault(); + const database = hypertrie(ram, { valueEncoding: 'json' }); + database.list = jest.fn((_, cb) => cb(null, [])); + + const feedStore = await FeedStore.create(ram, { + database: () => database, + hypercore: customHypercore + }); expect(feedStore).toBeInstanceOf(FeedStore); + expect(database.list.mock.calls.length).toBe(1); + + await feedStore.openFeed('/test'); + + expect(customHypercore.mock.calls.length).toBe(1); + }); + + test('Should throw an assert error creating without storage.', async () => { + await expect(FeedStore.create()).rejects.toThrow(/storage is required/); }); test('Create feed', async () => { - const metadata = { topic: 'books' }; - booksFeed = await feedStore.openFeed('/books', { metadata }); + const { feedStore } = await createDefault(); + const { booksFeed } = await defaultFeeds(feedStore); + expect(booksFeed).toBeInstanceOf(hypercore); + const booksFeedDescriptor = feedStore.getDescriptors().find(fd => fd.path === '/books'); expect(booksFeedDescriptor).toHaveProperty('path', '/books'); - expect(booksFeedDescriptor.metadata).toEqual(metadata); + expect(booksFeedDescriptor.metadata).toHaveProperty('topic', 'books'); + await pify(booksFeed.append.bind(booksFeed))('Foundation and Empire'); await expect(pify(booksFeed.head.bind(booksFeed))()).resolves.toBe('Foundation and Empire'); + // It should return the same opened instance. await expect(feedStore.openFeed('/books')).resolves.toBe(booksFeed); + // You can't open a feed with a different key. await expect(feedStore.openFeed('/books', { key: Buffer.from('...') })).rejects.toThrow(/Invalid public key/); await expect(feedStore.openFeed('/foo', { key: booksFeed.key })).rejects.toThrow(/Feed exists/); - - // Create a reader feed from key - const feedStore2 = await FeedStore.create(ram); - const readerFeed = await feedStore2.openFeed('/reader', { key: booksFeed.key }); - expect(readerFeed).toBeInstanceOf(hypercore); }); test('Create duplicate feed', async () => { - const [feed1, feed2] = await Promise.all([feedStore.openFeed('/users'), feedStore.openFeed('/users')]); - expect(feed1).toBe(feed2); - usersFeed = feed1; - groupsFeed = await feedStore.openFeed('/groups'); + const { feedStore } = await createDefault(); + + const [usersFeed, feed2] = await Promise.all([feedStore.openFeed('/users'), feedStore.openFeed('/users')]); + expect(usersFeed).toBe(feed2); await pify(usersFeed.append.bind(usersFeed))('alice'); await expect(pify(usersFeed.head.bind(usersFeed))()).resolves.toBe('alice'); }); test('Create and close a feed', async () => { - await expect(feedStore.closeFeed('/fooo')).rejects.toThrow(/Feed not found/); - await feedStore.closeFeed('/groups'); - expect(groupsFeed.opened).toBeTruthy(); - }); + const { feedStore } = await createDefault(); - test('Config default + custom database + custom hypercore', async () => { - const customHypercore = jest.fn((...args) => { - return hypercore(...args); - }); - - const database = hypertrie(ram, { valueEncoding: 'json' }); - database.list = jest.fn((_, cb) => cb(null, [])); - - const feedStore = await FeedStore.create(ram, { - database: () => database, - hypercore: customHypercore - }); - - expect(feedStore).toBeInstanceOf(FeedStore); - expect(database.list.mock.calls.length).toBe(1); - - await feedStore.openFeed('/test'); - - expect(customHypercore.mock.calls.length).toBe(1); + await expect(feedStore.closeFeed('/foo')).rejects.toThrow(/Feed not found/); + const foo = await feedStore.openFeed('/foo'); + await feedStore.closeFeed('/foo'); + expect(foo.opened).toBeTruthy(); }); test('Descriptors', async () => { + const { feedStore } = await createDefault(); + const { booksFeed } = await defaultFeeds(feedStore); + expect(feedStore.getDescriptors().map(fd => fd.path)).toEqual(['/books', '/users', '/groups']); expect(feedStore.getDescriptorByDiscoveryKey(booksFeed.discoveryKey).path).toEqual('/books'); }); test('Feeds', async () => { - expect(feedStore.getOpenFeeds().map(f => f.key)).toEqual([booksFeed.key, usersFeed.key]); + const { feedStore } = await createDefault(); + const { booksFeed, usersFeed, groupsFeed } = await defaultFeeds(feedStore); + + expect(feedStore.getOpenFeeds().map(f => f.key)).toEqual([booksFeed.key, usersFeed.key, groupsFeed.key]); expect(feedStore.getOpenFeed(fd => fd.key.equals(booksFeed.key))).toBe(booksFeed); expect(feedStore.getOpenFeed(() => false)).toBeUndefined(); expect(feedStore.getOpenFeeds(fd => fd.path === '/books')).toEqual([booksFeed]); }); - test('Load feed', async () => { - const [feed] = await feedStore.openFeeds(fd => fd.path === '/groups'); + test('Close/Load feed', async () => { + const { feedStore } = await createDefault(); + const { booksFeed } = await defaultFeeds(feedStore); + + await feedStore.closeFeed('/books'); + expect(feedStore.getDescriptors().find(fd => fd.path === '/books')).toHaveProperty('opened', false); + + const [feed] = await feedStore.openFeeds(fd => fd.path === '/books'); expect(feed).toBeDefined(); - expect(feed.key).toEqual(groupsFeed.key); - expect(feedStore.getDescriptors().find(fd => fd.path === '/groups')).toHaveProperty('opened', true); + expect(feed.key).toEqual(booksFeed.key); + expect(feedStore.getDescriptors().find(fd => fd.path === '/books')).toHaveProperty('opened', true); }); test('Close feedStore and their feeds', async () => { + const { feedStore } = await createDefault(); + await defaultFeeds(feedStore); + + expect(feedStore.opened).toBe(true); + expect(feedStore.getDescriptors().filter(fd => fd.opened).length).toBe(3); + await feedStore.close(); expect(feedStore.getDescriptors().filter(fd => fd.opened).length).toBe(0); expect(feedStore.opened).toBe(false); }); test('Reopen feedStore and recreate feeds from the indexDB', async () => { - await feedStore.initialize(); + const { feedStore } = await createDefault(); + let { booksFeed, usersFeed } = await defaultFeeds(feedStore); + await pify(booksFeed.append.bind(booksFeed))('Foundation and Empire'); + await pify(usersFeed.append.bind(usersFeed))('alice'); + + await feedStore.close(); + await feedStore.open(); + expect(feedStore.opened).toBe(true); expect(feedStore.getDescriptors().length).toBe(3); - const booksFeed = await feedStore.openFeed('/books'); - const [usersFeed] = await feedStore.openFeeds(fd => fd.path === '/users'); + booksFeed = await feedStore.openFeed('/books'); + ([usersFeed] = await feedStore.openFeeds(fd => fd.path === '/users')); expect(feedStore.getDescriptors().filter(fd => fd.opened).length).toBe(2); await expect(pify(booksFeed.head.bind(booksFeed))()).resolves.toBe('Foundation and Empire'); @@ -149,6 +178,9 @@ describe('FeedStore', () => { }); test('Delete descriptor', async () => { + const { feedStore } = await createDefault(); + await defaultFeeds(feedStore); + await feedStore.deleteDescriptor('/books'); expect(feedStore.getDescriptors().length).toBe(2); }); @@ -442,14 +474,14 @@ describe('FeedStore', () => { // Check that the metadata was updated in indexdb. await feedStore.close(); - await feedStore.initialize(); + await feedStore.open(); descriptor = feedStore.getDescriptors().find(fd => fd.path === '/test'); expect(descriptor.metadata).toEqual({ tag: 1 }); }); test('openFeed should wait until FeedStore is ready', async () => { const feedStore = new FeedStore(ram); - feedStore.initialize(); + feedStore.open(); const feed = await feedStore.openFeed('/test'); expect(feed).toBeDefined(); }); @@ -463,7 +495,7 @@ describe('FeedStore', () => { resolve(); })); - await feedStore.initialize(); + await feedStore.open(); const stream2 = feedStore.createReadStream(); eos(stream2, err => { @@ -488,7 +520,10 @@ describe('FeedStore', () => { }); test('Delete all', async () => { - expect(feedStore.getDescriptors().length).toBe(2); + const { feedStore } = await createDefault(); + await defaultFeeds(feedStore); + + expect(feedStore.getDescriptors().length).toBe(3); await feedStore.deleteAllDescriptors(); expect(feedStore.getDescriptors().length).toBe(0); });