Skip to content

Commit

Permalink
Added TestContainers package with EventStoreDB Test Container
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed Mar 1, 2024
1 parent 897cac7 commit ac9a599
Show file tree
Hide file tree
Showing 13 changed files with 1,138 additions and 31 deletions.
925 changes: 904 additions & 21 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"workspaces": [
"packages/emmett",
"packages/emmett-esdb",
"packages/emmett-expressjs"
"packages/emmett-expressjs",
"packages/emmett-testcontainers"
]
}
2 changes: 1 addition & 1 deletion packages/emmett-esdb/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@event-driven-io/emmett-esdb",
"version": "0.3.0",
"description": "Emmett - Event Sourcing development made simple",
"description": "Emmett - EventStoreDB - Event Sourcing development made simple",
"scripts": {
"build": "tsup",
"build:ts": "tsc",
Expand Down
49 changes: 49 additions & 0 deletions packages/emmett-testcontainers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@event-driven-io/emmett-testcontainers",
"version": "0.3.0",
"description": "Emmett - TestContainers - Event Sourcing development made simple",
"scripts": {
"build": "tsup",
"build:ts": "tsc",
"build:ts:watch": "tsc --watch",
"lint": "npm run lint:eslint && npm run lint:prettier",
"lint:prettier": "prettier --check \"**/**/!(*.d).{ts,json,md}\"",
"lint:eslint": "eslint **/*.ts",
"fix": "run-s fix:eslint fix:prettier",
"fix:prettier": "prettier --write \"**/**/!(*.d).{ts,json,md}\"",
"fix:eslint": "eslint **/*.ts --fix",
"test": "run-s test:unit test:int test:e2e",
"test:unit": "glob -c \"node --import tsx --test\" **/*.unit.spec.ts",
"test:int": "glob -c \"node --import tsx --test\" **/*.int.spec.ts",
"test:e2e": "glob -c \"node --import tsx --test\" **/*.e2e.spec.ts",
"test:watch": "node --import tsx --test --watch",
"test:unit:watch": "glob -c \"node --import tsx --test --watch\" **/*.unit.spec.ts",
"test:int:watch": "glob -c \"node --import tsx --test --watch\" **/*.int.spec.ts",
"test:e2e:watch": "glob -c \"node --import tsx --test --watch\" **/*.e2e.spec.ts"
},
"repository": {
"type": "git",
"url": "git+https://github.com/event-driven-io/emmett.git"
},
"keywords": [
"Event Sourcing"
],
"author": "Oskar Dudycz",
"bugs": {
"url": "https://github.com/event-driven-io/emmett/issues"
},
"homepage": "https://event-driven-io.github.io/emmett/",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"dependencies": {
"@event-driven-io/emmett": "0.3.0",
"testcontainers": "^10.7.2"
},
"devDependencies": {
"@eventstore/db-client": "^6.1.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
import { jsonEvent } from '@eventstore/db-client';
import assert from 'node:assert/strict';
import { after, beforeEach, describe, it } from 'node:test';
import { v4 as uuid } from 'uuid';
import {
EventStoreDBContainer,
StartedEventStoreDBContainer,
} from './eventStoreDBContainer';

describe('EventStoreDBContainer', () => {
let container: StartedEventStoreDBContainer;

beforeEach(async () => {
container = await new EventStoreDBContainer().start();
});

it('should connect to EventStoreDB and append new event', async () => {
const client = container.getClient();

const result = await client.appendToStream(
`test-${uuid()}`,
jsonEvent({ type: 'test-event', data: { test: 'test' } }),
);

assert.ok(result.success);
});

after(async () => {
await container.stop();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { EventStoreDBClient } from '@eventstore/db-client';
import {
AbstractStartedContainer,
GenericContainer,
type StartedTestContainer,
} from 'testcontainers';
import type { Environment } from 'testcontainers/build/types';

const EVENTSTOREDB_PORT = 2113;
const EVENTSTOREDB_TCP_PORT = 1113;
const EVENTSTOREDB_TCP_PORTS = [EVENTSTOREDB_TCP_PORT, EVENTSTOREDB_PORT];
const EVENTSTOREDB_IMAGE_NAME = 'eventstore/eventstore';
const EVENTSTOREDB_IMAGE_TAG = '23.10.1-bookworm-slim';

export class EventStoreDBContainer extends GenericContainer {
private readonly tcpPorts = EVENTSTOREDB_TCP_PORTS;

constructor(
image = `${EVENTSTOREDB_IMAGE_NAME}:${EVENTSTOREDB_IMAGE_TAG}`,
runProjections = true,
isInsecure = true,
emptyDatabase = true,
withoutReuse = false,
) {
super(image);

const environment: Environment = {
...(runProjections
? {
EVENTSTORE_RUN_PROJECTIONS: 'ALL',
}
: {}),
...(isInsecure
? {
EVENTSTORE_INSECURE: 'true',
}
: {}),
...(!emptyDatabase
? {
EVENTSTORE_MEM_DB: 'false',
EVENTSTORE_DB: '/data/integration-tests',
}
: {}),
EVENTSTORE_CLUSTER_SIZE: '1',
EVENTSTORE_START_STANDARD_PROJECTIONS: 'true',
EVENTSTORE_EXT_TCP_PORT: `${EVENTSTOREDB_TCP_PORT}`,
EVENTSTORE_HTTP_PORT: `${EVENTSTOREDB_PORT}`,
EVENTSTORE_ENABLE_EXTERNAL_TCP: 'true',
EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP: 'true',
};

this.withEnvironment(environment).withExposedPorts(...this.tcpPorts);

if (!withoutReuse) this.withReuse();
}

async start(): Promise<StartedEventStoreDBContainer> {
return new StartedEventStoreDBContainer(await super.start());
}
}

export class StartedEventStoreDBContainer extends AbstractStartedContainer {
constructor(container: StartedTestContainer) {
super(container);
}

getConnectionString(): string {
return `esdb://${this.getHost()}:${this.getMappedPort(
2113,
)}?tls=false&throwOnAppendFailure=false`;
}

getClient(): EventStoreDBClient {
return EventStoreDBClient.connectionString(this.getConnectionString());
}
}
27 changes: 27 additions & 0 deletions packages/emmett-testcontainers/src/eventStore/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { EventStoreDBClient } from '@eventstore/db-client';
import {
EventStoreDBContainer,
StartedEventStoreDBContainer,
} from './eventStoreDBContainer';

let esdbContainer: StartedEventStoreDBContainer;

export const getEventStoreDBTestClient = async (
useTestContainers = false,
): Promise<EventStoreDBClient> => {
let connectionString;

if (useTestContainers) {
if (!esdbContainer)
esdbContainer = await new EventStoreDBContainer().start();

connectionString = esdbContainer.getConnectionString();
} else {
// await compose.upAll();
connectionString = 'esdb://localhost:2113?tls=false';
}

// That's how EventStoreDB client is setup
// We're taking the connection string from container
return EventStoreDBClient.connectionString(connectionString);
};
1 change: 1 addition & 0 deletions packages/emmett-testcontainers/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './eventStore';
6 changes: 6 additions & 0 deletions packages/emmett-testcontainers/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"composite": false
}
}
17 changes: 17 additions & 0 deletions packages/emmett-testcontainers/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.shared.json",
"include": ["./src/**/*"],
"compilerOptions": {
"composite": true,
"outDir": "./dist" /* Redirect output structure to the directory. */,
"rootDir": "./src",
"paths": {
"@event-driven-io/emmett": ["../packages/emmett"]
}
},
"references": [
{
"path": "../emmett/"
}
]
}
20 changes: 20 additions & 0 deletions packages/emmett-testcontainers/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { defineConfig } from 'tsup';

const env = process.env.NODE_ENV;

export default defineConfig({
splitting: true,
clean: true, // clean up the dist folder
dts: true, // generate dts files
format: ['cjs', 'esm'], // generate cjs and esm files
minify: env === 'production',
bundle: env === 'production',
skipNodeModulesBundle: true,
entryPoints: ['src/index.ts'],
watch: env === 'development',
target: 'esnext',
outDir: 'dist', //env === 'production' ? 'dist' : 'lib',
entry: ['src/**/*.ts'], //include all files under src
sourcemap: true,
tsconfig: 'tsconfig.build.json', // workaround for https://github.com/egoist/tsup/issues/571#issuecomment-1760052931
});
8 changes: 0 additions & 8 deletions packages/emmett/src/testing/placeholder.e2e.spec.ts

This file was deleted.

3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
},
{
"path": "./packages/emmett-expressjs/"
},
{
"path": "./packages/emmett-testcontainers/"
}
]
}

0 comments on commit ac9a599

Please sign in to comment.