diff --git a/.github/workflows/docker-ecs-worker-image.yml b/.github/workflows/docker-ecs-worker-image.yml index c046bf46d8..979a6eda7d 100644 --- a/.github/workflows/docker-ecs-worker-image.yml +++ b/.github/workflows/docker-ecs-worker-image.yml @@ -60,7 +60,7 @@ jobs: - name: Build the Docker image run: | - docker build . --build-arg="WORKER_VERSION=${{ env.WORKER_VERSION }}" --tag public.ecr.aws/d8a4z9o5/artillery-worker:${{ env.WORKER_VERSION }} -f ./packages/artillery/lib/platform/aws-ecs/worker/Dockerfile + docker build . --build-arg="WORKER_VERSION=${{ env.WORKER_VERSION }}" --tag public.ecr.aws/d8a4z9o5/artillery-worker:${{ env.WORKER_VERSION }} -f ./packages/artillery/lib/platform/aws-lambda/lambda-handler/Dockerfile - name: Push Docker image run: | diff --git a/packages/artillery/lib/platform/aws-lambda/create-test.js b/packages/artillery/lib/platform/aws-lambda/create-test.js new file mode 100644 index 0000000000..6b222c9255 --- /dev/null +++ b/packages/artillery/lib/platform/aws-lambda/create-test.js @@ -0,0 +1,142 @@ +const { promisify } = require('node:util'); +const { createBOM } = require('../../create-bom/create-bom'); +const createS3Client = require('../aws-ecs/legacy/create-s3-client'); +const debug = require('debug')('aws:lambda'); +const Table = require('cli-table3'); +const fs = require('fs'); + +const prepareManifest = async (absoluteScriptPath, absoluteConfigPath) => { + let createBomOpts = {}; + let entryPoint = absoluteScriptPath; + let extraFiles = []; + if (absoluteConfigPath) { + entryPoint = absoluteConfigPath; + extraFiles.push(absoluteScriptPath); + createBomOpts.entryPointIsConfig = true; + } + // TODO: custom package.json path here + + // artillery.log('- Bundling test data'); + const bom = await promisify(createBOM)(entryPoint, extraFiles, createBomOpts); + + return bom; +}; + +const prettyPrintManifest = (bomManifest) => { + artillery.logger({ showTimestamp: true }).log('Test bundle prepared...'); + artillery.log('Test bundle contents:'); + const t = new Table({ head: ['Name', 'Type', 'Notes'] }); + for (const f of bomManifest.files) { + t.push([f.noPrefix, 'file']); + } + for (const m of bomManifest.modules) { + t.push([ + m, + 'package', + bomManifest.pkgDeps.indexOf(m) === -1 ? 'not in package.json' : '' + ]); + } + artillery.log(t.toString()); + artillery.log(); +}; + +async function uploadFileToS3(item, testRunId, bucketName) { + const plainS3 = createS3Client(); + const prefix = `tests/${testRunId}`; + // 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) { + console.log(fsErr); + } + + if (!body) { + return; + } + + const key = prefix + '/' + item.noPrefix; + + try { + await plainS3.putObject({ + Bucket: bucketName, + Key: key, + // TODO: stream, not readFileSync + Body: body + }).promise(); + + console.log(`Uploaded ${key}`); + return; + } catch (err) { + //TODO: retry if needed + console.log(err); + return; + } +} + +async function syncS3(bomManifest, testRunId, bucketName) { + console.log('Will try syncing to:', bucketName); + + console.log('Manifest: ', bomManifest); + const metadata = { + createdOn: Date.now(), + name: testRunId, + modules: bomManifest.modules + }; + + //TODO: parallelise this + for (const file of bomManifest.files) { + console.log(`STARTING ON FILE:`) + console.log(file) + await uploadFileToS3(file, testRunId, bucketName); + } + + const plainS3 = createS3Client(); + const prefix = `tests/${testRunId}`; + + console.log(bucketName) + console.log(prefix) + + //TODO: add writeTestMetadata with configPath and newScriptPath if needed + try { + const key = prefix + '/metadata.json'; + await plainS3.putObject({ + Bucket: bucketName, + Key: key, + // TODO: stream, not readFileSync + Body: JSON.stringify(metadata) + }).promise(); + + console.log(`Uploaded ${key}`); + return; + } catch (err) { + //TODO: retry if needed + debug(err); + return; + } + +} + +const createTest = async ( + absoluteScriptPath, + absoluteConfigPath, + testRunId, + bucketName +) => { + const bom = await prepareManifest(absoluteScriptPath, absoluteConfigPath); + + prettyPrintManifest(bom); + console.log(bom) + + await syncS3(bom, testRunId, bucketName); + + return bom; +}; + +module.exports = { + createTest +}; diff --git a/packages/artillery/lib/platform/aws-lambda/index.js b/packages/artillery/lib/platform/aws-lambda/index.js index 03aefd1e78..9abbb21517 100644 --- a/packages/artillery/lib/platform/aws-lambda/index.js +++ b/packages/artillery/lib/platform/aws-lambda/index.js @@ -22,10 +22,9 @@ const https = require('https'); const { QueueConsumer } = require('../../queue-consumer'); -const { createBOM } = require('../../create-bom/create-bom'); +const { createTest } = require('./create-test'); const setDefaultAWSCredentials = require('../aws/aws-set-default-credentials'); -const { promisify } = require('node:util'); const telemetry = require('../../telemetry').init(); const crypto = require('node:crypto'); @@ -120,22 +119,16 @@ class PlatformLambda { await setDefaultAWSCredentials(AWS); this.accountId = await getAccountId(); + const bucketName = await ensureS3BucketExists( + this.region, + this.s3LifecycleConfigurationRules + ); + this.bucketName = bucketName; const dirname = temp.mkdirSync(); // TODO: May want a way to override this by the user const zipfile = temp.path({ suffix: '.zip' }); - debug({ dirname, zipfile }); - - let createBomOpts = {}; - let entryPoint = this.opts.absoluteScriptPath; - let extraFiles = []; - if (this.opts.absoluteConfigPath) { - entryPoint = this.opts.absoluteConfigPath; - extraFiles.push(this.opts.absoluteScriptPath); - createBomOpts.entryPointIsConfig = true; - } - // TODO: custom package.json path here - + console.log({ dirname, zipfile }); const metadata = { region: this.region, platformConfig: { @@ -145,39 +138,39 @@ class PlatformLambda { }; global.artillery.globalEvents.emit('metadata', metadata); - artillery.log('- Bundling test data'); - const bom = await promisify(createBOM)( - entryPoint, - extraFiles, - createBomOpts - ); - for (const f of bom.files) { - artillery.log(' -', f.noPrefix); - } + const bom = await createTest(this.opts.absoluteScriptPath, this.opts.absoluteConfigPath, this.testRunId, this.bucketName); + // process.exit(1); + + // process.exit(1); // Copy handler: - fs.copyFileSync( - path.resolve(__dirname, 'lambda-handler', 'index.js'), - path.join(dirname, 'index.js') - ); - fs.copyFileSync( - path.resolve(__dirname, 'lambda-handler', 'package.json'), - path.join(dirname, 'package.json') - ); + // fs.copyFileSync( + // path.resolve(__dirname, 'lambda-handler', 'index.js'), + // path.join(dirname, 'index.js') + // ); + // fs.copyFileSync( + // path.resolve(__dirname, 'lambda-handler', 'package.json'), + // path.join(dirname, 'package.json') + // ); // FIXME: This may overwrite lambda-handler's index.js or package.json // Copy files that make up the test: - for (const o of bom.files) { - fs.ensureFileSync(path.join(dirname, o.noPrefix)); - fs.copyFileSync(o.orig, path.join(dirname, o.noPrefix)); - } - - if (this.platformOpts.cliArgs.dotenv) { - fs.copyFileSync( - path.resolve(process.cwd(), this.platformOpts.cliArgs.dotenv), - path.join(dirname, path.basename(this.platformOpts.cliArgs.dotenv)) - ); - } + // for (const o of bom.files) { + // if (o.noPrefix.includes(`package.json`)) { + // continue; + // } + // console.log(`Copying ${o.orig} to ${path.join(dirname, o.noPrefix)}`) + // fs.ensureFileSync(path.join(dirname, o.noPrefix)); + // fs.copyFileSync(o.orig, path.join(dirname, o.noPrefix)); + // } + + //TODO: account for dotenv + // if (this.platformOpts.cliArgs.dotenv) { + // fs.copyFileSync( + // path.resolve(process.cwd(), this.platformOpts.cliArgs.dotenv), + // path.join(dirname, path.basename(this.platformOpts.cliArgs.dotenv)) + // ); + // } this.artilleryArgs.push('run'); @@ -228,116 +221,111 @@ class PlatformLambda { )[0]; this.artilleryArgs.push(p.noPrefix); - artillery.log('- Installing dependencies'); - const { stdout, stderr, status, error } = spawn.sync( - 'npm', - ['install', '--omit', 'dev'], - { - cwd: dirname - } - ); - - if (error) { - artillery.log(stdout?.toString(), stderr?.toString(), status, error); - } else { - // artillery.log(' npm log is in:', temp.path({suffix: '.log'})); - } - - // Install extra plugins & engines - if (bom.modules.length > 0) { - artillery.log( - `- Installing extra engines & plugins: ${bom.modules.join(', ')}` - ); - const { stdout, stderr, status, error } = spawn.sync( - 'npm', - ['install'].concat(bom.modules), - { cwd: dirname } - ); - if (error) { - artillery.log(stdout?.toString(), stderr?.toString(), status, error); - } - } - - // Copy this version of Artillery into the Lambda package - const a9basepath = path.resolve(__dirname, '..', '..', '..'); - // TODO: read this from .files in package.json instead: - for (const dir of ['bin', 'lib']) { - const destdir = path.join(dirname, 'node_modules', 'artillery', dir); - const srcdir = path.join(a9basepath, dir); - fs.ensureDirSync(destdir); - fs.copySync(srcdir, destdir); - } - for (const fn of ['console-reporter.js', 'util.js']) { - const destfn = path.join(dirname, 'node_modules', 'artillery', fn); - const srcfn = path.join(a9basepath, fn); - fs.copyFileSync(srcfn, destfn); - } - - fs.copyFileSync( - path.resolve(a9basepath, 'package.json'), - path.join(dirname, 'node_modules', 'artillery', 'package.json') - ); - - const a9cwd = path.join(dirname, 'node_modules', 'artillery'); - debug({ a9basepath, a9cwd }); - - const { - stdout: stdout2, - stderr: stderr2, - status: status2, - error: error2 - } = spawn.sync('npm', ['install', '--omit', 'dev'], { cwd: a9cwd }); - if (error2) { - artillery.log(stdout2?.toString(), stderr2?.toString(), status2, error2); - } else { - // artillery.log(' npm log is in:', temp.path({suffix: '.log'})); - } - - const { - stdout: stdout3, - stderr: stderr3, - status: status3, - error: error3 - } = spawn.sync( - 'npm', - [ - 'uninstall', - 'dependency-tree', - 'detective', - 'is-builtin-module', - 'try-require', - 'walk-sync', - 'esbuild-wasm', - 'artillery-plugin-publish-metrics' - ], - { - cwd: a9cwd - } - ); - if (error3) { - artillery.log(stdout3?.toString(), stderr3?.toString(), status3, error3); - } else { - // artillery.log(' npm log is in:', temp.path({suffix: '.log'})); - } - - fs.removeSync(path.join(dirname, 'node_modules', 'aws-sdk')); - fs.removeSync(path.join(a9cwd, 'node_modules', 'typescript')); - fs.removeSync(path.join(a9cwd, 'node_modules', 'tap')); - fs.removeSync(path.join(a9cwd, 'node_modules', 'prettier')); - - artillery.log('- Creating zip package'); - await this.createZip(dirname, zipfile); - - artillery.log('Preparing AWS environment...'); - const bucketName = await ensureS3BucketExists( - this.region, - this.s3LifecycleConfigurationRules - ); - this.bucketName = bucketName; - - const s3path = await this.uploadLambdaZip(bucketName, zipfile); - debug({ s3path }); - this.lambdaZipPath = s3path; + // artillery.log('- Installing dependencies'); + // const { stdout, stderr, status, error } = spawn.sync( + // 'npm', + // ['install', '--omit', 'dev'], + // { + // cwd: dirname + // } + // ); + + // if (error) { + // artillery.log(stdout?.toString(), stderr?.toString(), status, error); + // } else { + // // artillery.log(' npm log is in:', temp.path({suffix: '.log'})); + // } + + // // Install extra plugins & engines + // if (bom.modules.length > 0) { + // artillery.log( + // `- Installing extra engines & plugins: ${bom.modules.join(', ')}` + // ); + // const { stdout, stderr, status, error } = spawn.sync( + // 'npm', + // ['install'].concat(bom.modules), + // { cwd: dirname } + // ); + // if (error) { + // artillery.log(stdout?.toString(), stderr?.toString(), status, error); + // } + // } + + // // Copy this version of Artillery into the Lambda package + // const a9basepath = path.resolve(__dirname, '..', '..', '..'); + // // TODO: read this from .files in package.json instead: + // for (const dir of ['bin', 'lib']) { + // const destdir = path.join(dirname, 'node_modules', 'artillery', dir); + // const srcdir = path.join(a9basepath, dir); + // fs.ensureDirSync(destdir); + // fs.copySync(srcdir, destdir); + // } + // for (const fn of ['console-reporter.js', 'util.js']) { + // const destfn = path.join(dirname, 'node_modules', 'artillery', fn); + // const srcfn = path.join(a9basepath, fn); + // fs.copyFileSync(srcfn, destfn); + // } + + // fs.copyFileSync( + // path.resolve(a9basepath, 'package.json'), + // path.join(dirname, 'node_modules', 'artillery', 'package.json') + // ); + + // const a9cwd = path.join(dirname, 'node_modules', 'artillery'); + // debug({ a9basepath, a9cwd }); + + // const { + // stdout: stdout2, + // stderr: stderr2, + // status: status2, + // error: error2 + // } = spawn.sync('npm', ['install', '--omit', 'dev'], { cwd: a9cwd }); + // if (error2) { + // artillery.log(stdout2?.toString(), stderr2?.toString(), status2, error2); + // } else { + // // artillery.log(' npm log is in:', temp.path({suffix: '.log'})); + // } + + // const { + // stdout: stdout3, + // stderr: stderr3, + // status: status3, + // error: error3 + // } = spawn.sync( + // 'npm', + // [ + // 'uninstall', + // 'dependency-tree', + // 'detective', + // 'is-builtin-module', + // 'try-require', + // 'walk-sync', + // 'esbuild-wasm', + // 'artillery-plugin-publish-metrics' + // ], + // { + // cwd: a9cwd + // } + // ); + // if (error3) { + // artillery.log(stdout3?.toString(), stderr3?.toString(), status3, error3); + // } else { + // // artillery.log(' npm log is in:', temp.path({suffix: '.log'})); + // } + + // fs.removeSync(path.join(dirname, 'node_modules', 'aws-sdk')); + // fs.removeSync(path.join(a9cwd, 'node_modules', 'typescript')); + // fs.removeSync(path.join(a9cwd, 'node_modules', 'tap')); + // fs.removeSync(path.join(a9cwd, 'node_modules', 'prettier')); + + // artillery.log('- Creating zip package'); + // await this.createZip(dirname, zipfile); + + // artillery.log('Preparing AWS environment...'); + + // const s3path = await this.uploadLambdaZip(bucketName, zipfile); + // debug({ s3path }); + // this.lambdaZipPath = s3path; // 36 is length of a UUUI v4 string const queueName = `${SQS_QUEUES_NAME_PREFIX}_${this.testRunId.slice( @@ -549,6 +537,8 @@ class PlatformLambda { BUCKET: this.bucketName, WAIT_FOR_GREEN: true }; + console.log(event) + // process.exit(1) debug('Lambda event payload:'); debug({ event }); @@ -752,20 +742,38 @@ class PlatformLambda { region: this.region }); + // const lambdaConfig = { + // Code: { + // S3Bucket: bucketName, + // S3Key: zipPath + // }, + // FunctionName: functionName, + // Description: 'Artillery.io test', + // Handler: 'index.handler', + // MemorySize: this.memorySize, + // PackageType: 'Zip', + // Runtime: 'nodejs16.x', + // Architectures: [this.architecture], + // Timeout: 900, + // Role: this.lambdaRoleArn + // }; + const lambdaConfig = { + PackageType: 'Image', Code: { - S3Bucket: bucketName, - S3Key: zipPath + ImageUri: 'URL_TO_ADD' }, FunctionName: functionName, Description: 'Artillery.io test', - Handler: 'index.handler', MemorySize: this.memorySize, - PackageType: 'Zip', - Runtime: 'nodejs16.x', - Architectures: [this.architecture], + PackageType: 'Image', Timeout: 900, - Role: this.lambdaRoleArn + Role: this.lambdaRoleArn, + Environment: { + Variables: { + S3_BUCKET_PATH: this.bucketName, + } + } }; if (this.securityGroupIds.length > 0 && this.subnetIds.length > 0) { @@ -775,23 +783,23 @@ class PlatformLambda { }; } - await lambda.createFunction(lambdaConfig).promise(); + await lambda.createFunction({ Environment: {}}).promise(); } - async uploadLambdaZip(bucketName, zipfile) { - const key = `lambda/${randomUUID()}.zip`; - // TODO: Set lifecycle policy on the bucket/key prefix to delete after 24 hours - const s3 = new AWS.S3(); - const s3res = await s3 - .putObject({ - Body: fs.createReadStream(zipfile), - Bucket: bucketName, - Key: key - }) - .promise(); - - return key; - } + // async uploadLambdaZip(bucketName, zipfile) { + // const key = `lambda/${randomUUID()}.zip`; + // // TODO: Set lifecycle policy on the bucket/key prefix to delete after 24 hours + // const s3 = new AWS.S3(); + // const s3res = await s3 + // .putObject({ + // Body: fs.createReadStream(zipfile), + // Bucket: bucketName, + // Key: key + // }) + // .promise(); + + // return key; + // } } module.exports = PlatformLambda; diff --git a/packages/artillery/lib/platform/aws-lambda/lambda-handler/Dockerfile b/packages/artillery/lib/platform/aws-lambda/lambda-handler/Dockerfile new file mode 100644 index 0000000000..c3fc1d6866 --- /dev/null +++ b/packages/artillery/lib/platform/aws-lambda/lambda-handler/Dockerfile @@ -0,0 +1,54 @@ +FROM mcr.microsoft.com/playwright:v1.42.1-focal as build-image + +# https://steele.blue/playwright-on-lambda/ +# https://blog.carlosnunez.me/post/scraping-chromium-lambda-nodeless-zerostress/ + +ENV DEBIAN_FRONTEND=noninteractive + +# Install aws-lambda-ric build dependencies +RUN apt-get update && apt-get install -y \ + g++ \ + make \ + cmake \ + unzip \ + libcurl4-openssl-dev \ + autoconf \ + libtool + +# Define custom function directory +ARG FUNCTION_DIR="/function" +# Create function dir and install node packages +RUN mkdir -p ${FUNCTION_DIR} + +WORKDIR ${FUNCTION_DIR} + +# COPY ./index.js . +# COPY ./dependencies.js . +# COPY ./package.json . + +COPY package.json package.json +COPY packages packages +COPY packages/artillery/lib/platform/aws-lambda/lambda-handler/index.js index.js +# COPY packages/artillery/lib/platform/aws-lambda/lambda-handler/dependencies.js dependencies.js +COPY packages/artillery/lib/platform/aws-lambda/lambda-handler/entrypoint.sh entrypoint.sh + +RUN npm install -w artillery --ignore-scripts --omit=dev +RUN npm install aws-lambda-ric +RUN npm install artillery-plugin-sqs-reporter +# RUN npm run build +# RUN npm install -w artillery --ignore-scripts --omit=dev + +RUN npm cache clean --force \ + && rm -rf /root/.cache \ + && ln -s /function/node_modules/.bin/artillery /usr/local/bin/artillery \ + && rm -rf /ms-playwright/firefox* \ + && rm -rf /ms-playwright/webkit* \ + && echo "ok" + +# COPY ./entrypoint.sh /entry_script.sh +RUN chmod +x ./entrypoint.sh +ADD aws-lambda-rie /usr/local/bin/aws-lambda-rie +ENTRYPOINT [ "./entrypoint.sh", "index.handler" ] + +# ENTRYPOINT ["/usr/local/bin/npx", "aws-lambda-ric"] +# CMD ["index.handler"] \ No newline at end of file diff --git a/packages/artillery/lib/platform/aws-lambda/lambda-handler/entrypoint.sh b/packages/artillery/lib/platform/aws-lambda/lambda-handler/entrypoint.sh new file mode 100644 index 0000000000..5fb4984e52 --- /dev/null +++ b/packages/artillery/lib/platform/aws-lambda/lambda-handler/entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then + # exec /usr/local/bin/aws-lambda-rie /usr/bin/npx aws-lambda-ric $1 +# else +exec /usr/bin/npx aws-lambda-ric $1 +# fi \ No newline at end of file diff --git a/packages/artillery/lib/platform/aws-lambda/lambda-handler/index.js b/packages/artillery/lib/platform/aws-lambda/lambda-handler/index.js index bd033be5b9..1369ef4019 100644 --- a/packages/artillery/lib/platform/aws-lambda/lambda-handler/index.js +++ b/packages/artillery/lib/platform/aws-lambda/lambda-handler/index.js @@ -3,11 +3,85 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const AWS = require('aws-sdk'); -const { spawn } = require('node:child_process'); +const { spawn, spawnSync } = require('node:child_process'); const { randomUUID } = require('node:crypto'); +const path = require('path'); +const fs = require('fs'); +// const npm = require('npm'); +const util = require('util'); +// const { syncTestData } = require('./dependencies') const TIMEOUT_THRESHOLD_MSEC = 20 * 1000; +const syncTestData = async (bucketName, testRunId) => { + // const REMOTE_TEST_DATA_PATH = `${bucketName}/tests/${testRunId}`; + + //use aws s3 sync with child process + const LOCAL_TEST_DATA_PATH = `/tmp/test_data/${testRunId}`; + + // const sync = spawn('aws', ['s3', 'sync', `s3://${REMOTE_TEST_DATA_PATH}`, LOCAL_TEST_DATA_PATH]); + + // //console.log files in directory LOCAL_TEST_DATA_PATH + // const ls = spawn('ls', [LOCAL_TEST_DATA_PATH]); + // ls.stdout.on('data', (data) => { + // console.log(`FILES:`) + // console.log(`stdout: ${data}`); + // }); + const s3 = new AWS.S3(); + const params = { + Bucket: bucketName, + Prefix: `tests/${testRunId}` + }; + const data = await s3.listObjectsV2(params).promise(); + + if (!fs.existsSync(LOCAL_TEST_DATA_PATH)) { + fs.mkdirSync(LOCAL_TEST_DATA_PATH, { recursive: true }) + } + + + //TODO : review why I didn't use s3 sync here? I think it was because aws cli wasnt available in the env at the time + for (const file of data.Contents) { + const params = { + Bucket: bucketName, + Key: file.Key + }; + const data = await s3.getObject(params).promise(); + const pathFile = path.basename(file.Key); + const localPath = `${LOCAL_TEST_DATA_PATH}/${pathFile}`; + + console.log(`CWD IS`) + console.log(process.cwd()); + console.log('LOCAL PATH IS'); + console.log(localPath); + fs.writeFileSync(`${LOCAL_TEST_DATA_PATH}/${pathFile}`, data.Body); + } + + for (const file of fs.readdirSync(LOCAL_TEST_DATA_PATH)) { + console.log(file); +} +}; + +const installNpmDependencies = async (testDataLocation) => { + process.chdir(testDataLocation); + + + // install using spawn npm + console.log("TRYING SPAWN SYNC") + + const res = await runProcess('npm', ['install', '--prefix', testDataLocation], { log: true, env: { + HOME: testDataLocation, + } }); + + console.log(`FINISHED WITH NPM DEPS`) + console.log(res) + + for (const file of fs.readdirSync(testDataLocation)) { + console.log(file); + } + + // process.chdir(originalDir); +} + class MQ { constructor({ region, queueUrl, attrs } = opts) { this.sqs = new AWS.SQS({ region }); @@ -58,6 +132,17 @@ async function handler(event, context) { workerId: WORKER_ID } }); + const TEST_DATA_LOCATION = `/tmp/test_data/${TEST_RUN_ID}` + + console.log('Syncing test data'); + await syncTestData(BUCKET, TEST_RUN_ID); + + console.log('Test data synced'); + + await installNpmDependencies(TEST_DATA_LOCATION); + console.log(`finished installing test data`) + + const interval = setInterval(async () => { const timeRemaining = context.getRemainingTimeInMillis(); @@ -99,15 +184,42 @@ async function handler(event, context) { } } + const currentPath = process.cwd(); + console.log(`CURRENT PATH`) + console.log(currentPath) + + console.log("FILES HERE:") + for (const file of fs.readdirSync(currentPath)) { + console.log(file); + } + try { - const { err, code, stdout, stderr } = await execArtillery({ + console.log(`ARTILLERY ARGS`) + console.log(ARTILLERY_ARGS) + const res = await execArtillery({ SQS_QUEUE_URL, SQS_REGION, TEST_RUN_ID, WORKER_ID, ARTILLERY_ARGS, - ENV + ENV, + TEST_DATA_LOCATION }); + console.log(`ERROR IS:`) + console.log(res.err) + console.log(`CODE IS:`) + console.log(res.code) + console.log(`STDOUT IS:`) + console.log(res.stdout) + console.log(`STDERR IS:`) + console.log(res.stderr) + console.log(`fULL res`) + console.log(res) + + if (res.err) { + console.log(`throwing err`) + throw res.err; + } if (err || code !== 0) { console.log(err); @@ -118,6 +230,7 @@ async function handler(event, context) { }); } } catch (err) { + console.log(`ERROR from CATCH IS:`) console.error(err); await mq.send({ @@ -137,7 +250,8 @@ async function execArtillery(options) { ARTILLERY_ARGS, ENV, NODE_BINARY_PATH, - ARTILLERY_BINARY_PATH + ARTILLERY_BINARY_PATH, + TEST_DATA_LOCATION } = options; const env = Object.assign( @@ -149,22 +263,47 @@ async function execArtillery(options) { SQS_QUEUE_URL: SQS_QUEUE_URL, SQS_REGION: SQS_REGION, ARTILLERY_DISABLE_ENSURE: 'true', + // NODE_PATH: `${process.cwd()}/node_modules`, + // ARTILLERY_PLUGIN_PATH: `${path.join(process.cwd(), '../../../var/task/node_modules/')}`, + ARTILLERY_PLUGIN_PATH: `${TEST_DATA_LOCATION}/node_modules/`, // Set test run ID for this Artillery process explicitly. This makes sure that $testId // template variable is set to the same value for all Lambda workers as the one user // sees on their terminal - ARTILLERY_TEST_RUN_ID: TEST_RUN_ID, + ARTILLERY_TEST_RUN_ID: TEST_RUN_ID // SHIP_LOGS: 'true', }, ENV ); - return runProcess( - NODE_BINARY_PATH || '/var/lang/bin/node', - [ARTILLERY_BINARY_PATH || './node_modules/artillery/bin/run'].concat( + console.log(`ENV IS:`) + console.log(env) + + // console.log("WHAT FOLDERS ARE HERE:") + // const artilleryPluginPath = `${path.join(process.cwd(), '../../../var/task/node_modules/')}` + // for (const file of fs.readdirSync(artilleryPluginPath)) { + // console.log(file); + // } + + const artilleryPath = `/function/node_modules/artillery/` + + //check that artillery is there + console.log("WHAT FOLDERS ARE IN ARTILLERY:") + for (const file of fs.readdirSync(artilleryPath)) { + console.log(file); + } + + const res = await runProcess( + 'node', + [ARTILLERY_BINARY_PATH || '/function/node_modules/artillery/bin/run'].concat( ARTILLERY_ARGS ), - { env, log: true } + { env: {...env, HOME: '/tmp'}, log: true } ); + + console.log(`RES IS:`) + console.log(res) + + return res } const sleep = async function (n) { @@ -176,12 +315,15 @@ const sleep = async function (n) { }; async function runProcess(name, args, { env, log } = opts) { + console.log(`RUNNING PROCESS ${name} WITH ARGS: ${args}`) + // console.log(args) return new Promise((resolve, reject) => { const proc = spawn(name, args, { env }); let stdout = ''; let stderr = ''; proc.stdout.on('data', (data) => { + if (log) { console.log(data.toString()); }