@webscale-networks/cloudedge-handlers
Version:
Webscale Networks CloudEDGE Handlers for cloud-agnostic edge function execution
168 lines (155 loc) • 5.62 kB
JavaScript
const child_process = require('child_process');
const fs = require('fs');
const fsExtra = require('fs-extra');
const os = require('os');
const path = require('path');
const { argv } = require('process');
const _ = require('lodash');
// Reference: https://nodejs.org/api/process.html#process_exit_codes.
const ERROR_CODE = 1;
const INVALID_ARGUMENT_CODE = 9;
const SUCCESS_CODE = 0;
const HANDLER_PACKAGE_PATH = path.join('node_modules', '@webscale-networks', 'cloudedge-handlers');
// Normalizes the user's provider name.
// Currently, the only accepted provider is 'aws'.
providerName = (provider) => {
normalizedProvider = provider.toLowerCase();
if (normalizedProvider == 'aws') {
return 'lambda';
}
return normalizedProvider;
};
// Finds the root directory of the user's handler. The root directory will
// contain the handler file's manifest.json, which is a required file for
// handlers.
computeRootDirectory = (scriptPath) => {
const directories = path.dirname(scriptPath).split(path.sep);
for (let i = directories.length; i >= 0; i--) {
const currentPath = directories.slice(0, i).join(path.sep);
if (fs.existsSync(path.join(currentPath, 'manifest.json'))) {
return currentPath;
}
}
return scriptPath;
};
// Returns the location of the @webscale-networks/cloudedge-handlers node
// module.
computeModuleDirectory = (rootDir) => {
return path.join(rootDir, HANDLER_PACKAGE_PATH);
};
// Creates a temporary directory, copies in Webscale's handler execution context
// node module and returns the temporary directory path.
createTemporaryDirectory = (srcDir) => {
tmpDir = fs.mkdtempSync(
path.join(
os.tmpdir(),
'cloudedge-handlers-execution-testing',
),
);
fsExtra.copySync(srcDir, tmpDir, { dereference: true });
return tmpDir;
};
// Installs the dependencies of Webscale's handler execution context node
// module.
npmInstall = (tempDir) => {
try {
process.chdir(tempDir);
child_process.execSync('npm install');
} catch (error) {
console.error(`${error.message}`);
console.error(`${error.stderr}`);
console.log(`${error.stdout}`);
return error.status;
}
return SUCCESS_CODE;
};
// Runs the cloud provider specific handler tests and returns the exit code of
// the test run.
runCloudProviderTests = (provider, rootDir) => {
try {
const vars = _.cloneDeep(process.env);
vars['HANDLER_ROOT_DIR'] = rootDir;
child_process.execSync(
`jest execution_testing/${provider}/src/index.js --testMatch=**/*.js`,
{ env: vars },
);
} catch (error) {
console.error(`${error.message}`);
console.error(`${error.stderr}`);
console.log(`${error.stdout}`);
return error.status;
}
return SUCCESS_CODE;
};
// Runs the Webscale handler interface tests and returns the exit code of the
// test run.
runHandlerInterfaceTests = (rootDir) => {
try {
const vars = _.cloneDeep(process.env);
vars['HANDLER_ROOT_DIR'] = rootDir;
child_process.execSync(
'jest execution_testing/webscale/src/index.js --testMatch=**/*.js',
{ env: vars },
);
} catch (error) {
console.error(`${error.message}`);
console.error(`${error.stderr}`);
console.log(`${error.stdout}`);
return error.status;
}
return SUCCESS_CODE;
};
// Remove the temporary directory.
destroyTemporaryDirectory = (dir) => {
fs.rmdirSync(dir, { recursive: true });
};
// Runs all handler unit tests. This includes cloud provider specific tests and
// Webscale handler interface tests. Returns an exit code.
runTests = (rootDir, provider) => {
const handlerDirectory = computeModuleDirectory(rootDir);
const tmpDir = createTemporaryDirectory(handlerDirectory);
const installExitCode = npmInstall(tmpDir);
if (installExitCode == SUCCESS_CODE) {
providerTestsExitCode =
runCloudProviderTests(provider, rootDir);
if (providerTestsExitCode != SUCCESS_CODE) {
statusCode = providerTestsExitCode;
} else {
handlerInterfaceTestsExitCode = runHandlerInterfaceTests(rootDir);
if (handlerInterfaceTestsExitCode != SUCCESS_CODE) {
statusCode = handlerInterfaceTestsExitCode;
} else {
statusCode = SUCCESS_CODE;
}
}
} else {
statusCode = installExitCode;
}
destroyTemporaryDirectory(tmpDir);
return statusCode;
};
// Jest is configured not to run tests found in node package's node_modules. As
// a result, this script will copy Webscale's handler execution context module
// into a temporary directory, run the included cloud provider specific and
// Webscale handler interface tests, report to standard out and standard error.
// This only returns a 0 status code if all tests pass.
//
// For more information on Jest, see:
// https://github.com/facebook/jest/issues/11781
// https://github.com/facebook/jest/issues/5039
try {
if (argv.length != 3) {
console.error(`
Usage: node run-execution-testing.js <cloud-provider>
where <cloud-provider> is one of ('aws').
`);
process.exit(INVALID_ARGUMENT_CODE);
}
const args = process.argv.slice(1);
const provider = providerName(args[1]);
const rootDir = computeRootDirectory(args[0]);
process.exit(runTests(rootDir, provider));
} catch (err) {
console.error(err);
process.exit(ERROR_CODE);
}