UNPKG

@artilleryio/platform-fargate

Version:
225 lines (186 loc) 6.3 kB
'use strict'; const A = require('async'); const debug = require('debug')('commands:create-test'); const uuid = require('uuid'); const { S3_BUCKET_NAME_PREFIX } = require('../constants'); const util = require('../util'); const { getBucketName } = require('../util'); const createS3Client = require('../utils/create-s3-client'); const setDefaultAWSCredentials = require('../utils/aws-set-default-credentials'); const path = require('path'); const fs = require('fs'); const _ = require('lodash'); const YAML = require('yaml-js'); const chalk = require('chalk'); const { createBOM, prettyPrint } = require('../bom'); function tryCreateTest(scriptPath, options) { createTest(scriptPath, options); } async function createTest(scriptPath, options, callback) { const absoluteScriptPath = path.resolve(process.cwd(), scriptPath); const contextPath = options.context ? path.resolve(options.context) : path.dirname(absoluteScriptPath); debug('script:', absoluteScriptPath); debug('root:', contextPath); let context = { contextDir: contextPath, scriptPath: absoluteScriptPath, originalScriptPath: scriptPath, name: options.name, // test name, eg simple-bom or aht_$UUID manifestPath: options.manifestPath, packageJsonPath: options.packageJsonPath, }; if (typeof options.config === 'string') { const absoluteConfigPath = path.resolve(process.cwd(), options.config); context.configPath = absoluteConfigPath; } // If we have a callback we were called from another command: if (!callback) { if (typeof context.name !== 'string') { // FIXME: not sure why it happens, but if --name not given interactively, its value is set to a Function console.log(util.formatError(new Error('A test name must be provided with the --name option'))); process.exit(1); } console.log(`Creating named test ${chalk.blue(context.name)}\n`); } await setDefaultAWSCredentials(); A.waterfall( [ A.constant(context), async function(context) { context.s3Bucket = await getBucketName(); return context; }, prepareManifest, printManifest, syncS3, writeTestMetadata ], function(err, context) { if (err) { console.log(err); return; } // If we have a callback we were called from another command: if (callback) { callback(err, context); } else { // TODO: How does one wrap the text automatically depending on terminal width? console.log(`\nTest ${chalk.blue(context.name)} has been created. You can now use the name of the test as an argument for artillery run-test`); } }); } function prepareManifest(context, callback) { let includeFiles; let fileToAnalyse = context.scriptPath; let extraFiles = []; if (context.configPath) { debug('context has been provided; extraFiles =', extraFiles); fileToAnalyse = context.configPath; extraFiles.push(context.scriptPath); } createBOM(fileToAnalyse, extraFiles, {packageJsonPath: context.packageJsonPath}, (err, bom) => { debug(err); debug(bom); context.manifest = bom; return callback(err, context); }); } function printManifest(context, callback) { prettyPrint(context.manifest); return callback(null, context); } function syncS3(context, callback) { const plainS3 = createS3Client(); const prefix = `tests/${context.name}`; context.s3Prefix = prefix; debug('Will try syncing to:', context.s3Bucket); debug('Manifest: ', context.manifest); // Iterate through manifest, for each element: has orig (local source) and noPrefix (S3 // destination) properties A.eachLimit( context.manifest.files, 3, (item, eachDone) => { // If we can't read the file, it may have been specified with a // template in its name, e.g. a payload file like: // {{ $environment }}-users.csv // If so, ignore it, hope config.includeFiles was used, and let // "artillery run" in the worker deal with it. let body; try { body = fs.readFileSync(item.orig); } catch (fsErr) { debug(fsErr); } if (!body) { return eachDone(null, context); } const key = context.s3Prefix + '/' + item.noPrefix; // root for a9 command is s3Prefix? yes. plainS3.putObject( { Bucket: context.s3Bucket, Key: key, // TODO: stream, not readFileSync Body: body }, (s3Err, s3Resp) => { if (s3Err) { // TODO: retry - see async#retry return eachDone(s3Err, context); } debug(`Uploaded ${key}`); return eachDone(null, context); } ); }, (bomUploadErr) => { return callback(bomUploadErr, context); }); } // create just overwrites an existing test for now function writeTestMetadata(context, callback) { const metadata = { createdOn: Date.now(), // createdBy: 'username', name: context.name, // scriptPath: context.newScriptPath, modules: context.manifest.modules }; // Here we need to provide config information (if given) -- so that the worker knows how to load it. if (context.configPath) { const res = context.manifest.files.filter((o) => { return o.orig === context.configPath; }); const newConfigPath = res[0].noPrefix; // if we have been given a config, we must have an entry metadata.configPath = newConfigPath; } const newScriptPath = (context.manifest.files.filter((o) => { return o.orig === context.scriptPath; }))[0].noPrefix; metadata.scriptPath = newScriptPath; debug('metadata', metadata); const s3 = createS3Client(); const key = context.s3Prefix + '/metadata.json'; // TODO: Rename to something less likely to clash debug('metadata location:', `${context.s3Bucket}/${key}`); s3.putObject( { Body: JSON.stringify(metadata), Bucket: context.s3Bucket, Key: key }, function(s3Err, s3Resp) { if (s3Err) { // TODO: probably delete the S3 dir return callback(s3Err, context); } return callback(null, context); }); } module.exports = { tryCreateTest, createTest, syncS3, prepareManifest };