Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
754 changes: 545 additions & 209 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"build": "npm run clean && tsc -b src",
"format": "prettier -w .",
"release": "release-it --only-version",
"test": "TS_NODE_PROJECT=tests node --test --test-concurrency=2 -r ts-node/register tests/**/index.test.ts",
"test": "tsx --tsconfig tests/tsconfig.json tests/run.ts",
"test:build": "npm run build && tstyche build",
"prepare": "husky"
},
Expand Down Expand Up @@ -74,9 +74,8 @@
"pathe": "^2.0.3",
"prettier": "^3.4.2",
"release-it": "^18.1.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"tstyche": "^4.0.0-beta.9",
"tsx": "^4.21.0",
"typescript": "^5.7.3",
"undici": "^6.21.2"
},
Expand Down
3 changes: 2 additions & 1 deletion tests/cloudfront/infrastructure/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as aws from '@pulumi/aws-v7';
import * as pulumi from '@pulumi/pulumi';
import { next as studion } from '@studion/infra-code-blocks';
import * as util from '../../util';
import * as config from './config';
import { OriginFactory } from './origin-factory';

Expand All @@ -15,7 +16,7 @@ const parent = new pulumi.ComponentResource(
'studion:cf:TestGroup',
`${config.appName}-root`,
);
const vpc = new studion.Vpc(`${config.appName}-vpc`, {}, { parent });
const vpc = util.getCommonVpc();
const hostedZone = aws.route53.getZoneOutput({
zoneId: hostedZoneId,
});
Expand Down
3 changes: 2 additions & 1 deletion tests/database/infrastructure/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import * as aws from '@pulumi/aws-v7';
import * as config from './config';
import * as pulumi from '@pulumi/pulumi';
import { next as studion } from '@studion/infra-code-blocks';
import * as util from '../../util';

const parent = new pulumi.ComponentResource(
'studion:database:TestGroup',
`${config.appName}-root`,
);

const vpc = new studion.Vpc(`${config.appName}-vpc`, {}, { parent });
const vpc = util.getCommonVpc();

const defaultDb = new studion.DatabaseBuilder(`${config.appName}-default-db`)
.withInstance({
Expand Down
3 changes: 2 additions & 1 deletion tests/ecs-service/infrastructure/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as aws from '@pulumi/aws-v7';
import * as pulumi from '@pulumi/pulumi';
import { next as studion } from '@studion/infra-code-blocks';
import * as util from '../../util';

const appName = 'ecs-test';
const stackName = pulumi.getStack();
Expand All @@ -20,7 +21,7 @@ const parent = new pulumi.ComponentResource(
`${appName}-root`,
);

const vpc = new studion.Vpc(`${appName}-vpc`, {}, { parent });
const vpc = util.getCommonVpc();

const cluster = new aws.ecs.Cluster(
`${appName}-cluster`,
Expand Down
3 changes: 2 additions & 1 deletion tests/redis/infrastructure/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as aws from '@pulumi/aws-v7';
import * as pulumi from '@pulumi/pulumi';
import * as upstash from '@upstash/pulumi';
import { next as studion } from '@studion/infra-code-blocks';
import * as util from '../../util';

const appName = 'redis-test';
const stackName = pulumi.getStack();
Expand All @@ -15,7 +16,7 @@ const parent = new pulumi.ComponentResource(
`${appName}-root`,
);

const vpc = new studion.Vpc(`${appName}-vpc`, {}, { parent });
const vpc = util.getCommonVpc();

const defaultElastiCacheRedis = new studion.ElastiCacheRedis(
`${appName}-default-elasticache`,
Expand Down
102 changes: 102 additions & 0 deletions tests/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import * as os from 'node:os';
import { finished } from 'node:stream/promises';
import { run } from 'node:test';
import { spec } from 'node:test/reporters';
import * as pulumi from '@pulumi/pulumi';
import { InlineProgramArgs } from '@pulumi/pulumi/automation';
import * as automation from './automation';

const stackName = 'dev';
const projectName = 'icb-test-common-infra';
const programArgs: InlineProgramArgs = {
stackName,
projectName,
program: provisionCommonInfra,
};

async function provisionCommonInfra() {
const { next: studion } = await import('@studion/infra-code-blocks');
const vpc = new studion.Vpc('common-infra-vpc', {});
const org = pulumi.getOrganization();

process.env.ICB_COMMON_INFRA_STACK_REF = `${org}/${projectName}/${stackName}`;

return { vpc };
}

async function globalSetup() {
await automation.deploy(programArgs);
}

async function globalTeardown() {
await automation.destroy(programArgs);
}

async function runTests(files?: string[]) {
const stream = run({
// Tests are not CPU intensive, instead most of the time is spent waiting
// for resources provisioning and destroying, so bumping concurrency over
// recommendation improves utilization and reduces execution time.
concurrency: os.availableParallelism() * 2,
...(files && files.length
? { files }
: {
globPatterns: ['tests/**/index.test.ts'],
}),
})
.on('test:fail', () => {
process.exitCode = 1;
})
.compose(spec);

// Do not wait for completion on stdout pipe, as it will not settle
// as expected which in turn will cause finally to not be reached.
// In other words, avoid:
// `const stream = run(...).compose(...).pipe(process.stdout); await finished(stream);`
stream.pipe(process.stdout);

await finished(stream);
}

function getBooleanArg(name: string): boolean {
const args = process.argv.slice(2);
const key = `--${name}`;
const idx = args.indexOf(key);

return idx !== -1;
}

function getFileArgs(): string[] {
const args = process.argv.slice(2);

return args.filter(arg => arg.startsWith('tests/'));
}

(async function exec() {
const includeSetup = getBooleanArg('setup');
const includeTests = getBooleanArg('tests');
const includeTeardown = getBooleanArg('teardown');
// Implicitly excluding everything has a same effect as explicitly including everything
const includeAll = !includeSetup && !includeTests && !includeTeardown;
const files = getFileArgs();

try {
if (includeSetup || includeAll) {
console.log('Running global setup...');
await globalSetup();
}

if (includeTests || includeAll) {
console.log('Running tests...');
await runTests(files);
}
} catch (err) {
console.error(err);
process.exitCode = 1;
} finally {
if (includeTeardown || includeAll) {
console.log('Running global teardown...');
await globalTeardown();
}
}
})();
4 changes: 0 additions & 4 deletions tests/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,5 @@
"paths": {
"@studion/infra-code-blocks": ["../src/index.ts"]
}
},
"ts-node": {
"transpileOnly": true,
"require": ["tsconfig-paths/register"]
}
}
10 changes: 10 additions & 0 deletions tests/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as pulumi from '@pulumi/pulumi';
import { OutputMap } from '@pulumi/pulumi/automation';
import { next as studion } from '@studion/infra-code-blocks';
import { backOff as backOffFn, BackoffOptions } from 'exponential-backoff';

const backOffDefaults: BackoffOptions = {
Expand Down Expand Up @@ -37,3 +39,11 @@ export function unwrapOutputs<T extends Record<string, any>>(

return unwrapped;
}

export function getCommonVpc(): pulumi.Output<studion.Vpc> {
const ref = requireEnv('ICB_COMMON_INFRA_STACK_REF');
const stack = new pulumi.StackReference(ref);
const vpc = stack.getOutput('vpc');

return vpc as pulumi.Output<studion.Vpc>;
}
3 changes: 2 additions & 1 deletion tests/web-server/infrastructure/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { next as studion } from '@studion/infra-code-blocks';
import * as aws from '@pulumi/aws-v7';
import * as pulumi from '@pulumi/pulumi';
import * as util from '../../util';
import {
webServerName,
healthCheckPath,
Expand All @@ -15,7 +16,7 @@ const parent = new pulumi.ComponentResource(
'studion:webserver:TestGroup',
`${webServerName}-root`,
);
const vpc = new studion.Vpc(`${webServerName}-vpc`, {}, { parent });
const vpc = util.getCommonVpc();
const tags = { Env: stackName, Project: webServerName };
const init = {
name: 'init',
Expand Down