diff --git a/src/config.ts b/src/config.ts index de3c5ba..389dd3a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -56,6 +56,7 @@ export const config = { messageStore: process.env.DWN_STORAGE_MESSAGES || process.env.DWN_STORAGE || 'level://data', dataStore: process.env.DWN_STORAGE_DATA || process.env.DWN_STORAGE || 'level://data', eventLog: process.env.DWN_STORAGE_EVENTS || process.env.DWN_STORAGE || 'level://data', + resumableTaskStore: process.env.DWN_STORAGE_RESUMABLE_TASKS || process.env.DWN_STORAGE || 'level://data', // tenant registration feature configuration registrationStoreUrl: process.env.DWN_REGISTRATION_STORE_URL || process.env.DWN_STORAGE, diff --git a/src/storage.ts b/src/storage.ts index 8c7b50c..087797c 100644 --- a/src/storage.ts +++ b/src/storage.ts @@ -62,7 +62,7 @@ export async function getDwnConfig( const dataStore: DataStore = await getStore(config.dataStore, StoreType.DataStore); const eventLog: EventLog = await getStore(config.eventLog, StoreType.EventLog); const messageStore: MessageStore = await getStore(config.messageStore, StoreType.MessageStore); - const resumableTaskStore: ResumableTaskStore = await getStore(config.messageStore, StoreType.ResumableTaskStore); + const resumableTaskStore: ResumableTaskStore = await getStore(config.resumableTaskStore, StoreType.ResumableTaskStore); return { didResolver, eventStream, eventLog, dataStore, messageStore, resumableTaskStore, tenantGate }; } diff --git a/tests/plugins/resumable-task-store-sqlite.ts b/tests/plugins/resumable-task-store-sqlite.ts new file mode 100644 index 0000000..474e8a7 --- /dev/null +++ b/tests/plugins/resumable-task-store-sqlite.ts @@ -0,0 +1,26 @@ +import type { ResumableTaskStore } from "@tbd54566975/dwn-sdk-js"; +import { ResumableTaskStoreSql } from "@tbd54566975/dwn-sql-store"; +import { getDialectFromUrl } from "../../src/storage.js"; + +/** + * An example of a plugin that is used for testing. + * The points to note are: + * - The class must be a default export. + * - The constructor must not take any arguments. + */ +export default class ResumableTaskStoreSqlite extends ResumableTaskStoreSql implements ResumableTaskStore { + constructor() { + const sqliteDialect = getDialectFromUrl(new URL('sqlite://')); + super(sqliteDialect); + + // NOTE: the following line is added purely to test the constructor invocation. + ResumableTaskStoreSqlite.spyingTheConstructor(); + } + + /** + * NOTE: This method is introduced purely to indirectly test/spy invocation of the constructor. + * As I was unable to find an easy way to directly spy the constructor. + */ + public static spyingTheConstructor(): void { + } +} \ No newline at end of file diff --git a/tests/scenarios/dynamic-plugin-loading.spec.ts b/tests/scenarios/dynamic-plugin-loading.spec.ts index 84ac281..6bdbb36 100644 --- a/tests/scenarios/dynamic-plugin-loading.spec.ts +++ b/tests/scenarios/dynamic-plugin-loading.spec.ts @@ -10,6 +10,8 @@ import { DwnServer } from '../../src/dwn-server.js'; import { DidDht, DidKey, UniversalResolver } from '@web5/dids'; import CommonScenarioValidator from '../common-scenario-validator.js'; +import MessageStoreSqlite from '../plugins/message-store-sqlite.js'; +import ResumableTaskStoreSqlite from '../plugins/resumable-task-store-sqlite.js'; // node.js 18 and earlier needs globalThis.crypto polyfill if (!globalThis.crypto) { @@ -23,7 +25,6 @@ describe('Dynamic DWN plugin loading', function () { let dwnServer: DwnServer; afterEach(async () => { - // clock.restore(); if (dwnServer !== undefined) { await dwnServer.stop(); } @@ -44,7 +45,9 @@ describe('Dynamic DWN plugin loading', function () { // 3. Validate that the DWN instance is using the custom data store plugin. // NOTE: was not able to spy on constructor directly, so spying on a method that is called in the constructor + const customMessageStoreConstructorSpy = sinon.spy(MessageStoreSqlite, 'spyingTheConstructor'); const customDataStoreConstructorSpy = sinon.spy(DataStoreSqlite, 'spyingTheConstructor'); + const customResumableTaskStoreConstructorSpy = sinon.spy(ResumableTaskStoreSqlite, 'spyingTheConstructor'); const customEventLogConstructorSpy = sinon.spy(EventLogSqlite, 'spyingTheConstructor'); const customEventStreamConstructorSpy = sinon.spy(EventStreamInMemory, 'spyingTheConstructor'); @@ -55,9 +58,9 @@ describe('Dynamic DWN plugin loading', function () { // The default config is not reliable because other tests modify it. dwnServerConfigCopy.registrationStoreUrl = undefined; // allow all traffic - // dwnServerConfigCopy.messageStore = '../tests/plugins/message-store-sqlite.js'; // not working - dwnServerConfigCopy.messageStore = 'sqlite://'; + dwnServerConfigCopy.messageStore = '../tests/plugins/message-store-sqlite.js'; dwnServerConfigCopy.dataStore = '../tests/plugins/data-store-sqlite.js'; + dwnServerConfigCopy.resumableTaskStore = '../tests/plugins/resumable-task-store-sqlite.js'; dwnServerConfigCopy.eventLog = '../tests/plugins/event-log-sqlite.js'; dwnServerConfigCopy.eventStreamPluginPath = '../tests/plugins/event-stream-in-memory.js'; @@ -72,7 +75,9 @@ describe('Dynamic DWN plugin loading', function () { }); dwnServer = new DwnServer({ config: dwnServerConfigCopy, didResolver }); await dwnServer.start(); + expect(customMessageStoreConstructorSpy.calledOnce).to.be.true; expect(customDataStoreConstructorSpy.calledOnce).to.be.true; + expect(customResumableTaskStoreConstructorSpy.calledOnce).to.be.true; expect(customEventLogConstructorSpy.calledOnce).to.be.true; expect(customEventStreamConstructorSpy.calledOnce).to.be.true; diff --git a/tests/scenarios/registration.spec.ts b/tests/scenarios/registration.spec.ts index 987a3c9..aa8e032 100644 --- a/tests/scenarios/registration.spec.ts +++ b/tests/scenarios/registration.spec.ts @@ -50,6 +50,7 @@ describe('Registration scenarios', function () { // and dwn-server.spec.ts already uses LevelDB. dwnServerConfig.messageStore = 'sqlite://', dwnServerConfig.dataStore = 'sqlite://', + dwnServerConfig.resumableTaskStore = 'sqlite://', dwnServerConfig.eventLog = 'sqlite://', // registration config