Skip to content

Commit

Permalink
[RND-512] e2e Developer Mode (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
andonyns authored Apr 5, 2023
1 parent 92cd0fe commit 459c095
Show file tree
Hide file tree
Showing 15 changed files with 118 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@
"copyfiles": "^2.4.1",
"dotenv": "^16.0.3",
"rimraf": "^3.0.2",
"testcontainers": "^9.3.0"
"testcontainers": "^9.4.0"
}
}
41 changes: 18 additions & 23 deletions Meadowlark-js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Meadowlark-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
"test:e2e:debug": "cross-env DEBUG=testcontainers* npm run test:e2e:jest",
"test:e2e:build": "npm run docker:build && npm run test:e2e:jest",
"test:e2e:build:wsl1": "npm run docker:build:wsl1 && npm run test:e2e:jest",
"test:e2e:dev:setup": "cross-env TESTCONTAINERS_RYUK_DISABLED=true ts-node tests/e2e/setup/DevModeConfig.ts",
"test:e2e:dev:exit": "docker stop mongo-test opensearch-test meadowlark-api-test && docker rm -f mongo-test opensearch-test meadowlark-api-test && docker network prune -f",
"start:local": "lerna run start:local",
"docker:lint": "cat ./Dockerfile | docker run --rm -i hadolint/hadolint",
"docker:install": "npm i lerna@^6.0.2 rimraf@^3.0.2 copyfiles@^2.4.1 [email protected] -g && npm ci --only=production",
Expand Down
13 changes: 10 additions & 3 deletions Meadowlark-js/tests/e2e/helpers/Credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,18 @@ export async function createAutomationUsers(): Promise<void> {

export async function authenticateAdmin(): Promise<void> {
try {
if (!process.env.ADMIN_KEY && !process.env.ADMIN_SECRET) {
if (process.env.DEVELOPER_MODE && process.env.ADMIN_KEY && process.env.ADMIN_SECRET) {
await getAdminAccessToken();
} else {
const credentials = await createAdminClient();
if (!process.env.ADMIN_KEY && !process.env.ADMIN_SECRET) {
console.info(
'INFO ℹ️: Add the following values to the .env file. \nIf not saved, tests cannot be executed again until cleaning the environment',
);
console.info(`ADMIN_KEY=${credentials.key}`);
console.info(`ADMIN_SECRET=${credentials.secret}`);
}
setCredentials(credentials);
} else {
await getAdminAccessToken();
}
console.debug('-- Admin Authenticated --');
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion Meadowlark-js/tests/e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"fast-memoize": "^2.5.2",
"fs-extra": "^10.1.0",
"supertest": "^6.3.1",
"testcontainers": "^9.3.0"
"testcontainers": "^9.4.0"
},
"scripts": {
"build": "npm run build:clean && npm run build:copy-non-ts && npm run build:dist",
Expand Down
10 changes: 10 additions & 0 deletions Meadowlark-js/tests/e2e/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ To run the tests:

Postgresql support is currently disabled and should be included again once Postgresql support is matched on main code.

## Developer Mode

This is a special mode to use when adding new e2e tests or in situations where it is not necessary to use a clean environment.

- To setup, run: `npm run test:e2e:dev:setup`. This will configure the test containers
- Set the environment variable `DEVELOPER_MODE=true`
- Run `npm run test:e2e:jest` to run the tests. Save the Admin Key and Secret (as specified in [.env.example](./setup/.env.example)) to be able to run the tests
without cleaning the environment
- When done, run: `npm run test:e2e:dev:exit` to clean the environment

## Troubleshooting

`API Image not found`
Expand Down
9 changes: 8 additions & 1 deletion Meadowlark-js/tests/e2e/setup/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,11 @@ OAUTH_SIGNING_KEY={{OAUTH_SIGNING_KEY}}
# MONGODB_PASS={{MONGODB_PASS}}

# Meadowlark API docker image configuration
# API_IMAGE_NAME=edfialliance/meadowlark-ed-fi-api:pre
# API_IMAGE_NAME=edfialliance/meadowlark-ed-fi-api:pre

# Enable this flag to enter dev mode, the test images are not deleted until deleted with `npm run test:e2e:dev:exit:backend` and `npm run test:e2e:dev:exit:service`
# DEVELOPER_MODE=true

# When using dev mode, key and secret can only be generated once
# ADMIN_KEY={{KEY}}
# ADMIN_SECRET={{SECRET}}
7 changes: 7 additions & 0 deletions Meadowlark-js/tests/e2e/setup/DevModeConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const infrastructure = require('./EnvironmentConfig');

(async () => {
await infrastructure.configure();
})().catch((e) => {
console.error(`Error setting up dev mode: ${e.message} ${e.stack}`);
});
10 changes: 9 additions & 1 deletion Meadowlark-js/tests/e2e/setup/EnvironmentConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@ export async function configure() {
throw new Error(`\n${error}`);
}

await Promise.all([MongoContainer.setup(network), ApiContainer.setup(network), OpenSearchContainer.setup(network)]);
if (process.env.DEVELOPER_MODE) {
console.warn(
'⚠️ WARNING: Running in DEVELOPER MODE. Containers should be already be started, if not, setup with `test:e2e:dev:setup`⚠️',
);
} else {
process.env.ALREADY_SET = 'true';
console.info('-- Setting up containers --');
await Promise.all([MongoContainer.setup(network), ApiContainer.setup(network), OpenSearchContainer.setup(network)]);
}

console.debug('-- Environment Ready --');
}
7 changes: 4 additions & 3 deletions Meadowlark-js/tests/e2e/setup/Setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ module.exports = async () => {
console.debug('\n-- Configuring Environment --');
await setupEnvironment.configure();

process.env.ROOT_URL = `http://localhost:${process.env.FASTIFY_PORT ?? 3001}`;
process.env.DOCUMENT_STORE_PLUGIN = process.env.DOCUMENT_STORE_PLUGIN ?? '@edfi/meadowlark-mongodb-backend';
console.info(`\n🧪 Running e2e tests for ${process.env.ROOT_URL} with: ${process.env.DOCUMENT_STORE_PLUGIN} 🧪\n`);

console.debug('-- Authenticating Admin --');
await credentialManager.authenticateAdmin();

console.debug('-- Creating Automation Users --');
await credentialManager.createAutomationUsers();
console.timeEnd('Setup Time');

process.env.DOCUMENT_STORE_PLUGIN = process.env.DOCUMENT_STORE_PLUGIN ?? '@edfi/meadowlark-mongodb-backend';
console.info(`\n🧪 Running e2e tests for ${process.env.ROOT_URL} with: ${process.env.DOCUMENT_STORE_PLUGIN} 🧪\n`);
};
4 changes: 3 additions & 1 deletion Meadowlark-js/tests/e2e/setup/Teardown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const environment = require('./EnvironmentConfig');

async function endServer() {
try {
await environment.stop();
if (!process.env.DEVELOPER_MODE) {
await environment.stop();
}
} catch (error) {
console.info(error);
}
Expand Down
5 changes: 2 additions & 3 deletions Meadowlark-js/tests/e2e/setup/containers/ApiContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function setup(network: StartedNetwork) {

const fastifyPort = parseInt(process.env.FASTIFY_PORT ?? '3001', 10);

console.info(`Building API Image: ${process.env.API_IMAGE_NAME ?? 'meadowlark'}`);
console.info(`Configuring Meadowlark API with docker image: ${process.env.API_IMAGE_NAME ?? 'meadowlark'}`);

try {
container = new GenericContainer(process.env.API_IMAGE_NAME ?? 'meadowlark')
Expand All @@ -23,6 +23,7 @@ export async function setup(network: StartedNetwork) {
container: fastifyPort,
host: fastifyPort,
})
.withReuse()
.withEnvironment({
OAUTH_SIGNING_KEY: process.env.OAUTH_SIGNING_KEY ?? '',
OAUTH_HARD_CODED_CREDENTIALS_ENABLED: 'true',
Expand Down Expand Up @@ -57,8 +58,6 @@ export async function setup(network: StartedNetwork) {
throw new Error(`\nUnexpected error setting up API container:\n${error}`);
}
await setAPILog(startedContainer);

process.env.ROOT_URL = `http://localhost:${fastifyPort}`;
}

export async function stop(): Promise<void> {
Expand Down
8 changes: 5 additions & 3 deletions Meadowlark-js/tests/e2e/setup/containers/MongoContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ let startedContainer: StartedTestContainer;

export async function setup(network: StartedNetwork) {
try {
startedContainer = await new MongoDBContainer(
const container = new MongoDBContainer(
'mongo:4.0.28@sha256:f68f07e0c0ee86b1d848a30b27e5573e9c960748a02f7c288e28282297117644',
)
.withNetwork(network)
.withNetworkAliases('mongo-t1')
.withName('mongo-test')
.withReuse()
.withCommand([
'/usr/bin/mongod',
'--bind_ip_all',
Expand All @@ -24,8 +25,9 @@ export async function setup(network: StartedNetwork) {
'/data/db',
'--enableMajorityReadConcern',
'true',
])
.start();
]);

startedContainer = await container.start();
} catch (error) {
throw new Error(`\nUnexpected error setting up mongo container:\n${error}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ let startedContainer: StartedTestContainer;
export async function setup(network: StartedNetwork) {
try {
const openSearchPort = parseInt(process.env.OPENSEARCH_PORT ?? '8200', 10);
startedContainer = await new GenericContainer(
const container = new GenericContainer(
'opensearchproject/opensearch:2.5.0@sha256:f077efb452be64d3df56d74fe99fd63244704896edf6ead73a0f5decb95a40bf',
)
.withName('opensearch-test')
.withNetwork(network)
.withReuse()
.withExposedPorts({
container: openSearchPort,
host: openSearchPort,
Expand All @@ -26,8 +27,9 @@ export async function setup(network: StartedNetwork) {
DISABLE_SECURITY_PLUGIN: 'true',
'http.port': `${openSearchPort}`,
})
.withStartupTimeout(120_000)
.start();
.withStartupTimeout(120_000);

startedContainer = await container.start();
} catch (error) {
throw new Error(`\nUnexpected error setting up open search container:\n${error}`);
}
Expand Down
33 changes: 33 additions & 0 deletions docs/LOCALHOST.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,36 @@ delete from meadowlark.references;
delete from meadowlark.aliases;
delete from meadowlark.authorization;
```

## Running E2E Tests

### Setup

1. Create a .env file based on .env.example in this folder.
2. Verify that Docker is running

There are multiple ways of running e2e tests, depending on your scenario:

### Building local image

If you're adding new features to Meadowlark, and want to test the changes in an isolated environment, run `npm run test:e2e:build`.
This will build the Docker image and run the tests against that image, cleaning the environment afterwards.

### Using published image

If you want to run the tests against and existing Docker image, set the variable `API_IMAGE_NAME` in the .env file.
Run the tests with `npm run test:e2e:jest`.
This will pull the image and run the tests.

### Developer Mode

If you're adding new e2e tests or want to test in an environment without clearing the test images set the variable `DEVELOPER_MODE` to true in the .env file.
Run `test:e2e:dev:setup`, this will generate docker containers with the -test prefix that are used for testing.
Run the tests with `npm run test:e2e:jest`. Notice that you *could* use `npm run test:e2e:build` but the generated image will be ignored because the tests are already running.

> **Note**
>
> * This will use a locally built image or the image provided in the `API_IMAGE_NAME`.
> * This will generate an `ADMIN_KEY` and `ADMIN_SECRET` that can only be generated once, therefore, after the first run, this must be added to the .env variables.
>
> To exit this mode, run `test:e2e:dev:exit`. This will stop and delete the docker containers generated.

0 comments on commit 459c095

Please sign in to comment.