Skip to content

Commit c33dda4

Browse files
authored
feat(smoke): simple smoke tests after deploy (#2802)
1 parent b5977fe commit c33dda4

File tree

7 files changed

+136
-1
lines changed

7 files changed

+136
-1
lines changed

.github/workflows/push.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ jobs:
6060
GOOGLE_ANALYTICS: ${{secrets.GOOGLE_ANALYTICS_NON_PROD}}
6161
NODE_ENV: "dev"
6262

63+
- name: (NonProd) After Deploy Smoke Test
64+
if: github.ref == 'refs/heads/master' && github.repository == 'linz/basemaps'
65+
run: |
66+
cd packages/smoke
67+
node --test
68+
6369
- name: (Prod) Configure AWS Credentials
6470
if: github.ref == 'refs/heads/master' && startsWith(github.event.head_commit.message, 'release:')
6571
uses: aws-actions/configure-aws-credentials@v2.0.0

packages/smoke/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# @basemaps/smoke
2+
3+
Utility to smoke test deployments
4+
5+
to run
6+
7+
```bash
8+
BASEMAPS_HOST=https://dev.basemaps.linz.govt.nz node --test
9+
```
10+
11+
*Requires Node >= 18*

packages/smoke/package.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@basemaps/smoke",
3+
"version": "6.32.1",
4+
"repository": {
5+
"type": "git",
6+
"url": "https://github.com/linz/basemaps.git",
7+
"directory": "packages/smoke"
8+
},
9+
"author": {
10+
"name": "Land Information New Zealand",
11+
"url": "https://linz.govt.nz",
12+
"organization": true
13+
},
14+
"type": "module",
15+
"engines": {
16+
"node": ">=18.0.0"
17+
},
18+
"license": "MIT",
19+
"scripts": {},
20+
"publishConfig": {
21+
"access": "public"
22+
},
23+
"files": [
24+
"build/",
25+
"bin/"
26+
],
27+
"dependencies": {
28+
"@basemaps/shared": "^6.40.0"
29+
},
30+
"devDependencies": {}
31+
}

packages/smoke/src/base.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { LogConfig } from '@basemaps/shared';
2+
import assert from 'node:assert';
3+
import ulid from 'ulid';
4+
5+
const logger = LogConfig.get();
6+
/** Fresh API Key to use */
7+
const apiKey = 'c' + ulid.ulid().toLowerCase();
8+
9+
/** Http headers required to trigger CORS */
10+
const Cors = { origin: 'https://example.com' };
11+
12+
/** Host that is being tested */
13+
let host = process.env['BASEMAPS_HOST'] || 'https://dev.basemaps.linz.govt.nz';
14+
15+
if (!host.startsWith('http')) throw new Error(`Invalid host: ${host}`);
16+
if (host.endsWith('/')) host = host.slice(0, host.length - 1);
17+
18+
/** Request a url with options
19+
*
20+
* @example
21+
* ```typescript
22+
* await req('/v1/version')
23+
* await req('/v1/version', { method: 'OPTIONS' })
24+
* ````
25+
*/
26+
async function req(path: string, opts?: RequestInit): Promise<Response> {
27+
const target = new URL(path, host);
28+
logger.trace({ path, url: target.href }, 'Fetch');
29+
const startTime = performance.now();
30+
const res = await fetch(target, opts);
31+
logger.info(
32+
{ path, url: target.href, status: res.status, ...opts, duration: performance.now() - startTime },
33+
'Fetch:Done',
34+
);
35+
return res;
36+
}
37+
38+
export const ctx = { logger, host, Cors, apiKey, req };
39+
40+
/** Validate that the response was not a cached response */
41+
export function assertCacheMiss(res: Response): void {
42+
const cacheHeader = res.headers.get('x-cache');
43+
if (cacheHeader == null) return; // No header is a miss
44+
assert.equal(cacheHeader.startsWith('Miss'), true, `Should be a cache Miss ${res.headers.get('x-cache')}`);
45+
}

packages/smoke/src/health.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import assert from 'node:assert';
2+
import { describe, it } from 'node:test';
3+
import { assertCacheMiss, ctx } from './base.js';
4+
5+
describe('health', () => {
6+
it('should 200 when GET /v1/ping', async () => {
7+
const res = await ctx.req('/v1/ping');
8+
assert.equal(res.status, 200);
9+
assertCacheMiss(res);
10+
});
11+
12+
it('should 200 when GET /v1/health', async () => {
13+
const res = await ctx.req('/v1/health');
14+
assert.equal(res.status, 200);
15+
assertCacheMiss(res);
16+
});
17+
18+
it('should 200 when GET /v1/version', async () => {
19+
const res = await ctx.req('/v1/version');
20+
assert.equal(res.status, 200);
21+
assertCacheMiss(res);
22+
23+
const data = await res.json();
24+
25+
assert.equal(typeof data.version, 'string');
26+
assert.ok(data.version);
27+
28+
assert.equal(typeof data.hash, 'string');
29+
assert.ok(data.hash);
30+
});
31+
});

packages/smoke/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"lib": ["DOM"],
5+
"rootDir": "./src",
6+
"outDir": "./build"
7+
},
8+
"include": ["src"],
9+
"references": [{ "path": "../shared" }]
10+
}

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
{ "path": "./packages/lambda-analytics" },
2020
{ "path": "./packages/attribution" },
2121
{ "path": "./packages/landing" },
22-
{ "path": "./packages/server" }
22+
{ "path": "./packages/server" },
23+
{ "path": "./packages/smoke" }
2324
]
2425
}

0 commit comments

Comments
 (0)