UNPKG

3.82 kBJavaScriptView Raw
1// Test runner
2const { test } = require('ava');
3
4// External dependencies
5const yaml = require('js-yaml');
6const fs = require('mz/fs');
7const strip = require('strip-color');
8const regEsc = require('escape-string-regexp');
9
10// Create/run and remove a Docker container.
11const Container = require('./helpers/container');
12
13const propagatedEnvVars = [
14 'BINARIS_API_KEY',
15 'BINARIS_DEPLOY_ENDPOINT',
16 'BINARIS_INVOKE_ENDPOINT',
17 'BINARIS_LOG_ENDPOINT'];
18
19const commonBashOpts = 'set -o pipefail;';
20
21let imageName = 'binaris/binaris';
22if (process.env.tag !== undefined) {
23 imageName = `${imageName}:${process.env.tag}`;
24}
25
26/**
27 * Create a Docker container for each test before it runs.
28 * This way all test runs are isolated thereby opening up
29 * many testing avenues.
30 */
31test.beforeEach(async (t) => {
32 // eslint-disable-next-line no-param-reassign
33 t.context.ct = new Container(imageName);
34});
35
36/**
37 * Always call `remove` on the container before exit
38 */
39test.afterEach.always(async (t) => {
40 if (t.context.cleanup) {
41 for (const cleanupStep of t.context.cleanup) {
42 // eslint-disable-next-line no-await-in-loop
43 const result = await t.context.ct.streamIn(`${commonBashOpts} ${cleanupStep}`);
44 if (result.exitCode !== 0) {
45 t.log(`Cleanup stdout: ${result.stdout}`);
46 t.log(`Cleanup stderr: ${result.stderr}`);
47 throw new Error(result.stderr);
48 }
49 }
50 }
51 await t.context.ct.stopAndKillContainer();
52});
53
54/**
55 * Iterates over the YAML CLI specification separating and testing each
56 * `test` entry separately.
57 */
58const testFileNames = ['./test/spec.yml', './test/cases.yml'];
59const testFiles = testFileNames.map(file => yaml.safeLoad(fs.readFileSync(file, 'utf8')));
60const testPlan = [].concat(...testFiles);
61
62function createTest(rawSubTest) {
63 const maybeSerialTest = rawSubTest.serial ? test.serial : test;
64 maybeSerialTest(rawSubTest.test, async (t) => {
65 const activeEnvs = propagatedEnvVars.filter(envKey =>
66 process.env[envKey] !== undefined).map(envKey =>
67 `${envKey}=${process.env[envKey]}`);
68 await t.context.ct.startContainer(activeEnvs);
69 if (rawSubTest.setup) {
70 for (const setupStep of rawSubTest.setup) {
71 // eslint-disable-next-line no-await-in-loop
72 const setupOut = await t.context.ct.streamIn(`${commonBashOpts} ${setupStep}`);
73 if (setupOut.exitCode !== 0) {
74 t.log(`Setup stdout: ${setupOut.stdout}`);
75 t.log(`Setup stderr: ${setupOut.stderr}`);
76 throw new Error(setupOut.stderr);
77 }
78 }
79 }
80 // eslint-disable-next-line no-param-reassign
81 t.context.cleanup = rawSubTest.cleanup;
82
83 const createRegTest = function createRegTest(expected) {
84 const escaped = expected.split('*').map(item => regEsc(item));
85 const finalString = `^${escaped.join('[\\s\\S]*')}$`;
86 return new RegExp(finalString);
87 };
88
89 for (const step of rawSubTest.steps) {
90 // eslint-disable-next-line no-await-in-loop
91 const cmdOut = await t.context.ct.streamIn(step.in);
92 if (step.out) {
93 t.true(createRegTest(step.out).test(strip(cmdOut.stdout.slice(0, -1))));
94 } else if (step.err) {
95 t.true(createRegTest(step.err).test(strip(cmdOut.stderr.slice(0, -1))));
96 }
97 t.true(cmdOut.exitCode === (step.exit || 0), step.err);
98 }
99 });
100}
101
102testPlan.forEach((rawSubTest) => {
103 if (rawSubTest.foreach) {
104 for (const variant of Object.keys(rawSubTest.foreach)) {
105 const vars = rawSubTest.foreach[variant];
106 let testStr = JSON.stringify(rawSubTest);
107 for (const key of Object.keys(vars)) {
108 const val = vars[key];
109 testStr = testStr.replace(new RegExp(`{${key}}`, 'g'), val);
110 }
111 const copy = JSON.parse(testStr);
112 createTest(copy);
113 }
114 } else {
115 createTest(rawSubTest);
116 }
117});
118