From 437d0f9021eee97aa4e9ed4706446aa6616d1889 Mon Sep 17 00:00:00 2001 From: gonzalojaubert Date: Fri, 28 Jul 2023 15:15:04 +0100 Subject: [PATCH] fix integration tests and load async --- common/config/rush/pnpm-lock.yaml | 2 ++ .../provider-specific/local/start/setup.ts | 2 +- .../framework-integration-tests/package.json | 5 +-- .../src/common/my-logger.ts | 31 +++++++++++++++++++ .../src/config/config.ts | 1 + .../src/services/event-registry.ts | 17 ++++++++-- .../src/services/read-model-registry.ts | 18 +++++++++-- .../src/services/web-socket-registry.ts | 21 ++++++++++--- 8 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 packages/framework-integration-tests/src/common/my-logger.ts diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 6022569e3..027efe875 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -391,6 +391,7 @@ importers: eslint-plugin-import: ^2.26.0 eslint-plugin-prettier: 3.4.0 eslint-plugin-unicorn: ~44.0.2 + express: ^4.17.1 express-unless: 2.1.3 faker: 5.1.0 graphology-types: ^0.24.0 @@ -423,6 +424,7 @@ importers: '@boostercloud/framework-types': link:../framework-types '@effect-ts/core': 0.60.5 aws-sdk: 2.853.0 + express: 4.18.2 express-unless: 2.1.3 graphql: 16.6.0 tslib: 2.5.0 diff --git a/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts b/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts index d737347ad..e39fba167 100644 --- a/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts +++ b/packages/framework-integration-tests/integration/provider-specific/local/start/setup.ts @@ -27,6 +27,6 @@ before(async () => { throw new Error('Pid not found') } storePIDFor(sandboxPath, serverProcess.pid) //store pid to kill process on stop - await sleep(2000) + await sleep(10000) console.log('local server ready') }) diff --git a/packages/framework-integration-tests/package.json b/packages/framework-integration-tests/package.json index 073561434..a121f4e79 100644 --- a/packages/framework-integration-tests/package.json +++ b/packages/framework-integration-tests/package.json @@ -19,7 +19,8 @@ "graphql": "^16.6.0", "tslib": "^2.4.0", "@effect-ts/core": "^0.60.4", - "express-unless": "2.1.3" + "express-unless": "2.1.3", + "express": "^4.17.1" }, "devDependencies": { "@boostercloud/eslint-config": "workspace:^2.2.0", @@ -102,7 +103,7 @@ "integration/aws-nuke": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" AWS_SDK_LOAD_CONFIG=true BOOSTER_ENV=production mocha --forbid-only --exit --config \"integration/provider-specific/aws/nuke/.mocharc.yml\" \"integration/provider-specific/aws/nuke/**/*.integration.ts\"", "integration/local": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" npm run integration/local-start && npm run integration/local-end-to-end && npm run integration/local-stop", "integration/local-ongoing": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" npm run integration/local-start && npm run integration/local-stop", - "integration/local-start": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --config \"integration/provider-specific/local/start/.mocharc.yml\" \"integration/provider-specific/local/start/*.integration.ts\"", + "integration/local-start": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/start/.mocharc.yml\" \"integration/provider-specific/local/start/*.integration.ts\"", "integration/local-func": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=LOCAL BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-unaware/functionality/.mocharc.yml\" \"integration/provider-unaware/functionality/**/*.integration.ts\"", "integration/local-end-to-end": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" TESTED_PROVIDER=LOCAL BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-unaware/end-to-end/.mocharc.yml\" \"integration/provider-unaware/end-to-end/**/*.integration.ts\"", "integration/local-stop": "TS_NODE_PROJECT=\"./tsconfig.integration.json\" BOOSTER_ENV=local mocha --forbid-only --exit --config \"integration/provider-specific/local/stop/.mocharc.yml\" \"integration/provider-specific/local/stop/*.integration.ts\"", diff --git a/packages/framework-integration-tests/src/common/my-logger.ts b/packages/framework-integration-tests/src/common/my-logger.ts new file mode 100644 index 000000000..6e2bc7874 --- /dev/null +++ b/packages/framework-integration-tests/src/common/my-logger.ts @@ -0,0 +1,31 @@ +import { Logger } from '@boostercloud/framework-types' + +export class MyLogger implements Logger { + debug(message?: any, ...optionalParams: any[]): void { + console.log(`[DEBUG] ${message?.toString()}`) + optionalParams.forEach((param) => { + console.log(`[DEBUG] ${param?.toString()}`) + }) + } + + info(message?: any, ...optionalParams: any[]): void { + console.log(`[INFO] ${message?.toString()}`) + optionalParams.forEach((param) => { + console.log(`[INFO] ${param?.toString()}`) + }) + } + + warn(message?: any, ...optionalParams: any[]): void { + console.log(`[WARN] ${message?.toString()}`) + optionalParams.forEach((param) => { + console.log(`[WARN] ${param?.toString()}`) + }) + } + + error(message?: any, ...optionalParams: any[]): void { + console.log(`[ERROR] ${message?.toString()}`) + optionalParams.forEach((param) => { + console.log(`[ERROR] ${param?.toString()}`) + }) + } +} diff --git a/packages/framework-integration-tests/src/config/config.ts b/packages/framework-integration-tests/src/config/config.ts index 69f1aa1af..6ec983654 100644 --- a/packages/framework-integration-tests/src/config/config.ts +++ b/packages/framework-integration-tests/src/config/config.ts @@ -45,6 +45,7 @@ function configureEventHub(config: BoosterConfig) { Booster.configure('local', (config: BoosterConfig): void => { config.appName = 'my-store' config.providerPackage = '@boostercloud/framework-provider-local' + config.logger = new MyLogger() config.tokenVerifiers = [ new PublicKeyTokenVerifier( 'booster', diff --git a/packages/framework-provider-local/src/services/event-registry.ts b/packages/framework-provider-local/src/services/event-registry.ts index 700198653..0a3f9f3e9 100644 --- a/packages/framework-provider-local/src/services/event-registry.ts +++ b/packages/framework-provider-local/src/services/event-registry.ts @@ -4,10 +4,18 @@ import { eventsDatabase } from '../paths' const DataStore = require('@seald-io/nedb') export class EventRegistry { - private readonly events + public readonly events + public isLoaded = false constructor() { - this.events = new DataStore({ filename: eventsDatabase, autoload: true }) + this.events = new DataStore({ filename: eventsDatabase }) + } + + async loadDatabaseIfNeeded(): Promise { + if (!this.isLoaded) { + this.isLoaded = true + await this.events.loadDatabaseAsync() + } } getCursor(query: object, createdAt = 1, projections?: unknown) { @@ -21,6 +29,7 @@ export class EventRegistry { limit?: number, projections?: unknown ): Promise { + await this.loadDatabaseIfNeeded() let cursor = this.getCursor(query, createdAt, projections) if (limit) { cursor = cursor.limit(Number(limit)) @@ -29,6 +38,7 @@ export class EventRegistry { } public async queryLatestSnapshot(query: object): Promise { + await this.loadDatabaseIfNeeded() const cursor = this.events.findAsync({ ...query, kind: 'snapshot' }).sort({ snapshottedEventCreatedAt: -1 }) // Sort in descending order (newer timestamps first) const results = await cursor.execAsync() if (results.length <= 0) { @@ -38,14 +48,17 @@ export class EventRegistry { } public async store(storableObject: EventEnvelope | EntitySnapshotEnvelope): Promise { + await this.loadDatabaseIfNeeded() await this.events.insertAsync(storableObject) } public async deleteAll(): Promise { + await this.loadDatabaseIfNeeded() return await this.events.removeAsync({}, { multi: true }) } public async count(query?: object): Promise { + await this.loadDatabaseIfNeeded() return await this.events.countAsync(query) } } diff --git a/packages/framework-provider-local/src/services/read-model-registry.ts b/packages/framework-provider-local/src/services/read-model-registry.ts index c950f7d99..3da531d1d 100644 --- a/packages/framework-provider-local/src/services/read-model-registry.ts +++ b/packages/framework-provider-local/src/services/read-model-registry.ts @@ -12,9 +12,18 @@ export const UNIQUE_VIOLATED_ERROR_TYPE = 'uniqueViolated' export class ReadModelRegistry { public readonly readModels + public isLoaded = false + constructor() { - this.readModels = new DataStore({ filename: readModelsDatabase, autoload: true }) - this.readModels.ensureIndex({ fieldName: 'uniqueKey', unique: true, sparse: true }) + this.readModels = new DataStore({ filename: readModelsDatabase }) + } + + async loadDatabaseIfNeeded(): Promise { + if (!this.isLoaded) { + this.isLoaded = true + await this.readModels.loadDatabaseAsync() + await this.readModels.ensureIndexAsync({ fieldName: 'uniqueKey', unique: true, sparse: true }) + } } public async query( @@ -23,6 +32,7 @@ export class ReadModelRegistry { skip?: number, limit?: number ): Promise> { + await this.loadDatabaseIfNeeded() let cursor = this.readModels.findAsync(query) const sortByList = this.toLocalSortFor(sortBy) if (sortByList) { @@ -38,6 +48,7 @@ export class ReadModelRegistry { } public async store(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise { + await this.loadDatabaseIfNeeded() const uniqueReadModel: ReadModelEnvelope & { uniqueKey?: string } = readModel uniqueReadModel.uniqueKey = `${readModel.typeName}_${readModel.value.id}_${readModel.value.boosterMetadata?.version}` if (uniqueReadModel.value.boosterMetadata?.version === 1) { @@ -47,10 +58,12 @@ export class ReadModelRegistry { } private async insert(readModel: ReadModelEnvelope): Promise { + await this.loadDatabaseIfNeeded() await this.readModels.insertAsync(readModel) } private async update(readModel: ReadModelEnvelope, expectedCurrentVersion: number): Promise { + await this.loadDatabaseIfNeeded() const { numAffected } = await this.readModels.updateAsync( { typeName: readModel.typeName, @@ -72,6 +85,7 @@ export class ReadModelRegistry { } public async deleteById(id: UUID, typeName: string): Promise { + await this.loadDatabaseIfNeeded() return await this.readModels.removeAsync({ typeName: typeName, 'value.id': id }, { multi: false }) } diff --git a/packages/framework-provider-local/src/services/web-socket-registry.ts b/packages/framework-provider-local/src/services/web-socket-registry.ts index 811cd93fe..826452cc8 100644 --- a/packages/framework-provider-local/src/services/web-socket-registry.ts +++ b/packages/framework-provider-local/src/services/web-socket-registry.ts @@ -10,15 +10,23 @@ export type SimpleRegistryTypes = ConnectionData | SubscriptionEnvelope export class WebSocketRegistry { public datastore + public isLoaded = false constructor(connectionsDatabase: string) { - this.datastore = new DataStore({ filename: connectionsDatabase, autoload: true }) - this.addIndexes() + this.datastore = new DataStore({ filename: connectionsDatabase }) } - addIndexes(): void { + async loadDatabaseIfNeeded(): Promise { + if (!this.isLoaded) { + this.isLoaded = true + await this.datastore.loadDatabaseAsync() + await this.addIndexes() + } + } + + async addIndexes(): Promise { const maxDurationInSeconds = 2 * 24 * 60 * 60 // 2 days - this.datastore.ensureIndex({ fieldName: 'expirationTime', expireAfterSeconds: maxDurationInSeconds }) + this.datastore.ensureIndexAsync({ fieldName: 'expirationTime', expireAfterSeconds: maxDurationInSeconds }) } getCursor(query: object, createdAt = 1, projections?: unknown) { @@ -26,6 +34,7 @@ export class WebSocketRegistry { } public async query(query: object, createdAt = 1, limit?: number, projections?: unknown): Promise { + await this.loadDatabaseIfNeeded() let cursor = this.getCursor(query, createdAt, projections) if (limit) { cursor = cursor.limit(Number(limit)) @@ -34,18 +43,22 @@ export class WebSocketRegistry { } public async store(envelope: SimpleRegistryTypes): Promise { + await this.loadDatabaseIfNeeded() await this.datastore.insertAsync(envelope) } public async delete(query: unknown): Promise { + await this.loadDatabaseIfNeeded() return await this.datastore.removeAsync(query, { multi: true }) } public async deleteAll(): Promise { + await this.loadDatabaseIfNeeded() return await this.datastore.removeAsync({}, { multi: true }) } public async count(query?: object): Promise { + await this.loadDatabaseIfNeeded() return await this.datastore.countAsync(query) } }