Skip to content

Commit 3e7cd24

Browse files
authored
Refactored tests to be independent of store implementation (#420)
* Refactored tests to be independent of store implementation * Updated CONTRIBUTING.md
1 parent 222c78f commit 3e7cd24

22 files changed

+572
-520
lines changed

CONTRIBUTING.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ We suggest the following process when picking up one of these issues:
3939
* Running the `npm run test:browser` command from the root of the project will run the tests in browser environments.
4040
* Please make sure there are no failing tests before switching your PR to ready for review! This validation is automated when you open a new pull request.
4141

42+
### Developing and testing custom store implementations
43+
Here is a guide on how to develop and test a custom implementation of the data store:
44+
45+
> Please note that we aim to improve the experience over time, such as exporting the interface definitions as their own module.
46+
47+
1. Fork the repository.
48+
1. Implement one or a combination of the `DataStore`, `MessageStore`, and `EventLog` interfaces.
49+
1. Override the store initialization logic in the `TestStoreInitializer` class.
50+
1. Run the tests as you would normally to ensure the functionality and correctness of your custom implementation.
51+
4252
### Running benchmarks
4353

4454
Benchmarks should be run directly using `node` (e.g. `node benchmarks/store/index/search-index.js`).

package-lock.json

Lines changed: 98 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
"rimraf": "3.0.2",
134134
"search-index": "3.4.0",
135135
"sinon": "13.0.1",
136+
"ts-sinon": "^2.0.2",
136137
"typescript": "4.8.2",
137138
"util": "0.12.4"
138139
},
@@ -161,4 +162,4 @@
161162
"license-check": "license-report --only=prod > license-report.json && node ./build/license-check.cjs",
162163
"publish:unstable": "./build/publish-unstable.sh"
163164
}
164-
}
165+
}

src/types/data-store.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export interface DataStore {
4545
* @param messageCid CID of the message that references the data.
4646
*/
4747
delete(tenant: string, messageCid: string, dataCid: string): Promise<void>;
48+
49+
/**
50+
* Clears the entire store. Mainly used for cleaning up in test environment.
51+
*/
52+
clear(): Promise<void>;
4853
}
4954

5055
/**

src/types/event-log.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ export interface EventLog {
3030
/**
3131
* retrieves all of a tenant's events that occurred after the watermark provided.
3232
* If no watermark is provided, all events for a given tenant will be returned.
33-
*
34-
* @param tenant
35-
* @param watermark
3633
*/
3734
getEvents(tenant: string, options?: GetEventsOptions): Promise<Array<Event>>
3835

3936
/**
4037
* deletes any events that have any of the cids provided
41-
* @param tenant
42-
* @param cids
4338
* @returns {Promise<number>} the number of events deleted
4439
*/
4540
deleteEventsByCid(tenant: string, cids: Array<string>): Promise<number>
41+
42+
/**
43+
* Clears the entire store. Mainly used for cleaning up in test environment.
44+
*/
45+
clear(): Promise<void>;
4646
}

src/types/message-store.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,9 @@ export interface MessageStore {
4141
* Deletes the message associated with the id provided.
4242
*/
4343
delete(tenant: string, cid: string, options?: MessageStoreOptions): Promise<void>;
44+
45+
/**
46+
* Clears the entire store. Mainly used for cleaning up in test environment.
47+
*/
48+
clear(): Promise<void>;
4449
}

tests/dwn.spec.ts

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,34 @@
1+
import type { DataStore, EventLog, MessageStore } from '../src/index.js';
12
import type { EventsGetReply, RecordsWriteMessage, TenantGate } from '../src/index.js';
23

34
import chaiAsPromised from 'chai-as-promised';
45
import sinon from 'sinon';
56
import chai, { expect } from 'chai';
67

7-
import { DataStoreLevel } from '../src/store/data-store-level.js';
88
import { DidKeyResolver } from '../src/did/did-key-resolver.js';
99
import { Dwn } from '../src/dwn.js';
1010
import { Encoder } from '../src/index.js';
11-
import { EventLogLevel } from '../src/event-log/event-log-level.js';
12-
import { MessageStoreLevel } from '../src/store/message-store-level.js';
11+
import { stubInterface } from 'ts-sinon';
1312
import { TestDataGenerator } from './utils/test-data-generator.js';
13+
import { TestStoreInitializer } from './test-store-initializer.js';
1414
import { DwnInterfaceName, DwnMethodName, Message } from '../src/core/message.js';
1515
import { Jws, RecordsRead } from '../src/index.js';
1616

1717
chai.use(chaiAsPromised);
1818

1919
describe('DWN', () => {
20-
let messageStore: MessageStoreLevel;
21-
let dataStore: DataStoreLevel;
22-
let eventLog: EventLogLevel;
20+
let messageStore: MessageStore;
21+
let dataStore: DataStore;
22+
let eventLog: EventLog;
2323
let dwn: Dwn;
2424

25+
// important to follow the `before` and `after` pattern to initialize and clean the stores in tests
26+
// so that different test suites can reuse the same backend store for testing
2527
before(async () => {
26-
// important to follow this pattern to initialize the message store in tests
27-
// so that different suites can reuse the same block store and index location for testing
28-
messageStore = new MessageStoreLevel({
29-
blockstoreLocation : 'TEST-MESSAGESTORE',
30-
indexLocation : 'TEST-INDEX'
31-
});
32-
33-
dataStore = new DataStoreLevel({
34-
blockstoreLocation: 'TEST-DATASTORE'
35-
});
36-
37-
eventLog = new EventLogLevel({
38-
location: 'TEST-EVENTLOG'
39-
});
28+
const stores = TestStoreInitializer.initializeStores();
29+
messageStore = stores.messageStore;
30+
dataStore = stores.dataStore;
31+
eventLog = stores.eventLog;
4032

4133
dwn = await Dwn.create({ messageStore, dataStore, eventLog });
4234
});
@@ -144,9 +136,9 @@ describe('DWN', () => {
144136
}
145137
};
146138

147-
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
148-
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
149-
const eventLogStub = sinon.createStubInstance(EventLogLevel);
139+
const messageStoreStub = stubInterface<MessageStore>();
140+
const dataStoreStub = stubInterface<DataStore>();
141+
const eventLogStub = stubInterface<EventLog>();
150142

151143
const dwnWithConfig = await Dwn.create({
152144
tenantGate : blockAllTenantGate,
@@ -285,9 +277,9 @@ describe('DWN', () => {
285277
}
286278
};
287279

288-
const messageStoreStub = sinon.createStubInstance(MessageStoreLevel);
289-
const dataStoreStub = sinon.createStubInstance(DataStoreLevel);
290-
const eventLogStub = sinon.createStubInstance(EventLogLevel);
280+
const messageStoreStub = stubInterface<MessageStore>();
281+
const dataStoreStub = stubInterface<DataStore>();
282+
const eventLogStub = stubInterface<EventLog>();
291283

292284
const dwnWithConfig = await Dwn.create({
293285
tenantGate : blockAllTenantGate,

tests/handlers/events-get.spec.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,37 @@
1-
import type { EventsGetReply } from '../../src/index.js';
1+
import type {
2+
DataStore,
3+
EventLog,
4+
EventsGetReply,
5+
MessageStore
6+
} from '../../src/index.js';
27

38
import { expect } from 'chai';
49
import { TestDataGenerator } from '../utils/test-data-generator.js';
510
import {
6-
DataStoreLevel,
711
DidKeyResolver,
812
DidResolver,
9-
Dwn,
10-
EventLogLevel,
11-
MessageStoreLevel,
13+
Dwn
1214
} from '../../src/index.js';
1315

1416
import { Message } from '../../src/core/message.js';
17+
import { TestStoreInitializer } from '../test-store-initializer.js';
1518

1619
describe('EventsGetHandler.handle()', () => {
1720
let didResolver: DidResolver;
18-
let messageStore: MessageStoreLevel;
19-
let dataStore: DataStoreLevel;
20-
let eventLog: EventLogLevel;
21+
let messageStore: MessageStore;
22+
let dataStore: DataStore;
23+
let eventLog: EventLog;
2124
let dwn: Dwn;
2225

26+
// important to follow the `before` and `after` pattern to initialize and clean the stores in tests
27+
// so that different test suites can reuse the same backend store for testing
2328
before(async () => {
2429
didResolver = new DidResolver([new DidKeyResolver()]);
2530

26-
// important to follow this pattern to initialize and clean the message and data store in tests
27-
// so that different suites can reuse the same block store and index location for testing
28-
messageStore = new MessageStoreLevel({
29-
blockstoreLocation : 'TEST-MESSAGESTORE',
30-
indexLocation : 'TEST-INDEX'
31-
});
32-
33-
dataStore = new DataStoreLevel({
34-
blockstoreLocation: 'TEST-DATASTORE'
35-
});
36-
37-
eventLog = new EventLogLevel({
38-
location: 'TEST-EVENTLOG'
39-
});
31+
const stores = TestStoreInitializer.initializeStores();
32+
messageStore = stores.messageStore;
33+
dataStore = stores.dataStore;
34+
eventLog = stores.eventLog;
4035

4136
dwn = await Dwn.create({ didResolver, messageStore, dataStore, eventLog });
4237
});

0 commit comments

Comments
 (0)