serverless/test/unit/lib/plugins/aws/metrics.test.js
2021-10-04 21:16:51 +02:00

374 lines
12 KiB
JavaScript

'use strict';
const expect = require('chai').expect;
const sinon = require('sinon');
const AwsProvider = require('../../../../../lib/plugins/aws/provider');
const AwsMetrics = require('../../../../../lib/plugins/aws/metrics');
const Serverless = require('../../../../../lib/Serverless');
const CLI = require('../../../../../lib/classes/CLI');
const dayjs = require('dayjs');
const LocalizedFormat = require('dayjs/plugin/localizedFormat');
dayjs.extend(LocalizedFormat);
describe('AwsMetrics', () => {
let awsMetrics;
let serverless;
beforeEach(() => {
serverless = new Serverless();
serverless.cli = new CLI(serverless);
const options = {
stage: 'dev',
region: 'us-east-1',
};
serverless.setProvider('aws', new AwsProvider(serverless, options));
awsMetrics = new AwsMetrics(serverless, options);
});
describe('#constructor()', () => {
it('should set the serverless instance to this.serverless', () => {
expect(awsMetrics.serverless).to.deep.equal(serverless);
});
it('should set the passed in options to this.options', () => {
expect(awsMetrics.options).to.deep.equal({ stage: 'dev', region: 'us-east-1' });
});
it('should set the provider variable to the AwsProvider instance', () =>
expect(awsMetrics.provider).to.be.instanceof(AwsProvider));
it('should have a "metrics:metrics" hook', () => {
// eslint-disable-next-line no-unused-expressions
expect(awsMetrics.hooks['metrics:metrics']).to.not.be.undefined;
});
it('should run promise chain in order for "metrics:metrics" hook', async () => {
const extendedValidateStub = sinon.stub(awsMetrics, 'extendedValidate').resolves();
const getMetricsStub = sinon.stub(awsMetrics, 'getMetrics').resolves();
const showMetricsStub = sinon.stub(awsMetrics, 'showMetrics').resolves();
await awsMetrics.hooks['metrics:metrics']();
expect(extendedValidateStub.calledOnce).to.equal(true);
expect(getMetricsStub.calledAfter(extendedValidateStub)).to.equal(true);
expect(showMetricsStub.calledAfter(getMetricsStub)).to.equal(true);
awsMetrics.extendedValidate.restore();
awsMetrics.getMetrics.restore();
awsMetrics.showMetrics.restore();
});
});
describe('#extendedValidate()', () => {
let validateStub;
beforeEach(() => {
awsMetrics.serverless.service.functions = {
function1: {},
};
awsMetrics.serverless.service.service = 'my-service';
awsMetrics.options.function = 'function1';
validateStub = sinon.stub(awsMetrics, 'validate').resolves();
});
afterEach(() => {
awsMetrics.validate.restore();
});
it('should call the shared validate() function', () => {
awsMetrics.extendedValidate();
expect(validateStub.calledOnce).to.equal(true);
});
it('should set the startTime to yesterday as the default value if not provided', () => {
awsMetrics.options.startTime = null;
let yesterday = new Date();
yesterday = yesterday.setDate(yesterday.getDate() - 1);
yesterday = new Date(yesterday);
const yesterdaysYear = yesterday.getFullYear();
const yesterdaysMonth = yesterday.getMonth() + 1;
const yesterdaysDay = yesterday.getDate();
const yesterdaysDate = `${yesterdaysYear}-${yesterdaysMonth}-${yesterdaysDay}`;
awsMetrics.extendedValidate();
const defaultsStartTime = dayjs(awsMetrics.options.startTime);
const defaultsDate = defaultsStartTime.format('YYYY-M-D');
expect(defaultsDate).to.equal(yesterdaysDate);
});
it('should set the startTime to the provided value', () => {
awsMetrics.options.startTime = '1970-01-01';
awsMetrics.extendedValidate();
const startTime = awsMetrics.options.startTime.toISOString();
const expectedStartTime = new Date('1970-01-01').toISOString();
expect(startTime).to.equal(expectedStartTime);
});
it('should translate human friendly syntax (e.g. 24h) for startTime', () => {
awsMetrics.options.startTime = '24h'; // 24 hours ago
let yesterday = new Date();
yesterday = yesterday.setDate(yesterday.getDate() - 1);
yesterday = new Date(yesterday);
const yesterdaysYear = yesterday.getFullYear();
const yesterdaysMonth = yesterday.getMonth() + 1;
const yesterdaysDay = yesterday.getDate();
const yesterdaysDate = `${yesterdaysYear}-${yesterdaysMonth}-${yesterdaysDay}`;
awsMetrics.extendedValidate();
const translatedStartTime = dayjs(awsMetrics.options.startTime);
const translatedDate = translatedStartTime.format('YYYY-M-D');
expect(translatedDate).to.equal(yesterdaysDate);
});
it('should set the endTime to today as the default value if not provided', () => {
awsMetrics.options.endTime = null;
const today = new Date();
const todaysYear = today.getFullYear();
const todaysMonth = today.getMonth() + 1;
const todaysDay = today.getDate();
const todaysDate = `${todaysYear}-${todaysMonth}-${todaysDay}`;
awsMetrics.extendedValidate();
const defaultsStartTime = dayjs(awsMetrics.options.endTime);
const defaultsDate = defaultsStartTime.format('YYYY-M-D');
expect(defaultsDate).to.equal(todaysDate);
});
it('should set the endTime to the provided value', () => {
awsMetrics.options.endTime = '1970-01-01';
awsMetrics.extendedValidate();
const endTime = awsMetrics.options.endTime.toISOString();
const expectedEndTime = new Date('1970-01-01').toISOString();
expect(endTime).to.equal(expectedEndTime);
});
});
describe('#getMetrics()', () => {
let requestStub;
beforeEach(() => {
awsMetrics.serverless.service.functions = {
function1: {
name: 'func1',
},
function2: {
name: 'func2',
},
};
awsMetrics.options.startTime = new Date('1970-01-01');
awsMetrics.options.endTime = new Date('1970-01-02');
requestStub = sinon.stub(awsMetrics.provider, 'request');
});
afterEach(() => {
awsMetrics.provider.request.restore();
});
it('should gather service wide function metrics if no function option is specified', async () => {
// stubs for function1
// invocations
requestStub.onCall(0).resolves({
ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' },
Label: 'Invocations',
Datapoints: [],
});
// throttles
requestStub.onCall(1).resolves({
ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' },
Label: 'Throttles',
Datapoints: [],
});
// errors
requestStub.onCall(2).resolves({
ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' },
Label: 'Errors',
Datapoints: [],
});
// duration
requestStub.onCall(3).resolves({
ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' },
Label: 'Duration',
Datapoints: [],
});
// stubs for function2
// invocations
requestStub.onCall(4).resolves({
ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func2' },
Label: 'Invocations',
Datapoints: [],
});
// throttles
requestStub.onCall(5).resolves({
ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func2' },
Label: 'Throttles',
Datapoints: [],
});
// errors
requestStub.onCall(6).resolves({
ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func2' },
Label: 'Errors',
Datapoints: [],
});
// duration
requestStub.onCall(7).resolves({
ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func2' },
Label: 'Duration',
Datapoints: [],
});
const expectedResult = [
[
{
ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' },
Label: 'Invocations',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' },
Label: 'Throttles',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' },
Label: 'Errors',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' },
Label: 'Duration',
Datapoints: [],
},
],
[
{
ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func2' },
Label: 'Invocations',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func2' },
Label: 'Throttles',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func2' },
Label: 'Errors',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func2' },
Label: 'Duration',
Datapoints: [],
},
],
];
const result = await awsMetrics.getMetrics();
expect(result).to.deep.equal(expectedResult);
});
it('should gather function metrics if function option is specified', async () => {
// only display metrics for function1
awsMetrics.options.function = 'function1';
// stubs for function1
// invocations
requestStub.onCall(0).resolves({
ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' },
Label: 'Invocations',
Datapoints: [],
});
// throttles
requestStub.onCall(1).resolves({
ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' },
Label: 'Throttles',
Datapoints: [],
});
// errors
requestStub.onCall(2).resolves({
ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' },
Label: 'Errors',
Datapoints: [],
});
// duration
requestStub.onCall(3).resolves({
ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' },
Label: 'Duration',
Datapoints: [],
});
const expectedResult = [
[
{
ResponseMetadata: { RequestId: '1f50045b-b569-11e6-86c6-eb54d1aaa755-func1' },
Label: 'Invocations',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f59059b-b569-11e6-aa18-c7bab68810d2-func1' },
Label: 'Throttles',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f50c7b1-b569-11e6-b1b6-ab86694b617b-func1' },
Label: 'Errors',
Datapoints: [],
},
{
ResponseMetadata: { RequestId: '1f63db14-b569-11e6-8501-d98a275ce164-func1' },
Label: 'Duration',
Datapoints: [],
},
],
];
const result = await awsMetrics.getMetrics();
expect(result).to.deep.equal(expectedResult);
});
it('should gather metrics with 1 hour period for time span < 24 hours', async () => {
awsMetrics.options.startTime = new Date('1970-01-01T09:00');
awsMetrics.options.endTime = new Date('1970-01-01T16:00');
await awsMetrics.getMetrics();
expect(
requestStub.calledWith(
sinon.match.string,
sinon.match.string,
sinon.match.has('Period', 3600)
)
).to.equal(true);
});
it('should gather metrics with 1 day period for time span > 24 hours', async () => {
awsMetrics.options.startTime = new Date('1970-01-01');
awsMetrics.options.endTime = new Date('1970-01-03');
await awsMetrics.getMetrics();
expect(
requestStub.calledWith(
sinon.match.string,
sinon.match.string,
sinon.match.has('Period', 24 * 3600)
)
).to.equal(true);
});
});
});