Skip to content
Permalink
Browse files
Mount the absolute path generated from inputs into docker
  • Loading branch information
Barry Gordon committed Oct 19, 2021
1 parent 5d5f5c7 commit c9ae7b02808eb0c0c8dbb6a2ed1538243abe617d
Showing 5 changed files with 105 additions and 26 deletions.
Empty file.
@@ -1,5 +1,6 @@
import axios from 'axios'

import fs from 'fs'
import path from 'path'
import {ApiClient} from '../src/api-client'
import {ImageService} from '../src/image-service'
import {JobParameters} from '../src/inputs'
@@ -19,13 +20,20 @@ describe('Updater', () => {
const internalDockerHost =
process.platform === 'darwin' ? 'host.docker.internal' : '172.17.0.1'
const dependabotApiDockerUrl = `http://${internalDockerHost}:${FAKE_SERVER_PORT}`
const workingDirectory = path.join(
__dirname,
'..',
'tmp',
'./integration_working_directory'
)

const params = new JobParameters(
1,
'job-token',
'cred-token',
dependabotApiUrl,
dependabotApiDockerUrl,
'nyi-workingDirectory'
workingDirectory
)

const client = axios.create({baseURL: dependabotApiUrl})
@@ -41,11 +49,14 @@ describe('Updater', () => {
await ImageService.pull(PROXY_IMAGE_NAME)

server = await runFakeDependabotApi(FAKE_SERVER_PORT)

fs.mkdirSync(workingDirectory)
})

afterEach(async () => {
server && server() // teardown server process
await removeDanglingUpdaterContainers()
fs.rmdirSync(workingDirectory, {recursive: true})
})

jest.setTimeout(120000)
@@ -63,7 +74,8 @@ describe('Updater', () => {
PROXY_IMAGE_NAME,
apiClient,
details,
credentials
credentials,
workingDirectory
)

await updater.runUpdater()
@@ -1,3 +1,5 @@
import fs from 'fs'
import path from 'path'
import {Updater} from '../src/updater'
import Docker from 'dockerode'
import {ContainerService} from '../src/container-service'
@@ -8,6 +10,17 @@ jest.mock('dockerode')
jest.mock('../src/container-service')
jest.mock('../src/proxy')

const outputFixturePath = (fixtureName: string): string => {
return path.join(
__dirname,
'..',
'__fixtures__',
'output',
fixtureName,
'output.json'
)
}

describe('Updater', () => {
const mockApiClient: any = {
getJobDetails: jest.fn(),
@@ -45,8 +58,22 @@ describe('Updater', () => {
id: 1
}

const workingDirectory = path.join(
__dirname,
'..',
'tmp',
'./test_working_directory'
)

const outputFilePath = path.join(workingDirectory, 'output', 'output.json')

beforeEach(async () => {
fs.mkdirSync(workingDirectory)
})

afterEach(async () => {
jest.clearAllMocks() // Reset any mocked classes
fs.rmdirSync(workingDirectory, {recursive: true})
})

describe('when there is a happy path update', () => {
@@ -56,16 +83,32 @@ describe('Updater', () => {
mockApiClient,
mockJobDetails,
[],
'../__fixtures__/output/happy_path/output.json'
workingDirectory
)

const outputFixture = outputFixturePath('happy_path')

beforeEach(async () => {
jest
.spyOn(Docker.prototype, 'createContainer')
.mockResolvedValue(mockContainer)

jest.spyOn(ProxyBuilder.prototype, 'run').mockResolvedValue(mockProxy)
jest.spyOn(ContainerService, 'run').mockImplementation(jest.fn())
jest
.spyOn(ContainerService, 'run')
.mockImplementationOnce(
jest.fn(async () => {
fs.copyFileSync(outputFixture, outputFilePath)
return true
})
)
.mockImplementationOnce(
jest.fn(
jest.fn(async () => {
return true
})
)
)
})

it('should be successful', async () => {
@@ -80,7 +123,7 @@ describe('Updater', () => {
mockApiClient,
mockJobDetails,
[],
'../__fixtures__/output/happy_path/output.json'
workingDirectory
)

beforeEach(async () => {
@@ -100,7 +143,9 @@ describe('Updater', () => {
})

it('should raise an error', async () => {
await expect(updater.runUpdater()).rejects.toThrow()
await expect(updater.runUpdater()).rejects.toThrow(
'First call to container service errored'
)
})
})

@@ -111,9 +156,11 @@ describe('Updater', () => {
mockApiClient,
mockJobDetails,
[],
'../__fixtures__/output/happy_path/output.json'
workingDirectory
)

const outputFixture = outputFixturePath('happy_path')

beforeEach(async () => {
jest
.spyOn(Docker.prototype, 'createContainer')
@@ -123,7 +170,12 @@ describe('Updater', () => {

jest
.spyOn(ContainerService, 'run')
.mockImplementationOnce(jest.fn())
.mockImplementationOnce(
jest.fn(async () => {
fs.copyFileSync(outputFixture, outputFilePath)
return true
})
)
.mockImplementationOnce(
jest.fn(async () =>
Promise.reject(
@@ -134,7 +186,9 @@ describe('Updater', () => {
})

it('should raise an error', async () => {
await expect(updater.runUpdater()).rejects.toThrow()
await expect(updater.runUpdater()).rejects.toThrow(
'Second call to container service errored'
)
})
})

@@ -145,7 +199,7 @@ describe('Updater', () => {
mockApiClient,
mockJobDetails,
[],
'../__fixtures__/output/empty/output.json'
workingDirectory
)

beforeEach(async () => {
@@ -172,21 +226,28 @@ describe('Updater', () => {
mockApiClient,
mockJobDetails,
[],
'../__fixtures__/output/malformed/output.json'
workingDirectory
)

const outputFixture = outputFixturePath('malformed')

beforeEach(async () => {
jest
.spyOn(Docker.prototype, 'createContainer')
.mockResolvedValue(mockContainer)

jest.spyOn(ProxyBuilder.prototype, 'run').mockResolvedValue(mockProxy)

jest.spyOn(ContainerService, 'run').mockImplementation(jest.fn())
jest.spyOn(ContainerService, 'run').mockImplementation(
jest.fn(async () => {
fs.copyFileSync(outputFixture, outputFilePath)
return true
})
)
})

it('should raise an error', async () => {
await expect(updater.runUpdater()).rejects.toThrow()
await expect(updater.runUpdater()).rejects.toThrow(/Unexpected token/)
})
})
})
@@ -52,7 +52,8 @@ export async function run(context: Context): Promise<void> {
PROXY_IMAGE_NAME,
apiClient,
details,
credentials
credentials,
params.workingDirectory
)

try {
@@ -18,22 +18,30 @@ const CA_CERT_FILENAME = 'dbot-ca.crt'

export class Updater {
docker: Docker
outputHostPath: string
repoHostPath: string

constructor(
private readonly updaterImage: string,
private readonly proxyImage: string,
private readonly apiClient: ApiClient,
private readonly details: JobDetails,
private readonly credentials: Credential[],
private readonly outputPath = '../../output/output.json'
private readonly workingDirectory: string
) {
this.docker = new Docker()
this.outputHostPath = path.join(workingDirectory, 'output')
this.repoHostPath = path.join(workingDirectory, 'repo')
}

/**
* Execute an update job and report the result to Dependabot API.
*/
async runUpdater(): Promise<boolean> {
// Create required folders in the workingDirectory
fs.mkdirSync(this.outputHostPath)
fs.mkdirSync(this.repoHostPath)

const proxy = await new ProxyBuilder(this.docker, this.proxyImage).run(
this.apiClient.params.jobId,
this.credentials
@@ -67,7 +75,7 @@ export class Updater {

await ContainerService.run(container)

const outputPath = path.join(__dirname, this.outputPath)
const outputPath = path.join(this.outputHostPath, 'output.json')
if (!fs.existsSync(outputPath)) {
throw new Error('No output.json created by the fetcher container')
}
@@ -148,8 +156,8 @@ export class Updater {
Memory: 8 * 1024 * 1024 * 1024, // 8GB in bytes
NetworkMode: proxy.networkName,
Binds: [
`${path.join(__dirname, '../../output')}:${JOB_OUTPUT_PATH}:rw`,
`${path.join(__dirname, '../../repo')}:${REPO_CONTENTS_PATH}:rw`
`${this.outputHostPath}:${JOB_OUTPUT_PATH}:rw`,
`${this.repoHostPath}:${REPO_CONTENTS_PATH}:rw`
]
}
})
@@ -161,15 +169,12 @@ export class Updater {
private async cleanup(proxy: Proxy): Promise<void> {
await proxy.shutdown()

const outputDir = path.join(__dirname, '../../output')
const repoDir = path.join(__dirname, '../../repo')

if (fs.existsSync(outputDir)) {
fs.rmdirSync(outputDir, {recursive: true})
if (fs.existsSync(this.outputHostPath)) {
fs.rmdirSync(this.outputHostPath, {recursive: true})
}

if (fs.existsSync(repoDir)) {
fs.rmdirSync(repoDir, {recursive: true})
if (fs.existsSync(this.repoHostPath)) {
fs.rmdirSync(this.repoHostPath, {recursive: true})
}
}
}

0 comments on commit c9ae7b0

Please sign in to comment.