serverless/test/utils/integration.js
2020-09-09 11:17:21 +02:00

124 lines
3.3 KiB
JavaScript

// Integration tests related utils
'use strict';
const path = require('path');
const fse = require('fs-extra');
const spawn = require('child-process-ext/spawn');
const nodeFetch = require('node-fetch');
const log = require('log').get('serverless:test');
const logFetch = require('log').get('fetch');
const wait = require('timers-ext/promise/sleep');
const resolveAwsEnv = require('@serverless/test/resolve-aws-env');
const { load: loadYaml } = require('js-yaml');
const serverlessExec = require('../serverlessBinary');
const env = resolveAwsEnv();
env.SLS_DEBUG = '1';
async function resolveServiceName(cwd) {
const configContent = await (async () => {
try {
return await fse.readFile(path.join(cwd, 'serverless.yml'));
} catch (error) {
if (error.code === 'ENOENT') return null;
throw error;
}
})();
if (!configContent) return null;
const configObject = (() => {
try {
return loadYaml(configContent);
} catch (error) {
return null;
}
})();
if (!configObject) return null;
return configObject.service;
}
async function deployService(cwd) {
log.notice('deploy %s (at %s)', (await resolveServiceName(cwd)) || '[unknown]', cwd);
return spawn(serverlessExec, ['deploy'], { cwd, env });
}
async function removeService(cwd) {
log.notice('remove %s (at %s)', (await resolveServiceName(cwd)) || '[unknown]', cwd);
return spawn(serverlessExec, ['remove'], { cwd, env });
}
async function getFunctionLogs(cwd, functionName) {
let logs;
try {
({ stdoutBuffer: logs } = await spawn(
serverlessExec,
['logs', '--function', functionName, '--noGreeting', 'true'],
{
cwd,
env,
}
));
} catch (_) {
// Attempting to read logs before first invocation will will result in a "No existing streams for the function" error
return null;
}
return String(logs);
}
const defaultTimeout = 60000;
async function waitForFunctionLogs(cwd, functionName, startMarker, endMarker, options = {}) {
const timeout = options.timeout || defaultTimeout;
const startTime = Date.now();
await wait(2000);
const logs = await getFunctionLogs(cwd, functionName);
if (logs && logs.includes(startMarker) && logs.includes(endMarker)) return logs;
const timeSpan = Date.now() - startTime;
if (timeSpan > timeout) throw new Error('Cannot find function logs');
return waitForFunctionLogs(cwd, functionName, startMarker, endMarker, {
timeout: timeout - timeSpan,
});
}
let lastRequestId = 0;
async function fetch(url, options) {
const requestId = ++lastRequestId;
logFetch.debug('[%d] %s %o', requestId, url, options);
let response;
try {
response = await nodeFetch(url, options);
} catch (error) {
logFetch.error('[%d] request error: %o', requestId, error);
throw error;
}
logFetch.debug('[%d] %d %j', requestId, response.status, response.headers.raw());
/* eslint-enable */
response
.clone()
.buffer()
.then(
buffer => logFetch.debug('[%d] %s', requestId, String(buffer)),
error => logFetch.error('[%d] response resolution error: %o', requestId, error)
);
return response;
}
function getMarkers(functionName) {
return {
start: `--- START ${functionName} ---`,
end: `--- END ${functionName} ---`,
};
}
module.exports = {
deployService,
env,
fetch,
removeService,
waitForFunctionLogs,
getMarkers,
};