examples.test.js (2632B)
1 // test/examples.test.js - the shipped examples must stay valid 2 // 3 // Documentation that no longer parses is worse than no documentation, so 4 // every example is compiled as part of the suite. 5 6 import test from 'node:test'; 7 import assert from 'node:assert/strict'; 8 import fs from 'node:fs/promises'; 9 import path from 'node:path'; 10 import { fileURLToPath } from 'node:url'; 11 import { compilePipeline } from '../src/lib/pipeline/index.js'; 12 13 const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); 14 const EXAMPLES = path.join(ROOT, 'examples'); 15 16 test('every example pipeline compiles', async () => { 17 const files = (await fs.readdir(EXAMPLES)).filter((f) => f.endsWith('.yml') || f.endsWith('.yaml')); 18 assert.ok(files.length > 0, 'expected at least one example'); 19 20 for (const file of files) { 21 const text = await fs.readFile(path.join(EXAMPLES, file), 'utf8'); 22 const pipeline = compilePipeline(text, { source: file }); 23 assert.ok(pipeline.tasks.length > 0, `${file} produced no tasks`); 24 } 25 }); 26 27 test('the distribution example fans in per architecture', async () => { 28 const text = await fs.readFile(path.join(EXAMPLES, 'distro.conductor.yml'), 'utf8'); 29 const pipeline = compilePipeline(text, { source: 'distro.conductor.yml' }); 30 const tasks = Object.fromEntries(pipeline.tasks.map((j) => [j.name, j])); 31 32 // check, two toolchains, twelve packages, two images, one publish. 33 assert.equal(pipeline.tasks.length, 18); 34 35 // A package waits only on its own architecture's toolchain. 36 assert.deepEqual(tasks['package:arch=aarch64,pkg=musl'].needs, ['toolchain:arch=aarch64']); 37 assert.deepEqual(tasks['package:arch=x86_64,pkg=grub'].needs, ['toolchain:arch=x86_64']); 38 39 // An image waits on every package for its architecture, and no others. 40 const imageNeeds = tasks['image:arch=x86_64'].needs; 41 assert.equal(imageNeeds.length, 6); 42 assert.ok(imageNeeds.every((n) => n.includes('arch=x86_64'))); 43 44 // publish has no architecture, so it waits for both, plus check. 45 assert.equal(tasks.publish.needs.length, 3); 46 assert.equal(tasks.publish.depth, 3); 47 }); 48 49 test('the node example wires services and features', async () => { 50 const text = await fs.readFile(path.join(EXAMPLES, 'node-app.conductor.yml'), 'utf8'); 51 const pipeline = compilePipeline(text, { source: 'node-app.conductor.yml' }); 52 const tasks = Object.fromEntries(pipeline.tasks.map((j) => [j.name, j])); 53 54 assert.deepEqual(tasks['test:suite=unit'].services.map((s) => s.alias), ['postgres']); 55 assert.deepEqual(tasks.image.requires, ['docker']); 56 assert.equal(tasks['test:suite=integration'].artifacts.when, 'always'); 57 });