serverless/test/unit/lib/plugins/aws/metrics.test.js
2024-05-29 11:51:04 -04:00

427 lines
13 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({ commands: [], options: {} })
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)
})
})
})