artillery
Version:
Cloud-scale load testing. https://www.artillery.io
240 lines (205 loc) • 6.07 kB
JavaScript
;
const A = require('async');
const debug = require('debug')('commands:create-test');
const util = require('./util');
const { getBucketName } = require('./util');
const createS3Client = require('./create-s3-client');
const setDefaultAWSCredentials = require('../../aws/aws-set-default-credentials');
const path = require('path');
const fs = require('fs');
const _ = require('lodash');
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,
flags: options.flags
};
if (typeof options.config === 'string') {
const absoluteConfigPath = path.resolve(process.cwd(), options.config);
context.configPath = absoluteConfigPath;
}
if (options.customSyncClient) {
context.customSyncClient = options.customSyncClient;
}
if (!options.customSyncClient) {
await setDefaultAWSCredentials();
}
return new Promise((resolve, reject) => {
A.waterfall(
[
A.constant(context),
async function (context) {
if (!context.customSyncClient) {
context.s3Bucket = await getBucketName();
return context;
} else {
context.s3Bucket = 'S3_BUCKET_ARGUMENT_NOT_USED_ON_AZURE';
return context;
}
},
prepareManifest,
printManifest,
syncS3,
writeTestMetadata
],
function (err, context) {
if (err) {
console.log(err);
return;
}
if (callback) {
callback(err, context);
} else if (err) {
reject(err);
} else {
resolve(context);
}
}
);
});
}
function prepareManifest(context, callback) {
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,
flags: context.flags,
scenarioPath: context.scriptPath
},
(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) {
let plainS3;
if (context.customSyncClient) {
plainS3 = context.customSyncClient;
} else {
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.noPrefixPosix;
plainS3.putObject(
{
Bucket: context.s3Bucket,
Key: key,
// TODO: stream, not readFileSync
Body: body
},
(s3Err, s3Resp) => {
if (s3Err) {
// TODO: retry if needed
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(),
name: context.name,
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].noPrefixPosix; // 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].noPrefixPosix;
metadata.scriptPath = newScriptPath;
debug('metadata', metadata);
let s3 = null;
if (context.customSyncClient) {
s3 = context.customSyncClient;
} else {
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) {
return callback(s3Err, context);
}
return callback(null, context);
}
);
}
module.exports = {
tryCreateTest,
createTest,
syncS3,
prepareManifest
};