Skip to content

Commit

Permalink
updated aio app pack tests
Browse files Browse the repository at this point in the history
  • Loading branch information
shazron committed May 11, 2023
1 parent eeec410 commit e44de8c
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 82 deletions.
82 changes: 54 additions & 28 deletions src/commands/app/pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const yaml = require('js-yaml')
const execa = require('execa')
const { loadConfigFile, writeFile } = require('../../lib/import-helper')
const { getObjectValue } = require('../../lib/app-helper')
const ora = require('ora')

const DEFAULTS = {
OUTPUT_ZIP_FILE: 'app.zip',
Expand All @@ -36,7 +37,7 @@ class Pack extends BaseCommand {
const appConfig = this.getFullConfig()

// resolve to absolute path before any chdir
flags.output = path.resolve(flags.output)
const outputZipFile = path.resolve(flags.output)

// change the cwd if necessary
if (args.path !== '.') {
Expand All @@ -45,32 +46,52 @@ class Pack extends BaseCommand {
aioLogger.debug(`changed current working directory to: ${resolvedPath}`)
}

// 1. create artifacts phase
this.log('Creating package artifacts...')
await fs.emptyDir(DEFAULTS.ARTIFACTS_FOLDER)

// ACNA-2038
// not artifacts folder should exist before we fire the event
await this.config.runHook('pre-pack', { appConfig, artifactsFolder: DEFAULTS.ARTIFACTS_FOLDER })

// 2. copy files to package phase
this.log('Copying files...')
const fileList = await this.filesToPack()
await this.copyPackageFiles(DEFAULTS.ARTIFACTS_FOLDER, fileList)

// 3. add/modify artifacts phase
this.log('Creating configuration files...')
await this.createDeployYamlFile(appConfig)
await this.addCodeDownloadAnnotation(appConfig)
// doing this before zip so other things can be added to the zip
await this.config.runHook('post-pack', { appConfig, artifactsFolder: DEFAULTS.ARTIFACTS_FOLDER })
try {
// 1. create artifacts phase
this.spinner.start(`Creating package artifacts folder '${DEFAULTS.ARTIFACTS_FOLDER}'...`)
await fs.emptyDir(DEFAULTS.ARTIFACTS_FOLDER)
this.spinner.succeed(`Created package artifacts folder '${DEFAULTS.ARTIFACTS_FOLDER}'`)

// ACNA-2038
// not artifacts folder should exist before we fire the event
await this.config.runHook('pre-pack', { appConfig, artifactsFolder: DEFAULTS.ARTIFACTS_FOLDER })

// 2. copy files to package phase
this.spinner.start('Copying project files...')
const fileList = await this.filesToPack([flags.output])
await this.copyPackageFiles(DEFAULTS.ARTIFACTS_FOLDER, fileList)
this.spinner.succeed('Copied project files')

// 3. add/modify artifacts phase
this.spinner.start('Creating configuration files...')
await this.createDeployYamlFile(appConfig)
this.spinner.succeed('Created configuration files')

this.spinner.start('Adding code-download annotations...')
await this.addCodeDownloadAnnotation(appConfig)
this.spinner.succeed('Added code-download annotations')

// doing this before zip so other things can be added to the zip
await this.config.runHook('post-pack', { appConfig, artifactsFolder: DEFAULTS.ARTIFACTS_FOLDER })

// 4. zip package phase
this.spinner.start(`Zipping package artifacts folder '${DEFAULTS.ARTIFACTS_FOLDER}' to '${outputZipFile}'...`)
await fs.remove(outputZipFile)
await this.zipHelper(DEFAULTS.ARTIFACTS_FOLDER, outputZipFile)
this.spinner.succeed(`Zipped package artifacts folder '${DEFAULTS.ARTIFACTS_FOLDER}' to '${outputZipFile}'`)
} catch (e) {
this.spinner.fail(e.message)
this.error(flags.verbose ? e : e.message)
}

// 4. zip package phase
this.log(`Zipping package artifacts folder '${DEFAULTS.ARTIFACTS_FOLDER}' to '${flags.output}'...`)
await fs.remove(flags.output)
await this.zipHelper(DEFAULTS.ARTIFACTS_FOLDER, flags.output)
this.spinner.succeed('Packaging done.')
}

this.log('Packaging done.')
get spinner () {
if (!this._spinner) {
this._spinner = ora()
}
return this._spinner
}

/**
Expand Down Expand Up @@ -111,11 +132,13 @@ class Pack extends BaseCommand {
// TODO: send a PR to their plugin to have a `--json` flag
const command = await this.config.findCommand('api-mesh:get')
if (command) {
this.log('Getting api-mesh config...')
this.spinner.start('Getting api-mesh config...')
const { stdout } = await execa('aio', ['api-mesh', 'get'], { cwd: process.cwd() })
// until we get the --json flag, we parse the output
const idx = stdout.indexOf('{')
meshConfig = JSON.parse(stdout.substring(idx))
aioLogger.debug(`api-mesh:get - ${JSON.stringify(meshConfig, null, 2)}`)
this.spinner.succeed('Got api-mesh config')
} else {
aioLogger.debug('api-mesh:get command was not found, meshConfig is not available for app:pack')
}
Expand Down Expand Up @@ -195,14 +218,17 @@ class Pack extends BaseCommand {
*
* This runs `npm pack` to get the list.
*
* @param {Array<string>} filesToExclude a list of files to exclude
* @param {string} workingDirectory the working directory to run `npm pack` in
* @returns {Array<string>} a list of files that are to be packed
*/
async filesToPack (workingDirectory = process.cwd()) {
async filesToPack (filesToExclude = [], workingDirectory = process.cwd()) {
const { stdout } = await execa('npm', ['pack', '--dry-run', '--json'], { cwd: workingDirectory })

const { files } = JSON.parse(stdout)[0]
return files.map(file => file.path)
return files
.map(file => file.path)
.filter(file => !filesToExclude.includes(file))
}

/**
Expand Down
182 changes: 128 additions & 54 deletions test/commands/app/pack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,62 +280,136 @@ test('addCodeDownloadAnnotation', async () => {
)
})

test('run (coverage: defaults)', async () => {
mockGetFullConfig.mockImplementation(() => fixtureJson('pack/1.all.config.json'))
describe('run', () => {
test('defaults', async () => {
mockGetFullConfig.mockImplementation(() => fixtureJson('pack/1.all.config.json'))

const command = new TheCommand()
command.argv = []

// since we already unit test the methods above, we mock it here
command.copyPackageFiles = jest.fn()
command.filesToPack = jest.fn()
command.createDeployYamlFile = jest.fn()
command.addCodeDownloadAnnotation = jest.fn()
command.zipHelper = jest.fn()
const runHook = jest.fn()
command.config = { runHook }
await command.run()

expect(command.copyPackageFiles).toHaveBeenCalledTimes(1)
expect(command.filesToPack).toHaveBeenCalledTimes(1)
expect(command.createDeployYamlFile).toHaveBeenCalledTimes(1)
expect(command.addCodeDownloadAnnotation).toHaveBeenCalledTimes(1)
expect(command.zipHelper).toHaveBeenCalledTimes(1)
const expectedObj = {
artifactsFolder: 'app-package',
appConfig: expect.any(Object)
}
expect(runHook).toHaveBeenCalledWith('pre-pack', expectedObj)
expect(runHook).toHaveBeenCalledWith('post-pack', expectedObj)
})

const command = new TheCommand()
command.argv = []
test('subcommand throws error (--verbose)', async () => {
mockGetFullConfig.mockImplementation(() => fixtureJson('pack/1.all.config.json'))

// since we already unit test the methods above, we mock it here
command.copyPackageFiles = jest.fn()
command.filesToPack = jest.fn()
command.createDeployYamlFile = jest.fn()
command.addCodeDownloadAnnotation = jest.fn()
command.zipHelper = jest.fn()
const runHook = jest.fn()
command.config = { runHook }
await command.run()

expect(command.copyPackageFiles).toHaveBeenCalledTimes(1)
expect(command.filesToPack).toHaveBeenCalledTimes(1)
expect(command.createDeployYamlFile).toHaveBeenCalledTimes(1)
expect(command.addCodeDownloadAnnotation).toHaveBeenCalledTimes(1)
expect(command.zipHelper).toHaveBeenCalledTimes(1)
const expectedObj = {
artifactsFolder: 'app-package',
appConfig: expect.any(Object)
}
expect(runHook).toHaveBeenCalledWith('pre-pack', expectedObj)
expect(runHook).toHaveBeenCalledWith('post-pack', expectedObj)
})
const command = new TheCommand()
command.argv = ['--verbose']

test('run (coverage: output flag, path arg)', async () => {
mockGetFullConfig.mockImplementation(() => fixtureJson('pack/1.all.config.json'))
const errorObject = new Error('zip error')

const command = new TheCommand()
command.argv = ['new_folder', '--output', 'app-2.zip']

// since we already unit test the methods above, we mock it here
command.copyPackageFiles = jest.fn()
command.filesToPack = jest.fn()
command.createDeployYamlFile = jest.fn()
command.addCodeDownloadAnnotation = jest.fn()
command.zipHelper = jest.fn()
const runHook = jest.fn()
command.config = { runHook }

await command.run()

expect(command.copyPackageFiles).toHaveBeenCalledTimes(1)
expect(command.filesToPack).toHaveBeenCalledTimes(1)
expect(command.createDeployYamlFile).toHaveBeenCalledTimes(1)
expect(command.addCodeDownloadAnnotation).toHaveBeenCalledTimes(1)
expect(command.zipHelper).toHaveBeenCalledTimes(1)

const expectedObj = {
artifactsFolder: 'app-package',
appConfig: expect.any(Object)
}
expect(runHook).toHaveBeenCalledWith('pre-pack', expectedObj)
expect(runHook).toHaveBeenCalledWith('post-pack', expectedObj)
// since we already unit test the methods above, we mock it here
command.copyPackageFiles = jest.fn()
command.filesToPack = jest.fn()
command.createDeployYamlFile = jest.fn()
command.addCodeDownloadAnnotation = jest.fn()
command.zipHelper = jest.fn(() => { throw errorObject })
command.error = jest.fn()
const runHook = jest.fn()
command.config = { runHook }

await command.run()

expect(command.copyPackageFiles).toHaveBeenCalledTimes(1)
expect(command.filesToPack).toHaveBeenCalledTimes(1)
expect(command.createDeployYamlFile).toHaveBeenCalledTimes(1)
expect(command.addCodeDownloadAnnotation).toHaveBeenCalledTimes(1)
expect(command.zipHelper).toHaveBeenCalledTimes(1)
expect(command.error).toHaveBeenCalledTimes(1)

const expectedObj = {
artifactsFolder: 'app-package',
appConfig: expect.any(Object)
}
expect(runHook).toHaveBeenCalledWith('pre-pack', expectedObj)
expect(runHook).toHaveBeenCalledWith('post-pack', expectedObj)
expect(command.error).toHaveBeenCalledWith(errorObject)
})

test('subcommand throws error (not verbose)', async () => {
mockGetFullConfig.mockImplementation(() => fixtureJson('pack/1.all.config.json'))

const command = new TheCommand()
command.argv = []

const errorMessage = 'zip error'

// since we already unit test the methods above, we mock it here
command.copyPackageFiles = jest.fn()
command.filesToPack = jest.fn()
command.createDeployYamlFile = jest.fn()
command.addCodeDownloadAnnotation = jest.fn()
command.zipHelper = jest.fn(() => { throw new Error(errorMessage) })
command.error = jest.fn()
const runHook = jest.fn()
command.config = { runHook }

await command.run()

expect(command.copyPackageFiles).toHaveBeenCalledTimes(1)
expect(command.filesToPack).toHaveBeenCalledTimes(1)
expect(command.createDeployYamlFile).toHaveBeenCalledTimes(1)
expect(command.addCodeDownloadAnnotation).toHaveBeenCalledTimes(1)
expect(command.zipHelper).toHaveBeenCalledTimes(1)
expect(command.error).toHaveBeenCalledTimes(1)

const expectedObj = {
artifactsFolder: 'app-package',
appConfig: expect.any(Object)
}
expect(runHook).toHaveBeenCalledWith('pre-pack', expectedObj)
expect(runHook).toHaveBeenCalledWith('post-pack', expectedObj)
expect(command.error).toHaveBeenCalledWith(errorMessage)
})

test('output flag, path arg', async () => {
mockGetFullConfig.mockImplementation(() => fixtureJson('pack/1.all.config.json'))

const command = new TheCommand()
command.argv = ['new_folder', '--output', 'app-2.zip']

// since we already unit test the methods above, we mock it here
command.copyPackageFiles = jest.fn()
command.filesToPack = jest.fn()
command.createDeployYamlFile = jest.fn()
command.addCodeDownloadAnnotation = jest.fn()
command.zipHelper = jest.fn()
const runHook = jest.fn()
command.config = { runHook }

await command.run()

expect(command.copyPackageFiles).toHaveBeenCalledTimes(1)
expect(command.filesToPack).toHaveBeenCalledTimes(1)
expect(command.createDeployYamlFile).toHaveBeenCalledTimes(1)
expect(command.addCodeDownloadAnnotation).toHaveBeenCalledTimes(1)
expect(command.zipHelper).toHaveBeenCalledTimes(1)

const expectedObj = {
artifactsFolder: 'app-package',
appConfig: expect.any(Object)
}
expect(runHook).toHaveBeenCalledWith('pre-pack', expectedObj)
expect(runHook).toHaveBeenCalledWith('post-pack', expectedObj)
})
})

0 comments on commit e44de8c

Please sign in to comment.