From dd5dfb3e486f95b92edd0854df2a2896d3ddefd2 Mon Sep 17 00:00:00 2001 From: Nikola Jokic Date: Wed, 8 Jun 2022 13:20:54 +0200 Subject: [PATCH] refactored tests to be easier to follow --- .../docker/src/dockerCommands/container.ts | 9 +- packages/docker/tests/cleanup-job-test.ts | 41 ++----- packages/docker/tests/e2e-test.ts | 114 ++++++++---------- packages/docker/tests/prepare-job-test.ts | 72 +++++------ packages/docker/tests/run-script-step.ts | 47 ++++++++ packages/docker/tests/test-setup.ts | 40 +++--- 6 files changed, 166 insertions(+), 157 deletions(-) create mode 100644 packages/docker/tests/run-script-step.ts diff --git a/packages/docker/src/dockerCommands/container.ts b/packages/docker/src/dockerCommands/container.ts index e47fc84..74050d3 100644 --- a/packages/docker/src/dockerCommands/container.ts +++ b/packages/docker/src/dockerCommands/container.ts @@ -2,10 +2,8 @@ import * as core from '@actions/core' import * as fs from 'fs' import { ContainerInfo, - JobContainerInfo, RunContainerStepArgs, - ServiceContainerInfo, - StepContainerInfo + ServiceContainerInfo } from 'hooklib/lib' import path from 'path' import { env } from 'process' @@ -55,7 +53,7 @@ export async function createContainer( const mountVolumes = [ ...(args.userMountVolumes || []), - ...((args as JobContainerInfo | StepContainerInfo).systemMountVolumes || []) + ...(args.systemMountVolumes || []) ] for (const mountVolume of mountVolumes) { dockerArgs.push( @@ -328,8 +326,7 @@ export async function containerExecStep( } } - // Todo figure out prepend path and update it here - // (we need to pass path in as -e Path={fullpath}) where {fullpath is the prepend path added to the current containers path} + dockerArgs.push('-e', `"PATH=${args.prependPath.join(':')}:$PATH"`) dockerArgs.push(containerId) dockerArgs.push(args.entryPoint) diff --git a/packages/docker/tests/cleanup-job-test.ts b/packages/docker/tests/cleanup-job-test.ts index a9cf3fe..e02727d 100644 --- a/packages/docker/tests/cleanup-job-test.ts +++ b/packages/docker/tests/cleanup-job-test.ts @@ -1,51 +1,30 @@ import * as fs from 'fs' -import * as path from 'path' -import { v4 as uuidv4 } from 'uuid' import { cleanupJob, prepareJob } from '../src/hooks' import TestSetup from './test-setup' -const prepareJobInputPath = path.resolve( - `${__dirname}/../../../examples/prepare-job.json` -) - -const tmpOutputDir = `${__dirname}/${uuidv4()}` - -let prepareJobOutputPath: string -let prepareJobData: any - let testSetup: TestSetup jest.useRealTimers() describe('cleanup job', () => { - beforeAll(() => { - fs.mkdirSync(tmpOutputDir, { recursive: true }) - }) - - afterAll(() => { - fs.rmSync(tmpOutputDir, { recursive: true }) - }) - beforeEach(async () => { - const prepareJobRawData = fs.readFileSync(prepareJobInputPath, 'utf8') - prepareJobData = JSON.parse(prepareJobRawData.toString()) - - prepareJobOutputPath = `${tmpOutputDir}/prepare-job-output-${uuidv4()}.json` - fs.writeFileSync(prepareJobOutputPath, '') - testSetup = new TestSetup() testSetup.initialize() - prepareJobData.args.container.userMountVolumes = testSetup.userMountVolumes - prepareJobData.args.container.systemMountVolumes = - testSetup.systemMountVolumes - prepareJobData.args.container.workingDirectory = testSetup.workingDirectory + const prepareJobDefinition = JSON.parse( + fs.readFileSync( + `${__dirname}/../../../examples/prepare-job.json`, + 'utf-8' + ) + ) - await prepareJob(prepareJobData.args, prepareJobOutputPath) + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' + ) + await prepareJob(prepareJobDefinition.args, prepareJobOutput) }) afterEach(() => { - fs.rmSync(prepareJobOutputPath, { force: true }) testSetup.teardown() }) diff --git a/packages/docker/tests/e2e-test.ts b/packages/docker/tests/e2e-test.ts index ea48f9f..b2e4ffc 100644 --- a/packages/docker/tests/e2e-test.ts +++ b/packages/docker/tests/e2e-test.ts @@ -1,6 +1,5 @@ import * as fs from 'fs' import * as path from 'path' -import { v4 as uuidv4 } from 'uuid' import { cleanupJob, prepareJob, @@ -9,94 +8,83 @@ import { } from '../src/hooks' import TestSetup from './test-setup' -const prepareJobJson = fs.readFileSync( - path.resolve(__dirname + '/../../../examples/prepare-job.json'), - 'utf8' -) +const definitions = { + prepareJob: JSON.parse( + fs.readFileSync( + path.resolve(__dirname + '/../../../examples/prepare-job.json'), + 'utf8' + ) + ), -const containerStepJson = fs.readFileSync( - path.resolve(__dirname + '/../../../examples/run-container-step.json'), - 'utf8' -) + runContainerStep: JSON.parse( + fs.readFileSync( + path.resolve(__dirname + '/../../../examples/run-container-step.json'), + 'utf8' + ) + ), -const tmpOutputDir = `${__dirname}/_temp/${uuidv4()}` - -let prepareJobData: any -let scriptStepJson: any -let scriptStepData: any -let containerStepData: any - -let prepareJobOutputFilePath: string + runScriptStep: JSON.parse( + fs.readFileSync( + path.resolve(__dirname + '/../../../examples/run-script-step.json'), + 'utf-8' + ) + ) +} let testSetup: TestSetup describe('e2e', () => { - beforeAll(() => { - fs.mkdirSync(tmpOutputDir, { recursive: true }) - }) - - afterAll(() => { - fs.rmSync(tmpOutputDir, { recursive: true }) - }) - beforeEach(() => { - // init dirs testSetup = new TestSetup() testSetup.initialize() - - prepareJobData = JSON.parse(prepareJobJson) - prepareJobData.args.container.userMountVolumes = testSetup.userMountVolumes - prepareJobData.args.container.systemMountVolumes = + definitions.prepareJob.args.container.systemMountVolumes = testSetup.systemMountVolumes - prepareJobData.args.container.workingDirectory = testSetup.workingDirectory - - scriptStepJson = fs.readFileSync( - path.resolve(__dirname + '/../../../examples/run-script-step.json'), - 'utf8' - ) - scriptStepData = JSON.parse(scriptStepJson) - scriptStepData.args.workingDirectory = testSetup.workingDirectory - - containerStepData = JSON.parse(containerStepJson) - containerStepData.args.workingDirectory = testSetup.workingDirectory - containerStepData.args.userMountVolumes = testSetup.userMountVolumes - containerStepData.args.systemMountVolumes = testSetup.systemMountVolumes - - prepareJobOutputFilePath = `${tmpOutputDir}/prepare-job-output-${uuidv4()}.json` - fs.writeFileSync(prepareJobOutputFilePath, '') }) afterEach(() => { - fs.rmSync(prepareJobOutputFilePath, { force: true }) testSetup.teardown() }) it('should prepare job, then run script step, then run container step then cleanup', async () => { + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' + ) + await expect( - prepareJob(prepareJobData.args, prepareJobOutputFilePath) + prepareJob(definitions.prepareJob.args, prepareJobOutput) ).resolves.not.toThrow() - let rawState = fs.readFileSync(prepareJobOutputFilePath, 'utf-8') + + let rawState = fs.readFileSync(prepareJobOutput, 'utf-8') let resp = JSON.parse(rawState) + await expect( - runScriptStep(scriptStepData.args, resp.state) + runScriptStep(definitions.runScriptStep.args, resp.state) ).resolves.not.toThrow() + await expect( - runContainerStep(containerStepData.args, resp.state) + runContainerStep(definitions.runContainerStep.args, resp.state) ).resolves.not.toThrow() + await expect(cleanupJob()).resolves.not.toThrow() }) it('should prepare job, then run script step, then run container step with Dockerfile then cleanup', async () => { + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' + ) + await expect( - prepareJob(prepareJobData.args, prepareJobOutputFilePath) - ).resolves.not.toThrow() - let rawState = fs.readFileSync(prepareJobOutputFilePath, 'utf-8') - let resp = JSON.parse(rawState) - await expect( - runScriptStep(scriptStepData.args, resp.state) + prepareJob(definitions.prepareJob.args, prepareJobOutput) ).resolves.not.toThrow() - const dockerfilePath = `${tmpOutputDir}/Dockerfile` + let rawState = fs.readFileSync(prepareJobOutput, 'utf-8') + let resp = JSON.parse(rawState) + + await expect( + runScriptStep(definitions.runScriptStep.args, resp.state) + ).resolves.not.toThrow() + + const dockerfilePath = `${testSetup.workingDirectory}/Dockerfile` fs.writeFileSync( dockerfilePath, `FROM ubuntu:latest @@ -104,13 +92,17 @@ ENV TEST=test ENTRYPOINT [ "tail", "-f", "/dev/null" ] ` ) - const containerStepDataCopy = JSON.parse(JSON.stringify(containerStepData)) - process.env.GITHUB_WORKSPACE = tmpOutputDir + + const containerStepDataCopy = JSON.parse( + JSON.stringify(definitions.runContainerStep) + ) + containerStepDataCopy.args.dockerfile = 'Dockerfile' - containerStepDataCopy.args.context = '.' + await expect( runContainerStep(containerStepDataCopy.args, resp.state) ).resolves.not.toThrow() + await expect(cleanupJob()).resolves.not.toThrow() }) }) diff --git a/packages/docker/tests/prepare-job-test.ts b/packages/docker/tests/prepare-job-test.ts index e94aa08..1494628 100644 --- a/packages/docker/tests/prepare-job-test.ts +++ b/packages/docker/tests/prepare-job-test.ts @@ -1,40 +1,24 @@ import * as fs from 'fs' -import { v4 as uuidv4 } from 'uuid' import { prepareJob } from '../src/hooks' import TestSetup from './test-setup' jest.useRealTimers() -let prepareJobOutputPath: string -let prepareJobData: any -const tmpOutputDir = `${__dirname}/_temp/${uuidv4()}` -const prepareJobInputPath = `${__dirname}/../../../examples/prepare-job.json` +const prepareJobDefinition = JSON.parse( + fs.readFileSync(`${__dirname}/../../../examples/prepare-job.json`, 'utf-8') +) let testSetup: TestSetup describe('prepare job', () => { - beforeAll(() => { - fs.mkdirSync(tmpOutputDir, { recursive: true }) - }) - - afterAll(() => { - fs.rmSync(tmpOutputDir, { recursive: true }) - }) - - beforeEach(async () => { + beforeEach(() => { testSetup = new TestSetup() testSetup.initialize() - let prepareJobRawData = fs.readFileSync(prepareJobInputPath, 'utf8') - prepareJobData = JSON.parse(prepareJobRawData.toString()) - - prepareJobData.args.container.userMountVolumes = testSetup.userMountVolumes - prepareJobData.args.container.systemMountVolumes = + prepareJobDefinition.args.container.systemMountVolumes = testSetup.systemMountVolumes - prepareJobData.args.container.workingDirectory = testSetup.workingDirectory - - prepareJobOutputPath = `${tmpOutputDir}/prepare-job-output-${uuidv4()}.json` - fs.writeFileSync(prepareJobOutputPath, '') + prepareJobDefinition.args.container.workingDirectory = + testSetup.workingDirectory }) afterEach(() => { @@ -42,38 +26,42 @@ describe('prepare job', () => { }) it('should not throw', async () => { + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' + ) await expect( - prepareJob(prepareJobData.args, prepareJobOutputPath) + prepareJob(prepareJobDefinition.args, prepareJobOutput) ).resolves.not.toThrow() - expect(() => fs.readFileSync(prepareJobOutputPath, 'utf-8')).not.toThrow() + expect(() => fs.readFileSync(prepareJobOutput, 'utf-8')).not.toThrow() }) it('should have JSON output written to a file', async () => { - await prepareJob(prepareJobData.args, prepareJobOutputPath) - const prepareJobOutputContent = fs.readFileSync( - prepareJobOutputPath, - 'utf-8' + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' ) + await prepareJob(prepareJobDefinition.args, prepareJobOutput) + const prepareJobOutputContent = fs.readFileSync(prepareJobOutput, 'utf-8') expect(() => JSON.parse(prepareJobOutputContent)).not.toThrow() }) it('should have context written to a file', async () => { - await prepareJob(prepareJobData.args, prepareJobOutputPath) - const prepareJobOutputContent = fs.readFileSync( - prepareJobOutputPath, - 'utf-8' + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' + ) + await prepareJob(prepareJobDefinition.args, prepareJobOutput) + const parsedPrepareJobOutput = JSON.parse( + fs.readFileSync(prepareJobOutput, 'utf-8') ) - const parsedPrepareJobOutput = JSON.parse(prepareJobOutputContent) expect(parsedPrepareJobOutput.context).toBeDefined() }) it('should have container ids written to file', async () => { - await prepareJob(prepareJobData.args, prepareJobOutputPath) - const prepareJobOutputContent = fs.readFileSync( - prepareJobOutputPath, - 'utf-8' + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' ) + await prepareJob(prepareJobDefinition.args, prepareJobOutput) + const prepareJobOutputContent = fs.readFileSync(prepareJobOutput, 'utf-8') const parsedPrepareJobOutput = JSON.parse(prepareJobOutputContent) expect(parsedPrepareJobOutput.context.container.id).toBeDefined() @@ -82,11 +70,11 @@ describe('prepare job', () => { }) it('should have ports for context written in form [containerPort]:[hostPort]', async () => { - await prepareJob(prepareJobData.args, prepareJobOutputPath) - const prepareJobOutputContent = fs.readFileSync( - prepareJobOutputPath, - 'utf-8' + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' ) + await prepareJob(prepareJobDefinition.args, prepareJobOutput) + const prepareJobOutputContent = fs.readFileSync(prepareJobOutput, 'utf-8') const parsedPrepareJobOutput = JSON.parse(prepareJobOutputContent) const mainContainerPorts = parsedPrepareJobOutput.context.container.ports diff --git a/packages/docker/tests/run-script-step.ts b/packages/docker/tests/run-script-step.ts new file mode 100644 index 0000000..15fbc41 --- /dev/null +++ b/packages/docker/tests/run-script-step.ts @@ -0,0 +1,47 @@ +import * as fs from 'fs' +import { PrepareJobResponse } from 'hooklib/lib' +import * as path from 'path' +import { prepareJob, runScriptStep } from '../src/hooks' +import TestSetup from './test-setup' + +jest.useRealTimers() + +let testSetup: TestSetup + +const definitions = { + prepareJob: JSON.parse( + fs.readFileSync( + path.resolve(__dirname + '/../../../examples/prepare-job.json'), + 'utf8' + ) + ), + + runScriptStep: JSON.parse( + fs.readFileSync( + path.resolve(__dirname + '/../../../examples/run-script-step.json'), + 'utf-8' + ) + ) +} + +let prepareJobResponse: PrepareJobResponse + +describe('run-script-step', () => { + beforeEach(async () => { + testSetup = new TestSetup() + testSetup.initialize() + + const prepareJobOutput = testSetup.createOutputFile( + 'prepare-job-output.json' + ) + await prepareJob(definitions.prepareJob.args, prepareJobOutput) + + prepareJobResponse = JSON.parse(fs.readFileSync(prepareJobOutput, 'utf-8')) + }) + + it('Should run script step without exceptions', async () => { + await expect( + runScriptStep(definitions.runScriptStep.args, prepareJobResponse.state) + ).resolves.not.toThrow() + }) +}) diff --git a/packages/docker/tests/test-setup.ts b/packages/docker/tests/test-setup.ts index 58434b9..df19c77 100644 --- a/packages/docker/tests/test-setup.ts +++ b/packages/docker/tests/test-setup.ts @@ -1,11 +1,14 @@ import * as fs from 'fs' -import { v4 as uuidv4 } from 'uuid' -import { env } from 'process' import { Mount } from 'hooklib' +import * as path from 'path' +import { env } from 'process' +import { v4 as uuidv4 } from 'uuid' export default class TestSetup { private testdir: string private runnerMockDir: string + readonly runnerOutputDir: string + private runnerMockSubdirs = { work: '_work', externals: 'externals', @@ -16,15 +19,16 @@ export default class TestSetup { githubWorkflow: '_work/_temp/_github_workflow' } - private readonly projectName = 'example' + private readonly projectName = 'repo' constructor() { this.testdir = `${__dirname}/_temp/${uuidv4()}` this.runnerMockDir = `${this.testdir}/runner/_layout` + this.runnerOutputDir = `${this.testdir}/outputs` } private get allTestDirectories() { - const resp = [this.testdir, this.runnerMockDir] + const resp = [this.testdir, this.runnerMockDir, this.runnerOutputDir] for (const [key, value] of Object.entries(this.runnerMockSubdirs)) { resp.push(`${this.runnerMockDir}/${value}`) @@ -38,29 +42,21 @@ export default class TestSetup { } public initialize(): void { - for (const dir of this.allTestDirectories) { - fs.mkdirSync(dir, { recursive: true }) - } + env['GITHUB_WORKSPACE'] = this.workingDirectory env['RUNNER_NAME'] = 'test' env[ 'RUNNER_TEMP' ] = `${this.runnerMockDir}/${this.runnerMockSubdirs.workTemp}` + + for (const dir of this.allTestDirectories) { + fs.mkdirSync(dir, { recursive: true }) + } } public teardown(): void { fs.rmdirSync(this.testdir, { recursive: true }) } - public get userMountVolumes(): Mount[] { - return [ - { - sourceVolumePath: 'my_docker_volume', - targetVolumePath: '/volume_mount', - readOnly: false - } - ] - } - public get systemMountVolumes(): Mount[] { return [ { @@ -106,7 +102,17 @@ export default class TestSetup { ] } + public createOutputFile(name: string): string { + let filePath = path.join(this.runnerOutputDir, name || `${uuidv4()}.json`) + fs.writeFileSync(filePath, '') + return filePath + } + public get workingDirectory(): string { + return `${this.runnerMockDir}/_work/${this.projectName}/${this.projectName}` + } + + public get containerWorkingDirectory(): string { return `/__w/${this.projectName}/${this.projectName}` } }