diff --git a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json index e9d7dfdf5b8fc..77e37b1fd5d0d 100644 --- a/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json +++ b/packages/@aws-cdk/aws-apigatewayv2-integrations/package.json @@ -72,10 +72,8 @@ "license": "Apache-2.0", "devDependencies": { "@types/jest": "^26.0.24", - "@types/nodeunit": "^0.0.32", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "nodeunit": "^0.11.3", "pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-cloudwatch/.gitignore b/packages/@aws-cdk/aws-cloudwatch/.gitignore index 0f4bf01dd552c..9f6a9219fad75 100644 --- a/packages/@aws-cdk/aws-cloudwatch/.gitignore +++ b/packages/@aws-cdk/aws-cloudwatch/.gitignore @@ -16,4 +16,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudwatch/.npmignore b/packages/@aws-cdk/aws-cloudwatch/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-cloudwatch/.npmignore +++ b/packages/@aws-cdk/aws-cloudwatch/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudwatch/jest.config.js b/packages/@aws-cdk/aws-cloudwatch/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index c57fc64d6f8a0..246ad8a89ef37 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -55,6 +55,7 @@ }, "cdk-build": { "cloudformation": "AWS::CloudWatch", + "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": "true" } @@ -72,11 +73,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/nodeunit": "^0.0.32", + "@types/jest": "^26.0.24", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", + "jest": "^26.6.3", "pkglint": "0.0.0", "@aws-cdk/assert-internal": "0.0.0" }, diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.alarm-status-widget.ts b/packages/@aws-cdk/aws-cloudwatch/test/alarm-status-widget.test.ts similarity index 80% rename from packages/@aws-cdk/aws-cloudwatch/test/test.alarm-status-widget.ts rename to packages/@aws-cdk/aws-cloudwatch/test/alarm-status-widget.test.ts index 17d24cfd3793f..3c771ba47ea05 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.alarm-status-widget.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/alarm-status-widget.test.ts @@ -1,8 +1,7 @@ import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Metric, Alarm, AlarmStatusWidget } from '../lib'; -export = { - 'alarm status widget'(test: Test) { +describe('Alarm Status Widget', () => { + test('alarm status widget', () => { // GIVEN const stack = new Stack(); const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); @@ -18,7 +17,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [ + expect(stack.resolve(widget.toJson())).toEqual([ { type: 'alarm', width: 6, @@ -30,6 +29,6 @@ export = { }, ]); - test.done(); - }, -}; + + }); +}); diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.alarm.ts b/packages/@aws-cdk/aws-cloudwatch/test/alarm.test.ts similarity index 73% rename from packages/@aws-cdk/aws-cloudwatch/test/test.alarm.ts rename to packages/@aws-cdk/aws-cloudwatch/test/alarm.test.ts index fbce3d9c4ef9c..c143e8baec65b 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/alarm.test.ts @@ -1,7 +1,7 @@ -import { ABSENT, expect, haveResource } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { ABSENT } from '@aws-cdk/assert-internal'; import { Duration, Stack } from '@aws-cdk/core'; import { Construct } from 'constructs'; -import { Test } from 'nodeunit'; import { Alarm, IAlarm, IAlarmAction, Metric, MathExpression, IMetric } from '../lib'; const testMetric = new Metric({ @@ -9,9 +9,9 @@ const testMetric = new Metric({ metricName: 'Metric', }); -export = { +describe('Alarm', () => { - 'alarm does not accept a math expression with more than 10 metrics'(test: Test) { + test('alarm does not accept a math expression with more than 10 metrics', () => { const stack = new Stack(); @@ -30,7 +30,7 @@ export = { usingMetrics, }); - test.throws(() => { + expect(() => { new Alarm(stack, 'Alarm', { metric: math, @@ -38,11 +38,11 @@ export = { evaluationPeriods: 3, }); - }, /Alarms on math expressions cannot contain more than 10 individual metrics/); + }).toThrow(/Alarms on math expressions cannot contain more than 10 individual metrics/); - test.done(); - }, - 'non ec2 instance related alarm does not accept EC2 action'(test: Test) { + + }); + test('non ec2 instance related alarm does not accept EC2 action', () => { const stack = new Stack(); const alarm = new Alarm(stack, 'Alarm', { @@ -51,12 +51,12 @@ export = { evaluationPeriods: 2, }); - test.throws(() => { + expect(() => { alarm.addAlarmAction(new Ec2TestAlarmAction('arn:aws:automate:us-east-1:ec2:reboot')); - }, /EC2 alarm actions requires an EC2 Per-Instance Metric. \(.+ does not have an 'InstanceId' dimension\)/); - test.done(); - }, - 'can make simple alarm'(test: Test) { + }).toThrow(/EC2 alarm actions requires an EC2 Per-Instance Metric. \(.+ does not have an 'InstanceId' dimension\)/); + + }); + test('can make simple alarm', () => { // GIVEN const stack = new Stack(); @@ -68,7 +68,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { ComparisonOperator: 'GreaterThanOrEqualToThreshold', EvaluationPeriods: 3, MetricName: 'Metric', @@ -76,12 +76,12 @@ export = { Period: 300, Statistic: 'Average', Threshold: 1000, - })); + }); - test.done(); - }, - 'override metric period in Alarm'(test: Test) { + }); + + test('override metric period in Alarm', () => { // GIVEN const stack = new Stack(); @@ -94,7 +94,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { ComparisonOperator: 'GreaterThanOrEqualToThreshold', EvaluationPeriods: 3, MetricName: 'Metric', @@ -102,12 +102,12 @@ export = { Period: 600, Statistic: 'Average', Threshold: 1000, - })); + }); - test.done(); - }, - 'override statistic Alarm'(test: Test) { + }); + + test('override statistic Alarm', () => { // GIVEN const stack = new Stack(); @@ -120,7 +120,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { ComparisonOperator: 'GreaterThanOrEqualToThreshold', EvaluationPeriods: 3, MetricName: 'Metric', @@ -129,12 +129,12 @@ export = { Statistic: 'Maximum', ExtendedStatistic: ABSENT, Threshold: 1000, - })); + }); + - test.done(); - }, + }); - 'can use percentile in Alarm'(test: Test) { + test('can use percentile in Alarm', () => { // GIVEN const stack = new Stack(); @@ -147,7 +147,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { ComparisonOperator: 'GreaterThanOrEqualToThreshold', EvaluationPeriods: 3, MetricName: 'Metric', @@ -156,12 +156,12 @@ export = { Statistic: ABSENT, ExtendedStatistic: 'p99', Threshold: 1000, - })); + }); + - test.done(); - }, + }); - 'can set DatapointsToAlarm'(test: Test) { + test('can set DatapointsToAlarm', () => { // GIVEN const stack = new Stack(); @@ -174,7 +174,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { ComparisonOperator: 'GreaterThanOrEqualToThreshold', EvaluationPeriods: 3, DatapointsToAlarm: 2, @@ -183,12 +183,12 @@ export = { Period: 300, Statistic: 'Average', Threshold: 1000, - })); + }); + - test.done(); - }, + }); - 'can add actions to alarms'(test: Test) { + test('can add actions to alarms', () => { // GIVEN const stack = new Stack(); @@ -204,16 +204,16 @@ export = { alarm.addOkAction(new TestAlarmAction('C')); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { AlarmActions: ['A'], InsufficientDataActions: ['B'], OKActions: ['C'], - })); + }); - test.done(); - }, - 'can make alarm directly from metric'(test: Test) { + }); + + test('can make alarm directly from metric', () => { // GIVEN const stack = new Stack(); @@ -226,7 +226,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { ComparisonOperator: 'GreaterThanOrEqualToThreshold', EvaluationPeriods: 2, MetricName: 'Metric', @@ -234,12 +234,12 @@ export = { Period: 10, Statistic: 'Minimum', Threshold: 1000, - })); + }); - test.done(); - }, - 'can use percentile string to make alarm'(test: Test) { + }); + + test('can use percentile string to make alarm', () => { // GIVEN const stack = new Stack(); @@ -251,13 +251,13 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResource('AWS::CloudWatch::Alarm', { ExtendedStatistic: 'p99.9', - })); + }); - test.done(); - }, -}; + + }); +}); class TestAlarmAction implements IAlarmAction { constructor(private readonly arn: string) { diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.composite-alarm.ts b/packages/@aws-cdk/aws-cloudwatch/test/composite-alarm.test.ts similarity index 89% rename from packages/@aws-cdk/aws-cloudwatch/test/test.composite-alarm.ts rename to packages/@aws-cdk/aws-cloudwatch/test/composite-alarm.test.ts index 87625abcd6aa6..054f1b21724ee 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.composite-alarm.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/composite-alarm.test.ts @@ -1,10 +1,9 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Alarm, AlarmRule, AlarmState, CompositeAlarm, Metric } from '../lib'; -export = { - 'test alarm rule expression builder'(test: Test) { +describe('CompositeAlarm', () => { + test('test alarm rule expression builder', () => { const stack = new Stack(); const testMetric = new Metric({ @@ -60,7 +59,7 @@ export = { alarmRule, }); - expect(stack).to(haveResource('AWS::CloudWatch::CompositeAlarm', { + expect(stack).toHaveResource('AWS::CloudWatch::CompositeAlarm', { AlarmName: 'CompositeAlarm', AlarmRule: { 'Fn::Join': [ @@ -105,9 +104,9 @@ export = { ], ], }, - })); + }); + - test.done(); - }, + }); -}; +}); diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.cross-environment.ts b/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts similarity index 57% rename from packages/@aws-cdk/aws-cloudwatch/test/test.cross-environment.ts rename to packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts index 1afb4cdca882c..959ceafab54fc 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.cross-environment.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/cross-environment.test.ts @@ -1,21 +1,20 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Alarm, GraphWidget, IWidget, Metric } from '../lib'; const a = new Metric({ namespace: 'Test', metricName: 'ACount' }); let stack1: Stack; let stack2: Stack; -export = { - 'setUp'(cb: () => void) { +describe('cross environment', () => { + beforeEach(() => { stack1 = new Stack(undefined, undefined, { env: { region: 'pluto', account: '1234' } }); stack2 = new Stack(undefined, undefined, { env: { region: 'mars', account: '5678' } }); - cb(); - }, - 'in graphs': { - 'metric attached to stack1 will not render region and account in stack1'(test: Test) { + }); + + describe('in graphs', () => { + test('metric attached to stack1 will not render region and account in stack1', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -24,14 +23,14 @@ export = { }); // THEN - graphMetricsAre(test, stack1, graph, [ + graphMetricsAre(stack1, graph, [ ['Test', 'ACount'], ]); - test.done(); - }, - 'metric attached to stack1 will render region and account in stack2'(test: Test) { + }); + + test('metric attached to stack1 will render region and account in stack2', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -40,14 +39,14 @@ export = { }); // THEN - graphMetricsAre(test, stack2, graph, [ + graphMetricsAre(stack2, graph, [ ['Test', 'ACount', { region: 'pluto', accountId: '1234' }], ]); - test.done(); - }, - 'metric with explicit account and region will render in environment agnostic stack'(test: Test) { + }); + + test('metric with explicit account and region will render in environment agnostic stack', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -56,14 +55,14 @@ export = { }); // THEN - graphMetricsAre(test, new Stack(), graph, [ + graphMetricsAre(new Stack(), graph, [ ['Test', 'ACount', { accountId: '1234', region: 'us-north-5' }], ]); - test.done(); - }, - 'metric attached to agnostic stack will not render in agnostic stack'(test: Test) { + }); + + test('metric attached to agnostic stack will not render in agnostic stack', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -72,16 +71,16 @@ export = { }); // THEN - graphMetricsAre(test, new Stack(), graph, [ + graphMetricsAre(new Stack(), graph, [ ['Test', 'ACount'], ]); - test.done(); - }, - }, - 'in alarms': { - 'metric attached to stack1 will not render region and account in stack1'(test: Test) { + }); + }); + + describe('in alarms', () => { + test('metric attached to stack1 will not render region and account in stack1', () => { // GIVEN new Alarm(stack1, 'Alarm', { threshold: 1, @@ -90,34 +89,34 @@ export = { }); // THEN - expect(stack1).to(haveResourceLike('AWS::CloudWatch::Alarm', { + expect(stack1).toHaveResourceLike('AWS::CloudWatch::Alarm', { MetricName: 'ACount', Namespace: 'Test', Period: 300, - })); + }); - test.done(); - }, - 'metric attached to stack1 will throw in stack2'(test: Test) { + }); + + test('metric attached to stack1 will throw in stack2', () => { // Cross-region/cross-account metrics are supported in Dashboards but not in Alarms // GIVEN - test.throws(() => { + expect(() => { new Alarm(stack2, 'Alarm', { threshold: 1, evaluationPeriods: 1, metric: a.attachTo(stack1), }); - }, /Cannot create an Alarm in region 'mars' based on metric 'ACount' in 'pluto'/); + }).toThrow(/Cannot create an Alarm in region 'mars' based on metric 'ACount' in 'pluto'/); - test.done(); - }, - }, -}; -function graphMetricsAre(test: Test, stack: Stack, w: IWidget, metrics: any[]) { - test.deepEqual(stack.resolve(w.toJson()), [{ + }); + }); +}); + +function graphMetricsAre(stack: Stack, w: IWidget, metrics: any[]) { + expect(stack.resolve(w.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.dashboard.ts b/packages/@aws-cdk/aws-cloudwatch/test/dashboard.test.ts similarity index 75% rename from packages/@aws-cdk/aws-cloudwatch/test/test.dashboard.ts rename to packages/@aws-cdk/aws-cloudwatch/test/dashboard.test.ts index 4249f8675d1be..5501a47ba5c3a 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.dashboard.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/dashboard.test.ts @@ -1,10 +1,10 @@ -import { expect, haveResource, isSuperObject } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; +import { isSuperObject } from '@aws-cdk/assert-internal'; import { App, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Dashboard, GraphWidget, PeriodOverride, TextWidget } from '../lib'; -export = { - 'widgets in different adds are laid out underneath each other'(test: Test) { +describe('Dashboard', () => { + test('widgets in different adds are laid out underneath each other', () => { // GIVEN const stack = new Stack(); const dashboard = new Dashboard(stack, 'Dash'); @@ -27,16 +27,16 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Dashboard', thatHasWidgets([ + expect(stack).toHaveResource('AWS::CloudWatch::Dashboard', thatHasWidgets([ { type: 'text', width: 10, height: 2, x: 0, y: 0, properties: { markdown: 'first' } }, { type: 'text', width: 1, height: 4, x: 0, y: 2, properties: { markdown: 'second' } }, { type: 'text', width: 4, height: 1, x: 0, y: 6, properties: { markdown: 'third' } }, - ]))); + ])); - test.done(); - }, - 'widgets in same add are laid out next to each other'(test: Test) { + }); + + test('widgets in same add are laid out next to each other', () => { // GIVEN const stack = new Stack(); const dashboard = new Dashboard(stack, 'Dash'); @@ -61,16 +61,16 @@ export = { ); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Dashboard', thatHasWidgets([ + expect(stack).toHaveResource('AWS::CloudWatch::Dashboard', thatHasWidgets([ { type: 'text', width: 10, height: 2, x: 0, y: 0, properties: { markdown: 'first' } }, { type: 'text', width: 1, height: 4, x: 10, y: 0, properties: { markdown: 'second' } }, { type: 'text', width: 4, height: 1, x: 11, y: 0, properties: { markdown: 'third' } }, - ]))); + ])); + - test.done(); - }, + }); - 'tokens in widgets are retained'(test: Test) { + test('tokens in widgets are retained', () => { // GIVEN const stack = new Stack(); const dashboard = new Dashboard(stack, 'Dash'); @@ -81,7 +81,7 @@ export = { ); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Dashboard', { + expect(stack).toHaveResource('AWS::CloudWatch::Dashboard', { DashboardBody: { 'Fn::Join': ['', [ '{"widgets":[{"type":"metric","width":1,"height":1,"x":0,"y":0,"properties":{"view":"timeSeries","region":"', @@ -89,12 +89,12 @@ export = { '","yAxis":{}}}]}', ]], }, - })); + }); - test.done(); - }, - 'dashboard body includes non-widget fields'(test: Test) { + }); + + test('dashboard body includes non-widget fields', () => { // GIVEN const stack = new Stack(); const dashboard = new Dashboard(stack, 'Dash', @@ -110,7 +110,7 @@ export = { ); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Dashboard', { + expect(stack).toHaveResource('AWS::CloudWatch::Dashboard', { DashboardBody: { 'Fn::Join': ['', [ '{"start":"-9H","end":"2018-12-17T06:00:00.000Z","periodOverride":"inherit",\ @@ -119,12 +119,12 @@ export = { '","yAxis":{}}}]}', ]], }, - })); + }); - test.done(); - }, - 'DashboardName is set when provided'(test: Test) { + }); + + test('DashboardName is set when provided', () => { // GIVEN const app = new App(); const stack = new Stack(app, 'MyStack'); @@ -135,14 +135,14 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Dashboard', { + expect(stack).toHaveResource('AWS::CloudWatch::Dashboard', { DashboardName: 'MyCustomDashboardName', - })); + }); - test.done(); - }, - 'DashboardName is not generated if not provided'(test: Test) { + }); + + test('DashboardName is not generated if not provided', () => { // GIVEN const app = new App(); const stack = new Stack(app, 'MyStack'); @@ -151,12 +151,12 @@ export = { new Dashboard(stack, 'MyDashboard'); // THEN - expect(stack).to(haveResource('AWS::CloudWatch::Dashboard', {})); + expect(stack).toHaveResource('AWS::CloudWatch::Dashboard', {}); + - test.done(); - }, + }); - 'throws if DashboardName is not valid'(test: Test) { + test('throws if DashboardName is not valid', () => { // GIVEN const app = new App(); const stack = new Stack(app, 'MyStack'); @@ -169,11 +169,11 @@ export = { }; // THEN - test.throws(() => toThrow(), /field dashboardName contains invalid characters/); + expect(() => toThrow()).toThrow(/field dashboardName contains invalid characters/); + - test.done(); - }, -}; + }); +}); /** * Returns a property predicate that checks that the given Dashboard has the indicated widgets diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.graphs.ts b/packages/@aws-cdk/aws-cloudwatch/test/graphs.test.ts similarity index 79% rename from packages/@aws-cdk/aws-cloudwatch/test/test.graphs.ts rename to packages/@aws-cdk/aws-cloudwatch/test/graphs.test.ts index e5cc11781393d..0c1adfb58b1f8 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.graphs.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/graphs.test.ts @@ -1,9 +1,8 @@ import { Duration, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Alarm, AlarmWidget, Color, GraphWidget, GraphWidgetView, LegendPosition, LogQueryWidget, Metric, Shading, SingleValueWidget, LogQueryVisualizationType } from '../lib'; -export = { - 'add stacked property to graphs'(test: Test) { +describe('Graphs', () => { + test('add stacked property to graphs', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -12,7 +11,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -25,10 +24,10 @@ export = { }, }]); - test.done(); - }, - 'add metrics to graphs on either axis'(test: Test) { + }); + + test('add metrics to graphs on either axis', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -42,7 +41,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -58,10 +57,10 @@ export = { }, }]); - test.done(); - }, - 'add metrics to graphs on either axis lazily'(test: Test) { + }); + + test('add metrics to graphs on either axis lazily', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -71,7 +70,7 @@ export = { widget.addRightMetric(new Metric({ namespace: 'CDK', metricName: 'Tast' })); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -87,10 +86,10 @@ export = { }, }]); - test.done(); - }, - 'label and color are respected in constructor'(test: Test) { + }); + + test('label and color are respected in constructor', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -98,7 +97,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -112,10 +111,10 @@ export = { }, }]); - test.done(); - }, - 'bar view'(test: Test) { + }); + + test('bar view', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -124,7 +123,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -136,10 +135,10 @@ export = { }, }]); - test.done(); - }, - 'singlevalue widget'(test: Test) { + }); + + test('singlevalue widget', () => { // GIVEN const stack = new Stack(); const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); @@ -150,7 +149,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 3, @@ -163,10 +162,10 @@ export = { }, }]); - test.done(); - }, - 'query result widget'(test: Test) { + }); + + test('query result widget', () => { // GIVEN const stack = new Stack(); const logGroup = { logGroupName: 'my-log-group' }; @@ -181,7 +180,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'log', width: 6, height: 6, @@ -192,10 +191,10 @@ export = { }, }]); - test.done(); - }, - 'query result widget - bar'(test: Test) { + }); + + test('query result widget - bar', () => { // GIVEN const stack = new Stack(); const logGroup = { logGroupName: 'my-log-group' }; @@ -211,7 +210,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'log', width: 6, height: 6, @@ -222,10 +221,10 @@ export = { }, }]); - test.done(); - }, - 'query result widget - pie'(test: Test) { + }); + + test('query result widget - pie', () => { // GIVEN const stack = new Stack(); const logGroup = { logGroupName: 'my-log-group' }; @@ -241,7 +240,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'log', width: 6, height: 6, @@ -252,10 +251,10 @@ export = { }, }]); - test.done(); - }, - 'query result widget - line'(test: Test) { + }); + + test('query result widget - line', () => { // GIVEN const stack = new Stack(); const logGroup = { logGroupName: 'my-log-group' } ; @@ -271,7 +270,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'log', width: 6, height: 6, @@ -283,10 +282,10 @@ export = { }, }]); - test.done(); - }, - 'query result widget - stackedarea'(test: Test) { + }); + + test('query result widget - stackedarea', () => { // GIVEN const stack = new Stack(); const logGroup = { logGroupName: 'my-log-group' }; @@ -302,7 +301,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'log', width: 6, height: 6, @@ -314,10 +313,10 @@ export = { }, }]); - test.done(); - }, - 'alarm widget'(test: Test) { + }); + + test('alarm widget', () => { // GIVEN const stack = new Stack(); @@ -332,7 +331,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -346,10 +345,10 @@ export = { }, }]); - test.done(); - }, - 'add annotations to graph'(test: Test) { + }); + + test('add annotations to graph', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -366,7 +365,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -390,10 +389,10 @@ export = { }, }]); - test.done(); - }, - 'convert alarm to annotation'(test: Test) { + }); + + test('convert alarm to annotation', () => { // GIVEN const stack = new Stack(); @@ -412,7 +411,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -433,10 +432,10 @@ export = { }, }]); - test.done(); - }, - 'add yAxis to graph'(test: Test) { + }); + + test('add yAxis to graph', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -459,7 +458,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -478,10 +477,10 @@ export = { }, }]); - test.done(); - }, - 'specify liveData property on graph'(test: Test) { + }); + + test('specify liveData property on graph', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -493,7 +492,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -509,10 +508,10 @@ export = { }, }]); - test.done(); - }, - 'can use imported alarm with graph'(test: Test) { + }); + + test('can use imported alarm with graph', () => { // GIVEN const stack = new Stack(); const alarm = Alarm.fromAlarmArn(stack, 'Alarm', 'arn:aws:cloudwatch:region:account-id:alarm:alarm-name'); @@ -525,10 +524,10 @@ export = { // THEN: Compiles - test.done(); - }, - 'add setPeriodToTimeRange to singleValueWidget'(test: Test) { + }); + + test('add setPeriodToTimeRange to singleValueWidget', () => { // GIVEN const stack = new Stack(); const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); @@ -540,7 +539,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 3, @@ -554,10 +553,10 @@ export = { }, }]); - test.done(); - }, - 'add singleValueFullPrecision to singleValueWidget'(test: Test) { + }); + + test('add singleValueFullPrecision to singleValueWidget', () => { // GIVEN const stack = new Stack(); const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); @@ -569,7 +568,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 3, @@ -583,10 +582,10 @@ export = { }, }]); - test.done(); - }, - 'allows overriding custom values of dashboard widgets'(test: Test) { + }); + + test('allows overriding custom values of dashboard widgets', () => { class HiddenMetric extends Metric { public toMetricConfig() { const ret = super.toMetricConfig(); @@ -603,16 +602,13 @@ export = { ], }); - // test.ok(widget.toJson()[0].properties.metrics[0].visible === false); - test.deepEqual( - stack.resolve(widget.toJson())[0].properties.metrics[0], - ['CDK', 'Test', { visible: false }], - ); + expect(stack.resolve(widget.toJson())[0].properties.metrics[0]) + .toEqual(['CDK', 'Test', { visible: false }]); + - test.done(); - }, + }); - 'GraphColor is correctly converted into the correct hexcode'(test: Test) { + test('GraphColor is correctly converted into the correct hexcode', () => { // GIVEN const stack = new Stack(); const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); @@ -627,12 +623,12 @@ export = { ], }); - test.deepEqual(stack.resolve(widget.toJson())[0].properties.metrics[0], ['CDK', 'Test', { color: '#1f77b4' }]); - test.deepEqual(stack.resolve(widget.toJson())[0].properties.annotations.horizontal[0], { yAxis: 'left', value: 100, color: '#d62728' }); - test.done(); - }, + expect(stack.resolve(widget.toJson())[0].properties.metrics[0]).toEqual(['CDK', 'Test', { color: '#1f77b4' }]); + expect(stack.resolve(widget.toJson())[0].properties.annotations.horizontal[0]).toEqual({ yAxis: 'left', value: 100, color: '#d62728' }); + + }); - 'legend position is respected in constructor'(test: Test) { + test('legend position is respected in constructor', () => { // WHEN const stack = new Stack(); const widget = new GraphWidget({ @@ -641,7 +637,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -658,10 +654,10 @@ export = { }, }]); - test.done(); - }, - 'add setPeriodToTimeRange to GraphWidget'(test: Test) { + }); + + test('add setPeriodToTimeRange to GraphWidget', () => { // GIVEN const stack = new Stack(); const widget = new GraphWidget({ @@ -671,7 +667,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -686,10 +682,10 @@ export = { }, }]); - test.done(); - }, - 'GraphWidget supports stat and period'(test: Test) { + }); + + test('GraphWidget supports stat and period', () => { // GIVEN const stack = new Stack(); const widget = new GraphWidget({ @@ -699,7 +695,7 @@ export = { }); // THEN - test.deepEqual(stack.resolve(widget.toJson()), [{ + expect(stack.resolve(widget.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -715,6 +711,6 @@ export = { }, }]); - test.done(); - }, -}; + + }); +}); diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.layout.ts b/packages/@aws-cdk/aws-cloudwatch/test/layout.test.ts similarity index 66% rename from packages/@aws-cdk/aws-cloudwatch/test/test.layout.ts rename to packages/@aws-cdk/aws-cloudwatch/test/layout.test.ts index 3a8cbb35ed1a3..f7062189ddd04 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.layout.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/layout.test.ts @@ -1,8 +1,7 @@ -import { Test } from 'nodeunit'; import { Column, IWidget, Row, Spacer, TextWidget } from '../lib'; -export = { - 'row has the height of the tallest element'(test: Test) { +describe('Layout', () => { + test('row has the height of the tallest element', () => { // WHEN const row = new Row( new Spacer({ width: 10, height: 1 }), @@ -10,24 +9,24 @@ export = { ); // THEN - test.equal(4, row.height); - test.equal(20, row.width); + expect(4).toEqual(row.height); + expect(20).toEqual(row.width); - test.done(); - }, - 'spacer has default height and width'(test: Test) { + }); + + test('spacer has default height and width', () => { // WHEN const spacer = new Spacer(); // THEN - test.equal(1, spacer.height); - test.equal(1, spacer.width); + expect(1).toEqual(spacer.height); + expect(1).toEqual(spacer.width); + - test.done(); - }, + }); - 'column has the width of the tallest element'(test: Test) { + test('column has the width of the tallest element', () => { // WHEN const col = new Column( new Spacer({ width: 1, height: 1 }), @@ -35,13 +34,13 @@ export = { ); // THEN - test.equal(4, col.width); - test.equal(5, col.height); + expect(4).toEqual(col.width); + expect(5).toEqual(col.height); + - test.done(); - }, + }); - 'row wraps to width of 24, taking tallest widget into account while wrapping'(test: Test) { + test('row wraps to width of 24, taking tallest widget into account while wrapping', () => { // Try the tall box in all positions for (const heights of [[4, 1, 1], [1, 4, 1], [1, 1, 4]]) { // GIVEN @@ -57,13 +56,13 @@ export = { row.position(1000, 1000); // Check that we correctly offset all inner widgets // THEN - test.equal(21, row.width); - test.equal(5, row.height); + expect(21).toEqual(row.width); + expect(5).toEqual(row.height); function assertWidgetPos(x: number, y: number, w: IWidget) { const json = w.toJson()[0]; - test.equal(x, json.x); - test.equal(y, json.y); + expect(x).toEqual(json.x); + expect(y).toEqual(json.y); } assertWidgetPos(1000, 1000, widgets[0]); @@ -72,10 +71,10 @@ export = { assertWidgetPos(1000, 1004, widgets[3]); } - test.done(); - }, - 'row can fit exactly 3 8-wide widgets without wrapping'(test: Test) { + }); + + test('row can fit exactly 3 8-wide widgets without wrapping', () => { // Try the tall box in all positions for (const heights of [[4, 1, 1], [1, 4, 1], [1, 1, 4]]) { // WHEN @@ -86,10 +85,10 @@ export = { ); // THEN - test.equal(24, row.width); - test.equal(4, row.height); + expect(24).toEqual(row.width); + expect(4).toEqual(row.height); } - test.done(); - }, -}; + + }); +}); diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.metric-math.ts b/packages/@aws-cdk/aws-cloudwatch/test/metric-math.test.ts similarity index 78% rename from packages/@aws-cdk/aws-cloudwatch/test/test.metric-math.ts rename to packages/@aws-cdk/aws-cloudwatch/test/metric-math.test.ts index dcf65649236aa..b9379bbdc360c 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.metric-math.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/metric-math.test.ts @@ -1,6 +1,5 @@ -import { expect, haveResourceLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import { Duration, Stack } from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Alarm, GraphWidget, IWidget, MathExpression, Metric } from '../lib'; const a = new Metric({ namespace: 'Test', metricName: 'ACount' }); @@ -9,14 +8,13 @@ const c = new Metric({ namespace: 'Test', metricName: 'CCount' }); const b99 = new Metric({ namespace: 'Test', metricName: 'BCount', statistic: 'p99' }); let stack: Stack; -export = { - 'setUp'(cb: () => void) { +describe('Metric Math', () => { + beforeEach(() => { stack = new Stack(); - cb(); - }, + }); - 'can not use invalid variable names in MathExpression'(test: Test) { - test.throws(() => { + test('can not use invalid variable names in MathExpression', () => { + expect(() => { new MathExpression({ expression: 'HAPPY + JOY', usingMetrics: { @@ -24,14 +22,14 @@ export = { JOY: b, }, }); - }, /Invalid variable names in expression/); + }).toThrow(/Invalid variable names in expression/); - test.done(); - }, - 'cannot reuse variable names in nested MathExpressions'(test: Test) { + }); + + test('cannot reuse variable names in nested MathExpressions', () => { // WHEN - test.throws(() => { + expect(() => { new MathExpression({ expression: 'a + e', usingMetrics: { @@ -42,37 +40,37 @@ export = { }), }, }); - }, /The ID 'a' used for two metrics in the expression: 'BCount' and 'ACount'. Rename one/); + }).toThrow(/The ID 'a' used for two metrics in the expression: 'BCount' and 'ACount'. Rename one/); + - test.done(); - }, + }); - 'can not use invalid period in MathExpression'(test: Test) { - test.throws(() => { + test('can not use invalid period in MathExpression', () => { + expect(() => { new MathExpression({ expression: 'a+b', usingMetrics: { a, b }, period: Duration.seconds(20), }); - }, /'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received 20/); + }).toThrow(/'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received 20/); + - test.done(); - }, + }); - 'MathExpression optimization: "with" with the same period returns the same object'(test: Test) { + test('MathExpression optimization: "with" with the same period returns the same object', () => { const m = new MathExpression({ expression: 'SUM(METRICS())', usingMetrics: {}, period: Duration.minutes(10) }); // Note: object equality, NOT deep equality on purpose - test.equals(m.with({}), m); - test.equals(m.with({ period: Duration.minutes(10) }), m); + expect(m.with({})).toEqual(m); + expect(m.with({ period: Duration.minutes(10) })).toEqual(m); - test.notEqual(m.with({ period: Duration.minutes(5) }), m); + expect(m.with({ period: Duration.minutes(5) })).not.toEqual(m); - test.done(); - }, - 'in graphs': { - 'MathExpressions can be added to a graph'(test: Test) { + }); + + describe('in graphs', () => { + test('MathExpressions can be added to a graph', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -84,16 +82,16 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ [{ expression: 'a + b', label: 'a + b' }], ['Test', 'ACount', { visible: false, id: 'a' }], ['Test', 'BCount', { visible: false, id: 'b' }], ]); - test.done(); - }, - 'can nest MathExpressions in a graph'(test: Test) { + }); + + test('can nest MathExpressions in a graph', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -111,7 +109,7 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ [{ label: 'a + e', expression: 'a + e' }], ['Test', 'ACount', { visible: false, id: 'a' }], [{ expression: 'b + c', visible: false, id: 'e' }], @@ -119,10 +117,10 @@ export = { ['Test', 'CCount', { visible: false, id: 'c' }], ]); - test.done(); - }, - 'can add the same metric under different ids'(test: Test) { + }); + + test('can add the same metric under different ids', () => { const graph = new GraphWidget({ left: [ new MathExpression({ @@ -138,7 +136,7 @@ export = { ], }); - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ [{ label: 'a + e', expression: 'a + e' }], ['Test', 'ACount', { visible: false, id: 'a' }], [{ expression: 'b + c', visible: false, id: 'e' }], @@ -146,10 +144,10 @@ export = { ['Test', 'CCount', { visible: false, id: 'c' }], ]); - test.done(); - }, - 'can reuse identifiers in MathExpressions if metrics are the same'(test: Test) { + }); + + test('can reuse identifiers in MathExpressions if metrics are the same', () => { const graph = new GraphWidget({ left: [ new MathExpression({ @@ -166,17 +164,17 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ [{ label: 'a + e', expression: 'a + e' }], ['Test', 'ACount', { visible: false, id: 'a' }], [{ expression: 'a + c', visible: false, id: 'e' }], ['Test', 'CCount', { visible: false, id: 'c' }], ]); - test.done(); - }, - 'MathExpression and its constituent metrics can both be added to a graph'(test: Test) { + }); + + test('MathExpression and its constituent metrics can both be added to a graph', () => { const graph = new GraphWidget({ left: [ a, @@ -188,15 +186,15 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ ['Test', 'ACount', { id: 'a' }], [{ label: 'a + b', expression: 'a + b' }], ['Test', 'BCount', { visible: false, id: 'b' }], ]); - test.done(); - }, - 'MathExpression controls period of metrics directly used in it'(test: Test) { + }); + + test('MathExpression controls period of metrics directly used in it', () => { // Check that if we add A with { period: 10s } to a mathexpression of period 5m // then two metric lines are added for A, one at 10s and one at 5m const graph = new GraphWidget({ @@ -210,16 +208,16 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ ['Test', 'ACount', { period: 10 }], [{ label: 'a + b', expression: 'a + b' }], ['Test', 'ACount', { visible: false, id: 'a' }], ['Test', 'BCount', { visible: false, id: 'b' }], ]); - test.done(); - }, - 'top level period in a MathExpression is respected in its metrics'(test: Test) { + }); + + test('top level period in a MathExpression is respected in its metrics', () => { const graph = new GraphWidget({ left: [ a, @@ -232,16 +230,16 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ ['Test', 'ACount'], [{ label: 'a + b', expression: 'a + b', period: 60 }], ['Test', 'ACount', { visible: false, id: 'a', period: 60 }], ['Test', 'BCount', { visible: false, id: 'b', period: 60 }], ]); - test.done(); - }, - 'MathExpression controls period of metrics transitively used in it'(test: Test) { + }); + + test('MathExpression controls period of metrics transitively used in it', () => { // Same as the previous test, but recursively const graph = new GraphWidget({ @@ -261,16 +259,16 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ [{ expression: 'a + e', label: 'a + e' }], ['Test', 'ACount', { visible: false, id: 'a' }], [{ expression: 'a + b', visible: false, id: 'e' }], ['Test', 'BCount', { visible: false, id: 'b' }], ]); - test.done(); - }, - 'can use percentiles in expression metrics in graphs'(test: Test) { + }); + + test('can use percentiles in expression metrics in graphs', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -282,16 +280,16 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ [{ expression: 'a + b99', label: 'a + b99' }], ['Test', 'ACount', { visible: false, id: 'a' }], ['Test', 'BCount', { visible: false, id: 'b99', stat: 'p99' }], ]); - test.done(); - }, - 'can reuse the same metric between left and right axes'(test: Test) { + }); + + test('can reuse the same metric between left and right axes', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -309,16 +307,16 @@ export = { }); // THEN - graphMetricsAre(test, graph, [ + graphMetricsAre(graph, [ [{ label: 'a + 1', expression: 'a + 1' }], ['Test', 'ACount', { visible: false, id: 'a' }], [{ label: 'a + 2', expression: 'a + 2', yAxis: 'right' }], ]); - test.done(); - }, - 'detect name conflicts between left and right axes'(test: Test) { + }); + + test('detect name conflicts between left and right axes', () => { // GIVEN const graph = new GraphWidget({ left: [ @@ -336,16 +334,16 @@ export = { }); // THEN - test.throws(() => { - graphMetricsAre(test, graph, []); - }, /Cannot have two different metrics share the same id \('m1'\)/); + expect(() => { + graphMetricsAre(graph, []); + }).toThrow(/Cannot have two different metrics share the same id \('m1'\)/); - test.done(); - }, - }, - 'in alarms': { - 'MathExpressions can be used for an alarm'(test: Test) { + }); + }); + + describe('in alarms', () => { + test('MathExpressions can be used for an alarm', () => { // GIVEN new Alarm(stack, 'Alarm', { threshold: 1, @@ -389,10 +387,10 @@ export = { ]); - test.done(); - }, - 'can nest MathExpressions in an alarm'(test: Test) { + }); + + test('can nest MathExpressions in an alarm', () => { // GIVEN new Alarm(stack, 'Alarm', { threshold: 1, @@ -458,10 +456,10 @@ export = { }, ]); - test.done(); - }, - 'MathExpression controls period of metrics transitively used in it with alarms'(test: Test) { + }); + + test('MathExpression controls period of metrics transitively used in it with alarms', () => { // GIVEN new Alarm(stack, 'Alarm', { threshold: 1, @@ -529,10 +527,10 @@ export = { }, ]); - test.done(); - }, - 'MathExpression without inner metrics emits its own period'(test: Test) { + }); + + test('MathExpression without inner metrics emits its own period', () => { // WHEN new Alarm(stack, 'Alarm', { threshold: 1, @@ -552,10 +550,10 @@ export = { }, ]); - test.done(); - }, - 'annotation for a mathexpression alarm is calculated based upon constituent metrics'(test: Test) { + }); + + test('annotation for a mathexpression alarm is calculated based upon constituent metrics', () => { // GIVEN const alarm = new Alarm(stack, 'Alarm', { threshold: 1, @@ -571,12 +569,12 @@ export = { const alarmLabel = alarm.toAnnotation().label; // THEN - test.equals(alarmLabel, 'a + b >= 1 for 1 datapoints within 10 minutes'); + expect(alarmLabel).toEqual('a + b >= 1 for 1 datapoints within 10 minutes'); - test.done(); - }, - 'can use percentiles in expression metrics in alarms'(test: Test) { + }); + + test('can use percentiles in expression metrics in alarms', () => { // GIVEN new Alarm(stack, 'Alarm', { threshold: 1, @@ -619,13 +617,13 @@ export = { }, ]); - test.done(); - }, - }, -}; -function graphMetricsAre(test: Test, w: IWidget, metrics: any[]) { - test.deepEqual(stack.resolve(w.toJson()), [{ + }); + }); +}); + +function graphMetricsAre(w: IWidget, metrics: any[]) { + expect(stack.resolve(w.toJson())).toEqual([{ type: 'metric', width: 6, height: 6, @@ -640,7 +638,7 @@ function graphMetricsAre(test: Test, w: IWidget, metrics: any[]) { } function alarmMetricsAre(metrics: any[]) { - expect(stack).to(haveResourceLike('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResourceLike('AWS::CloudWatch::Alarm', { Metrics: metrics, - })); + }); } diff --git a/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts b/packages/@aws-cdk/aws-cloudwatch/test/metrics.test.ts similarity index 64% rename from packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts rename to packages/@aws-cdk/aws-cloudwatch/test/metrics.test.ts index dc55f7a2bb0e7..dc958860b6a4c 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/test.metrics.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/metrics.test.ts @@ -1,11 +1,10 @@ -import { expect, haveResource, haveResourceLike } from '@aws-cdk/assert-internal'; +import '@aws-cdk/assert-internal/jest'; import * as iam from '@aws-cdk/aws-iam'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import { Alarm, Metric } from '../lib'; -export = { - 'metric grant'(test: Test) { +describe('Metrics', () => { + test('metric grant', () => { // GIVEN const stack = new cdk.Stack(); const role = new iam.Role(stack, 'SomeRole', { @@ -16,7 +15,7 @@ export = { Metric.grantPutMetricData(role); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + expect(stack).toHaveResource('AWS::IAM::Policy', { PolicyDocument: { Version: '2012-10-17', Statement: [ @@ -27,33 +26,33 @@ export = { }, ], }, - })); + }); + - test.done(); - }, + }); - 'can not use invalid period in Metric'(test: Test) { - test.throws(() => { + test('can not use invalid period in Metric', () => { + expect(() => { new Metric({ namespace: 'Test', metricName: 'ACount', period: cdk.Duration.seconds(20) }); - }, /'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received 20/); + }).toThrow(/'period' must be 1, 5, 10, 30, or a multiple of 60 seconds, received 20/); - test.done(); - }, - 'Metric optimization: "with" with the same period returns the same object'(test: Test) { + }); + + test('Metric optimization: "with" with the same period returns the same object', () => { const m = new Metric({ namespace: 'Test', metricName: 'Metric', period: cdk.Duration.minutes(10) }); // Note: object equality, NOT deep equality on purpose - test.equals(m.with({}), m); - test.equals(m.with({ period: cdk.Duration.minutes(10) }), m); + expect(m.with({})).toEqual(m); + expect(m.with({ period: cdk.Duration.minutes(10) })).toEqual(m); + + expect(m.with({ period: cdk.Duration.minutes(5) })).not.toEqual(m); - test.notEqual(m.with({ period: cdk.Duration.minutes(5) }), m); - test.done(); - }, + }); - 'cannot use null dimension value'(test: Test) { - test.throws(() => { + test('cannot use null dimension value', () => { + expect(() => { new Metric({ namespace: 'Test', metricName: 'ACount', @@ -62,13 +61,13 @@ export = { DimensionWithNull: null, }, }); - }, /Dimension value of 'null' is invalid/); + }).toThrow(/Dimension value of 'null' is invalid/); - test.done(); - }, - 'cannot use undefined dimension value'(test: Test) { - test.throws(() => { + }); + + test('cannot use undefined dimension value', () => { + expect(() => { new Metric({ namespace: 'Test', metricName: 'ACount', @@ -77,16 +76,16 @@ export = { DimensionWithUndefined: undefined, }, }); - }, /Dimension value of 'undefined' is invalid/); + }).toThrow(/Dimension value of 'undefined' is invalid/); + - test.done(); - }, + }); - 'cannot use long dimension values'(test: Test) { + test('cannot use long dimension values', () => { const arr = new Array(256); const invalidDimensionValue = arr.fill('A', 0).join(''); - test.throws(() => { + expect(() => { new Metric({ namespace: 'Test', metricName: 'ACount', @@ -95,16 +94,16 @@ export = { DimensionWithLongValue: invalidDimensionValue, }, }); - }, `Dimension value must be at least 1 and no more than 255 characters; received ${invalidDimensionValue}`); + }).toThrow(`Dimension value must be at least 1 and no more than 255 characters; received ${invalidDimensionValue}`); + - test.done(); - }, + }); - 'cannot use long dimension values in dimensionsMap'(test: Test) { + test('cannot use long dimension values in dimensionsMap', () => { const arr = new Array(256); const invalidDimensionValue = arr.fill('A', 0).join(''); - test.throws(() => { + expect(() => { new Metric({ namespace: 'Test', metricName: 'ACount', @@ -113,13 +112,13 @@ export = { DimensionWithLongValue: invalidDimensionValue, }, }); - }, `Dimension value must be at least 1 and no more than 255 characters; received ${invalidDimensionValue}`); + }).toThrow(`Dimension value must be at least 1 and no more than 255 characters; received ${invalidDimensionValue}`); - test.done(); - }, - 'throws error when there are more than 10 dimensions'(test: Test) { - test.throws(() => { + }); + + test('throws error when there are more than 10 dimensions', () => { + expect(() => { new Metric({ namespace: 'Test', metricName: 'ACount', @@ -138,13 +137,13 @@ export = { dimensionK: 'value11', }, } ); - }, /The maximum number of dimensions is 10, received 11/); + }).toThrow(/The maximum number of dimensions is 10, received 11/); + - test.done(); - }, + }); - 'throws error when there are more than 10 dimensions in dimensionsMap'(test: Test) { - test.throws(() => { + test('throws error when there are more than 10 dimensions in dimensionsMap', () => { + expect(() => { new Metric({ namespace: 'Test', metricName: 'ACount', @@ -163,12 +162,12 @@ export = { dimensionK: 'value11', }, } ); - }, /The maximum number of dimensions is 10, received 11/); + }).toThrow(/The maximum number of dimensions is 10, received 11/); - test.done(); - }, - 'can create metric with dimensionsMap property'(test: Test) { + }); + + test('can create metric with dimensionsMap property', () => { const stack = new cdk.Stack(); const metric = new Metric({ namespace: 'Test', @@ -185,11 +184,11 @@ export = { evaluationPeriods: 1, }); - test.deepEqual(metric.dimensions, { + expect(metric.dimensions).toEqual({ dimensionA: 'value1', dimensionB: 'value2', }); - expect(stack).to(haveResourceLike('AWS::CloudWatch::Alarm', { + expect(stack).toHaveResourceLike('AWS::CloudWatch::Alarm', { Namespace: 'Test', MetricName: 'Metric', Dimensions: [ @@ -204,12 +203,12 @@ export = { ], Threshold: 10, EvaluationPeriods: 1, - })); + }); - test.done(); - }, - '"with" with a different dimensions property'(test: Test) { + }); + + test('"with" with a different dimensions property', () => { const dims = { dimensionA: 'value1', }; @@ -225,20 +224,20 @@ export = { dimensionB: 'value2', }; - test.deepEqual(metric.with({ + expect(metric.with({ dimensionsMap: newDims, - }).dimensions, newDims); + }).dimensions).toEqual(newDims); + - test.done(); - }, + }); - 'metric accepts a variety of statistics'(test: Test) { + test('metric accepts a variety of statistics', () => { new Metric({ namespace: 'Test', metricName: 'Metric', statistic: 'myCustomStatistic', }); - test.done(); - }, -}; + + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/.gitignore b/packages/@aws-cdk/aws-lambda-event-sources/.gitignore index d0a956699806b..be330198b9888 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/.gitignore +++ b/packages/@aws-cdk/aws-lambda-event-sources/.gitignore @@ -16,4 +16,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-event-sources/.npmignore b/packages/@aws-cdk/aws-lambda-event-sources/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/.npmignore +++ b/packages/@aws-cdk/aws-lambda-event-sources/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js b/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js new file mode 100644 index 0000000000000..cd664e1d069e5 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-event-sources/jest.config.js @@ -0,0 +1,2 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = baseConfig; diff --git a/packages/@aws-cdk/aws-lambda-event-sources/package.json b/packages/@aws-cdk/aws-lambda-event-sources/package.json index 8a1897a9fc7a5..0db8f4d09f9a6 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/package.json +++ b/packages/@aws-cdk/aws-lambda-event-sources/package.json @@ -64,12 +64,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@types/nodeunit": "^0.0.32", + "@types/jest": "^26.0.24", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", - "nodeunit": "^0.11.3", + "jest": "^26.6.3", "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "@aws-cdk/assertions": "0.0.0" }, "dependencies": { "@aws-cdk/aws-apigateway": "0.0.0", @@ -129,6 +129,7 @@ }, "maturity": "stable", "cdk-build": { + "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.api.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/api.test.ts similarity index 66% rename from packages/@aws-cdk/aws-lambda-event-sources/test/test.api.ts rename to packages/@aws-cdk/aws-lambda-event-sources/test/api.test.ts index b4aea8a304a16..b0b2e9fb5ec71 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.api.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/api.test.ts @@ -1,11 +1,10 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions } from '@aws-cdk/assertions'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as events from '../lib'; -export = { - 'minimal example'(test: Test) { +describe('ApiEventSource', () => { + test('minimal example', () => { // GIVEN const stack = new cdk.Stack(); const handler = new lambda.Function(stack, 'MyFunc', { @@ -18,20 +17,20 @@ export = { handler.addEventSource(new events.ApiEventSource('get', '/foo')); // THEN - expect(stack).to(haveResource('AWS::ApiGateway::Resource', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Resource', { PathPart: 'foo', ParentId: { 'Fn::GetAtt': ['MyFuncApiEventSourceA7A86A4FFB3F557C', 'RootResourceId'] }, - })); + }); - expect(stack).to(haveResource('AWS::ApiGateway::Method', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', { HttpMethod: 'GET', ResourceId: { Ref: 'MyFuncApiEventSourceA7A86A4FfooCA6F87E4' }, - })); + }); - test.done(); - }, - 'disjoint routes'(test: Test) { + }); + + test('disjoint routes', () => { // GIVEN const stack = new cdk.Stack(); const handler = new lambda.Function(stack, 'MyFunc', { @@ -45,30 +44,30 @@ export = { handler.addEventSource(new events.ApiEventSource('post', '/bar')); // THEN - expect(stack).to(haveResource('AWS::ApiGateway::Resource', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Resource', { PathPart: 'foo', ParentId: { 'Fn::GetAtt': ['MyFuncApiEventSourceA7A86A4FFB3F557C', 'RootResourceId'] }, - })); + }); - expect(stack).to(haveResource('AWS::ApiGateway::Resource', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Resource', { PathPart: 'bar', ParentId: { 'Fn::GetAtt': ['MyFuncApiEventSourceA7A86A4FFB3F557C', 'RootResourceId'] }, - })); + }); - expect(stack).to(haveResource('AWS::ApiGateway::Method', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', { HttpMethod: 'GET', ResourceId: { Ref: 'MyFuncApiEventSourceA7A86A4FfooCA6F87E4' }, - })); + }); - expect(stack).to(haveResource('AWS::ApiGateway::Method', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', { HttpMethod: 'POST', ResourceId: { Ref: 'MyFuncApiEventSourceA7A86A4FbarDFB0F21B' }, - })); + }); - test.done(); - }, - 'tree of routes'(test: Test) { + }); + + test('tree of routes', () => { // GIVEN const stack = new cdk.Stack(); const handler = new lambda.Function(stack, 'MyFunc', { @@ -83,26 +82,26 @@ export = { handler.addEventSource(new events.ApiEventSource('post', '/foo/bar/zoo')); // THEN - expect(stack).to(haveResource('AWS::ApiGateway::Resource', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Resource', { PathPart: 'foo', ParentId: { 'Fn::GetAtt': ['MyFuncApiEventSourceA7A86A4FFB3F557C', 'RootResourceId'] }, - })); + }); - expect(stack).to(haveResource('AWS::ApiGateway::Resource', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Resource', { PathPart: 'bar', ParentId: { Ref: 'MyFuncApiEventSourceA7A86A4FfooCA6F87E4' }, - })); + }); - expect(stack).to(haveResource('AWS::ApiGateway::Method', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', { HttpMethod: 'GET', ResourceId: { Ref: 'MyFuncApiEventSourceA7A86A4FfooCA6F87E4' }, - })); + }); - expect(stack).to(haveResource('AWS::ApiGateway::Method', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Method', { HttpMethod: 'POST', ResourceId: { Ref: 'MyFuncApiEventSourceA7A86A4Ffoobar028FFFDE' }, - })); + }); + - test.done(); - }, -}; + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.dynamo.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/dynamo.test.ts similarity index 77% rename from packages/@aws-cdk/aws-lambda-event-sources/test/test.dynamo.ts rename to packages/@aws-cdk/aws-lambda-event-sources/test/dynamo.test.ts index d79a8f17020ed..8ea8da3c026f4 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.dynamo.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/dynamo.test.ts @@ -1,16 +1,15 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions } from '@aws-cdk/assertions'; import * as dynamodb from '@aws-cdk/aws-dynamodb'; import * as lambda from '@aws-cdk/aws-lambda'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as sources from '../lib'; import { TestFunction } from './test-function'; /* eslint-disable quote-props */ -export = { - 'sufficiently complex example'(test: Test) { +describe('DynamoEventSource', () => { + test('sufficiently complex example', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -28,7 +27,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -57,9 +56,9 @@ export = { 'Roles': [{ 'Ref': 'FnServiceRoleB9001A96', }], - })); + }); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -71,12 +70,12 @@ export = { }, 'BatchSize': 100, 'StartingPosition': 'TRIM_HORIZON', - })); + }); + - test.done(); - }, + }); - 'specific tumblingWindow'(test: Test) { + test('specific tumblingWindow', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -96,14 +95,14 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { TumblingWindowInSeconds: 60, - })); + }); + - test.done(); - }, + }); - 'specific batch size'(test: Test) { + test('specific batch size', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -122,7 +121,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -134,12 +133,12 @@ export = { }, 'BatchSize': 50, 'StartingPosition': 'LATEST', - })); + }); + - test.done(); - }, + }); - 'fails if streaming not enabled on table'(test: Test) { + test('fails if streaming not enabled on table', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -151,15 +150,15 @@ export = { }); // WHEN - test.throws(() => fn.addEventSource(new sources.DynamoEventSource(table, { + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { batchSize: 50, startingPosition: lambda.StartingPosition.LATEST, - })), /DynamoDB Streams must be enabled on the table Default\/T/); + }))).toThrow(/DynamoDB Streams must be enabled on the table Default\/T/); + - test.done(); - }, + }); - 'fails if batch size < 1'(test: Test) { + test('fails if batch size < 1', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -172,15 +171,15 @@ export = { }); // WHEN - test.throws(() => fn.addEventSource(new sources.DynamoEventSource(table, { + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { batchSize: 0, startingPosition: lambda.StartingPosition.LATEST, - })), /Maximum batch size must be between 1 and 1000 inclusive \(given 0\)/); + }))).toThrow(/Maximum batch size must be between 1 and 1000 inclusive \(given 0\)/); - test.done(); - }, - 'fails if batch size > 1000'(test: Test) { + }); + + test('fails if batch size > 1000', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -193,15 +192,15 @@ export = { }); // WHEN - test.throws(() => fn.addEventSource(new sources.DynamoEventSource(table, { + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { batchSize: 1001, startingPosition: lambda.StartingPosition.LATEST, - })), /Maximum batch size must be between 1 and 1000 inclusive \(given 1001\)/); + }))).toThrow(/Maximum batch size must be between 1 and 1000 inclusive \(given 1001\)/); + - test.done(); - }, + }); - 'specific maxBatchingWindow'(test: Test) { + test('specific maxBatchingWindow', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -220,7 +219,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -232,12 +231,12 @@ export = { }, 'MaximumBatchingWindowInSeconds': 120, 'StartingPosition': 'LATEST', - })); + }); + - test.done(); - }, + }); - 'throws if maxBatchingWindow > 300 seconds'(test: Test) { + test('throws if maxBatchingWindow > 300 seconds', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -250,16 +249,16 @@ export = { }); // THEN - test.throws(() => + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { maxBatchingWindow: cdk.Duration.seconds(301), startingPosition: lambda.StartingPosition.LATEST, - })), /maxBatchingWindow cannot be over 300 seconds/); + }))).toThrow(/maxBatchingWindow cannot be over 300 seconds/); + - test.done(); - }, + }); - 'contains eventSourceMappingId after lambda binding'(test: Test) { + test('contains eventSourceMappingId after lambda binding', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -278,11 +277,11 @@ export = { fn.addEventSource(eventSource); // THEN - test.ok(eventSource.eventSourceMappingId); - test.done(); - }, + expect(eventSource.eventSourceMappingId).toBeDefined(); - 'eventSourceMappingId throws error before binding to lambda'(test: Test) { + }); + + test('eventSourceMappingId throws error before binding to lambda', () => { // GIVEN const stack = new cdk.Stack(); const table = new dynamodb.Table(stack, 'T', { @@ -297,11 +296,11 @@ export = { }); // WHEN/THEN - test.throws(() => eventSource.eventSourceMappingId, /DynamoEventSource is not yet bound to an event source mapping/); - test.done(); - }, + expect(() => eventSource.eventSourceMappingId).toThrow(/DynamoEventSource is not yet bound to an event source mapping/); + + }); - 'specific retryAttempts'(test: Test) { + test('specific retryAttempts', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -320,7 +319,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -332,12 +331,12 @@ export = { }, 'MaximumRetryAttempts': 10, 'StartingPosition': 'LATEST', - })); + }); + - test.done(); - }, + }); - 'fails if retryAttempts < 0'(test: Test) { + test('fails if retryAttempts < 0', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -350,16 +349,16 @@ export = { }); // THEN - test.throws(() => + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { retryAttempts: -1, startingPosition: lambda.StartingPosition.LATEST, - })), /retryAttempts must be between 0 and 10000 inclusive, got -1/); + }))).toThrow(/retryAttempts must be between 0 and 10000 inclusive, got -1/); + - test.done(); - }, + }); - 'fails if retryAttempts > 10000'(test: Test) { + test('fails if retryAttempts > 10000', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -372,16 +371,16 @@ export = { }); // THEN - test.throws(() => + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { retryAttempts: 10001, startingPosition: lambda.StartingPosition.LATEST, - })), /retryAttempts must be between 0 and 10000 inclusive, got 10001/); + }))).toThrow(/retryAttempts must be between 0 and 10000 inclusive, got 10001/); - test.done(); - }, - 'specific bisectBatchOnFunctionError'(test: Test) { + }); + + test('specific bisectBatchOnFunctionError', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -400,7 +399,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -412,12 +411,12 @@ export = { }, 'BisectBatchOnFunctionError': true, 'StartingPosition': 'LATEST', - })); + }); - test.done(); - }, - 'specific parallelizationFactor'(test: Test) { + }); + + test('specific parallelizationFactor', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -436,7 +435,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -448,12 +447,12 @@ export = { }, 'ParallelizationFactor': 5, 'StartingPosition': 'LATEST', - })); + }); - test.done(); - }, - 'fails if parallelizationFactor < 1'(test: Test) { + }); + + test('fails if parallelizationFactor < 1', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -466,16 +465,16 @@ export = { }); // THEN - test.throws(() => + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { parallelizationFactor: 0, startingPosition: lambda.StartingPosition.LATEST, - })), /parallelizationFactor must be between 1 and 10 inclusive, got 0/); + }))).toThrow(/parallelizationFactor must be between 1 and 10 inclusive, got 0/); + - test.done(); - }, + }); - 'fails if parallelizationFactor > 10'(test: Test) { + test('fails if parallelizationFactor > 10', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -488,16 +487,16 @@ export = { }); // THEN - test.throws(() => + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { parallelizationFactor: 11, startingPosition: lambda.StartingPosition.LATEST, - })), /parallelizationFactor must be between 1 and 10 inclusive, got 11/); + }))).toThrow(/parallelizationFactor must be between 1 and 10 inclusive, got 11/); + - test.done(); - }, + }); - 'specific maxRecordAge'(test: Test) { + test('specific maxRecordAge', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -516,7 +515,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -528,12 +527,12 @@ export = { }, 'MaximumRecordAgeInSeconds': 100, 'StartingPosition': 'LATEST', - })); + }); + - test.done(); - }, + }); - 'fails if maxRecordAge < 60 seconds'(test: Test) { + test('fails if maxRecordAge < 60 seconds', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -546,16 +545,16 @@ export = { }); // THEN - test.throws(() => + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { maxRecordAge: cdk.Duration.seconds(59), startingPosition: lambda.StartingPosition.LATEST, - })), /maxRecordAge must be between 60 seconds and 7 days inclusive/); + }))).toThrow(/maxRecordAge must be between 60 seconds and 7 days inclusive/); - test.done(); - }, - 'fails if maxRecordAge > 7 days'(test: Test) { + }); + + test('fails if maxRecordAge > 7 days', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -568,16 +567,16 @@ export = { }); // THEN - test.throws(() => + expect(() => fn.addEventSource(new sources.DynamoEventSource(table, { maxRecordAge: cdk.Duration.seconds(604801), startingPosition: lambda.StartingPosition.LATEST, - })), /maxRecordAge must be between 60 seconds and 7 days inclusive/); + }))).toThrow(/maxRecordAge must be between 60 seconds and 7 days inclusive/); + - test.done(); - }, + }); - 'specific destinationConfig'(test: Test) { + test('specific destinationConfig', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -597,7 +596,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -619,12 +618,12 @@ export = { }, }, 'StartingPosition': 'LATEST', - })); + }); + - test.done(); - }, + }); - 'specific functionResponseTypes'(test: Test) { + test('specific functionResponseTypes', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -643,7 +642,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'TD925BC7E', @@ -655,12 +654,12 @@ export = { }, 'StartingPosition': 'LATEST', 'FunctionResponseTypes': ['ReportBatchItemFailures'], - })); + }); + - test.done(); - }, + }); - 'event source disabled'(test: Test) { + test('event source disabled', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -679,10 +678,10 @@ export = { })); //THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'Enabled': false, - })); + }); + - test.done(); - }, -}; + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kafka.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/kafka.test.ts similarity index 84% rename from packages/@aws-cdk/aws-lambda-event-sources/test/test.kafka.ts rename to packages/@aws-cdk/aws-lambda-event-sources/test/kafka.test.ts index 615f3bcbc7d51..1b973242f2f3c 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kafka.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/kafka.test.ts @@ -1,15 +1,14 @@ -import { arrayWith, expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions, Match } from '@aws-cdk/assertions'; import { SecurityGroup, SubnetType, Vpc } from '@aws-cdk/aws-ec2'; import * as lambda from '@aws-cdk/aws-lambda'; import { Secret } from '@aws-cdk/aws-secretsmanager'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as sources from '../lib'; import { TestFunction } from './test-function'; -export = { - 'msk': { - 'default'(test: Test) { +describe('KafkaEventSource', () => { + describe('msk', () => { + test('default', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -25,7 +24,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -46,9 +45,9 @@ export = { Ref: 'FnServiceRoleB9001A96', }, ], - })); + }); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { EventSourceArn: clusterArn, FunctionName: { Ref: 'Fn9270CBC0', @@ -58,11 +57,11 @@ export = { Topics: [ kafkaTopic, ], - })); + }); - test.done(); - }, - 'with secret'(test: Test) { + + }); + test('with secret', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -80,7 +79,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -111,9 +110,9 @@ export = { Ref: 'FnServiceRoleB9001A96', }, ], - })); + }); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { EventSourceArn: clusterArn, FunctionName: { Ref: 'Fn9270CBC0', @@ -131,14 +130,14 @@ export = { }, }, ], - })); + }); + - test.done(); - }, - }, + }); + }); - 'self-managed kafka': { - 'default'(test: Test) { + describe('self-managed kafka', () => { + test('default', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -156,7 +155,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -178,9 +177,9 @@ export = { Ref: 'FnServiceRoleB9001A96', }, ], - })); + }); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { FunctionName: { Ref: 'Fn9270CBC0', }, @@ -202,30 +201,30 @@ export = { }, }, ], - })); + }); + - test.done(); - }, - 'without vpc, secret must be set'(test: Test) { + }); + test('without vpc, secret must be set', () => { const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const kafkaTopic = 'some-topic'; const bootstrapServers = ['kafka-broker:9092']; - test.throws(() => { + expect(() => { fn.addEventSource(new sources.SelfManagedKafkaEventSource( { bootstrapServers: bootstrapServers, topic: kafkaTopic, startingPosition: lambda.StartingPosition.TRIM_HORIZON, })); - }, /secret must be set/); + }).toThrow(/secret must be set/); - test.done(); - }, - VPC: { - 'correctly rendered in the stack'(test: Test) { + }); + + describe('vpc', () => { + test('correctly rendered in the stack', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -246,8 +245,8 @@ export = { })); // THEN - expect(stack).notTo(haveResource('AWS::IAM::Policy')); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).resourceCountIs('AWS::IAM::Policy', 0); + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { FunctionName: { Ref: 'Fn9270CBC0', }, @@ -279,11 +278,11 @@ export = { }, }, ], - })); + }); + - test.done(); - }, - 'with secret'(test: Test) { + }); + test('with secret', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -306,7 +305,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { PolicyDocument: { Statement: [ { @@ -328,9 +327,9 @@ export = { Ref: 'FnServiceRoleB9001A96', }, ], - })); + }); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { FunctionName: { Ref: 'Fn9270CBC0', }, @@ -368,11 +367,11 @@ export = { }, }, ], - })); + }); + - test.done(); - }, - 'setting vpc requires vpcSubnets to be set'(test: Test) { + }); + test('setting vpc requires vpcSubnets to be set', () => { const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const kafkaTopic = 'some-topic'; @@ -380,7 +379,7 @@ export = { const bootstrapServers = ['kafka-broker:9092']; const vpc = new Vpc(stack, 'Vpc'); - test.throws(() => { + expect(() => { fn.addEventSource(new sources.SelfManagedKafkaEventSource( { bootstrapServers: bootstrapServers, @@ -391,12 +390,12 @@ export = { securityGroup: SecurityGroup.fromSecurityGroupId(stack, 'SecurityGroup', 'sg-0123456789'), })); - }, /vpcSubnets must be set/); + }).toThrow(/vpcSubnets must be set/); - test.done(); - }, - 'setting vpc requires securityGroup to be set'(test: Test) { + }); + + test('setting vpc requires securityGroup to be set', () => { const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const kafkaTopic = 'some-topic'; @@ -404,7 +403,7 @@ export = { const bootstrapServers = ['kafka-broker:9092']; const vpc = new Vpc(stack, 'Vpc'); - test.throws(() => { + expect(() => { fn.addEventSource(new sources.SelfManagedKafkaEventSource( { bootstrapServers: bootstrapServers, @@ -414,13 +413,13 @@ export = { vpc: vpc, vpcSubnets: { subnetType: SubnetType.PRIVATE }, })); - }, /securityGroup must be set/); + }).toThrow(/securityGroup must be set/); + - test.done(); - }, - }, + }); + }); - 'using SCRAM-SHA-256'(test: Test) { + test('using SCRAM-SHA-256', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -443,19 +442,19 @@ export = { authenticationMethod: sources.AuthenticationMethod.SASL_SCRAM_256_AUTH, })); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { - SourceAccessConfigurations: arrayWith( + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { + SourceAccessConfigurations: Match.arrayWith([ { Type: 'SASL_SCRAM_256_AUTH', URI: { Ref: 'SecretA720EF05', }, }, - ), - })); + ]), + }); + - test.done(); - }, - }, + }); + }); -} +}); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kinesis.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/kinesis.test.ts similarity index 74% rename from packages/@aws-cdk/aws-lambda-event-sources/test/test.kinesis.ts rename to packages/@aws-cdk/aws-lambda-event-sources/test/kinesis.test.ts index dc3ff6e6637d1..b8217be186f0f 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.kinesis.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/kinesis.test.ts @@ -1,15 +1,14 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions } from '@aws-cdk/assertions'; import * as kinesis from '@aws-cdk/aws-kinesis'; import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as sources from '../lib'; import { TestFunction } from './test-function'; /* eslint-disable quote-props */ -export = { - 'sufficiently complex example'(test: Test) { +describe('KinesisEventSource', () => { + test('sufficiently complex example', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -21,7 +20,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -57,9 +56,9 @@ export = { 'Roles': [{ 'Ref': 'FnServiceRoleB9001A96', }], - })); + }); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'S509448A1', @@ -71,12 +70,12 @@ export = { }, 'BatchSize': 100, 'StartingPosition': 'TRIM_HORIZON', - })); + }); + - test.done(); - }, + }); - 'specific tumblingWindowInSeconds'(test: Test) { + test('specific tumblingWindowInSeconds', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -90,7 +89,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'S509448A1', @@ -103,12 +102,12 @@ export = { 'BatchSize': 50, 'StartingPosition': 'LATEST', 'TumblingWindowInSeconds': 60, - })); + }); + - test.done(); - }, + }); - 'specific batch size'(test: Test) { + test('specific batch size', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -121,7 +120,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'S509448A1', @@ -133,42 +132,42 @@ export = { }, 'BatchSize': 50, 'StartingPosition': 'LATEST', - })); + }); + - test.done(); - }, + }); - 'fails if batch size < 1'(test: Test) { + test('fails if batch size < 1', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const stream = new kinesis.Stream(stack, 'S'); // WHEN - test.throws(() => fn.addEventSource(new sources.KinesisEventSource(stream, { + expect(() => fn.addEventSource(new sources.KinesisEventSource(stream, { batchSize: 0, startingPosition: lambda.StartingPosition.LATEST, - })), /Maximum batch size must be between 1 and 10000 inclusive \(given 0\)/); + }))).toThrow(/Maximum batch size must be between 1 and 10000 inclusive \(given 0\)/); - test.done(); - }, - 'fails if batch size > 10000'(test: Test) { + }); + + test('fails if batch size > 10000', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const stream = new kinesis.Stream(stack, 'S'); // WHEN - test.throws(() => fn.addEventSource(new sources.KinesisEventSource(stream, { + expect(() => fn.addEventSource(new sources.KinesisEventSource(stream, { batchSize: 10001, startingPosition: lambda.StartingPosition.LATEST, - })), /Maximum batch size must be between 1 and 10000 inclusive \(given 10001\)/); + }))).toThrow(/Maximum batch size must be between 1 and 10000 inclusive \(given 10001\)/); + - test.done(); - }, + }); - 'accepts if batch size is a token'(test: Test) { + test('accepts if batch size is a token', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -180,10 +179,10 @@ export = { startingPosition: lambda.StartingPosition.LATEST, })); - test.done(); - }, - 'specific maxBatchingWindow'(test: Test) { + }); + + test('specific maxBatchingWindow', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -196,7 +195,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'S509448A1', @@ -208,12 +207,12 @@ export = { }, 'MaximumBatchingWindowInSeconds': 120, 'StartingPosition': 'LATEST', - })); + }); + - test.done(); - }, + }); - 'contains eventSourceMappingId after lambda binding'(test: Test) { + test('contains eventSourceMappingId after lambda binding', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -226,11 +225,11 @@ export = { fn.addEventSource(eventSource); // THEN - test.ok(eventSource.eventSourceMappingId); - test.done(); - }, + expect(eventSource.eventSourceMappingId).toBeDefined(); - 'eventSourceMappingId throws error before binding to lambda'(test: Test) { + }); + + test('eventSourceMappingId throws error before binding to lambda', () => { // GIVEN const stack = new cdk.Stack(); const stream = new kinesis.Stream(stack, 'S'); @@ -239,11 +238,11 @@ export = { }); // WHEN/THEN - test.throws(() => eventSource.eventSourceMappingId, /KinesisEventSource is not yet bound to an event source mapping/); - test.done(); - }, + expect(() => eventSource.eventSourceMappingId).toThrow(/KinesisEventSource is not yet bound to an event source mapping/); + + }); - 'event source disabled'(test: Test) { + test('event source disabled', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -257,9 +256,9 @@ export = { fn.addEventSource(eventSource); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'Enabled': false, - })); - test.done(); - }, -}; + }); + + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.s3.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/s3.test.ts similarity index 88% rename from packages/@aws-cdk/aws-lambda-event-sources/test/test.s3.ts rename to packages/@aws-cdk/aws-lambda-event-sources/test/s3.test.ts index f4ab1b3f75d5b..5c77a130fa23f 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.s3.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/s3.test.ts @@ -1,14 +1,13 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions } from '@aws-cdk/assertions'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as sources from '../lib'; import { TestFunction } from './test-function'; /* eslint-disable quote-props */ -export = { - 'sufficiently complex example'(test: Test) { +describe('S3EventSource', () => { + test('sufficiently complex example', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -24,7 +23,7 @@ export = { })); // THEN - expect(stack).to(haveResource('Custom::S3BucketNotifications', { + TemplateAssertions.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', { 'NotificationConfiguration': { 'LambdaFunctionConfigurations': [ { @@ -79,7 +78,6 @@ export = { }, ], }, - })); - test.done(); - }, -}; + }); + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sns.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/sns.test.ts similarity index 77% rename from packages/@aws-cdk/aws-lambda-event-sources/test/test.sns.ts rename to packages/@aws-cdk/aws-lambda-event-sources/test/sns.test.ts index bc7204d056491..498172c2a321e 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sns.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/sns.test.ts @@ -1,15 +1,14 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions } from '@aws-cdk/assertions'; import * as sns from '@aws-cdk/aws-sns'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as sources from '../lib'; import { TestFunction } from './test-function'; /* eslint-disable quote-props */ -export = { - 'sufficiently complex example'(test: Test) { +describe('SNSEventSource', () => { + test('sufficiently complex example', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -19,7 +18,7 @@ export = { fn.addEventSource(new sources.SnsEventSource(topic)); // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { 'Action': 'lambda:InvokeFunction', 'FunctionName': { 'Fn::GetAtt': [ @@ -31,9 +30,9 @@ export = { 'SourceArn': { 'Ref': 'TD925BC7E', }, - })); + }); - expect(stack).to(haveResource('AWS::SNS::Subscription', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { 'Endpoint': { 'Fn::GetAtt': [ 'Fn9270CBC0', @@ -44,12 +43,12 @@ export = { 'TopicArn': { 'Ref': 'TD925BC7E', }, - })); + }); - test.done(); - }, - 'props are passed to subscription'(test: Test) { + }); + + test('props are passed to subscription', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -68,7 +67,7 @@ export = { fn.addEventSource(new sources.SnsEventSource(topic, props)); // THEN - expect(stack).to(haveResource('AWS::Lambda::Permission', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::Permission', { 'Action': 'lambda:InvokeFunction', 'FunctionName': { 'Fn::GetAtt': [ @@ -80,9 +79,9 @@ export = { 'SourceArn': { 'Ref': 'TD925BC7E', }, - })); + }); - expect(stack).to(haveResource('AWS::SNS::Subscription', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { 'Endpoint': { 'Fn::GetAtt': [ 'Fn9270CBC0', @@ -107,8 +106,8 @@ export = { ], }, }, - })); + }); + - test.done(); - }, -}; + }); +}); diff --git a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sqs.ts b/packages/@aws-cdk/aws-lambda-event-sources/test/sqs.test.ts similarity index 62% rename from packages/@aws-cdk/aws-lambda-event-sources/test/test.sqs.ts rename to packages/@aws-cdk/aws-lambda-event-sources/test/sqs.test.ts index 0840546569c4e..b6b12c3b17a63 100644 --- a/packages/@aws-cdk/aws-lambda-event-sources/test/test.sqs.ts +++ b/packages/@aws-cdk/aws-lambda-event-sources/test/sqs.test.ts @@ -1,14 +1,13 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions } from '@aws-cdk/assertions'; import * as sqs from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as sources from '../lib'; import { TestFunction } from './test-function'; /* eslint-disable quote-props */ -export = { - 'defaults'(test: Test) { +describe('SQSEventSource', () => { + test('defaults', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -18,7 +17,7 @@ export = { fn.addEventSource(new sources.SqsEventSource(q)); // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { 'PolicyDocument': { 'Statement': [ { @@ -40,9 +39,9 @@ export = { ], 'Version': '2012-10-17', }, - })); + }); - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'Q63C6E3AB', @@ -52,12 +51,12 @@ export = { 'FunctionName': { 'Ref': 'Fn9270CBC0', }, - })); + }); - test.done(); - }, - 'specific batch size'(test: Test) { + }); + + test('specific batch size', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -69,7 +68,7 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'EventSourceArn': { 'Fn::GetAtt': [ 'Q63C6E3AB', @@ -80,12 +79,12 @@ export = { 'Ref': 'Fn9270CBC0', }, 'BatchSize': 5, - })); + }); - test.done(); - }, - 'unresolved batch size'(test: Test) { + }); + + test('unresolved batch size', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -102,42 +101,42 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'BatchSize': 500, - })); + }); + - test.done(); - }, + }); - 'fails if batch size is < 1'(test: Test) { + test('fails if batch size is < 1', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const q = new sqs.Queue(stack, 'Q'); // WHEN/THEN - test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + expect(() => fn.addEventSource(new sources.SqsEventSource(q, { batchSize: 0, - })), /Maximum batch size must be between 1 and 10 inclusive \(given 0\) when batching window is not specified\./); + }))).toThrow(/Maximum batch size must be between 1 and 10 inclusive \(given 0\) when batching window is not specified\./); - test.done(); - }, - 'fails if batch size is > 10'(test: Test) { + }); + + test('fails if batch size is > 10', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const q = new sqs.Queue(stack, 'Q'); // WHEN/THEN - test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + expect(() => fn.addEventSource(new sources.SqsEventSource(q, { batchSize: 11, - })), /Maximum batch size must be between 1 and 10 inclusive \(given 11\) when batching window is not specified\./); + }))).toThrow(/Maximum batch size must be between 1 and 10 inclusive \(given 11\) when batching window is not specified\./); + - test.done(); - }, + }); - 'batch size is > 10 and batch window is defined'(test: Test) { + test('batch size is > 10 and batch window is defined', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -150,30 +149,30 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'BatchSize': 1000, 'MaximumBatchingWindowInSeconds': 300, - })); + }); + - test.done(); - }, + }); - 'fails if batch size is > 10000 and batch window is defined'(test: Test) { + test('fails if batch size is > 10000 and batch window is defined', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const q = new sqs.Queue(stack, 'Q'); // WHEN/THEN - test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + expect(() => fn.addEventSource(new sources.SqsEventSource(q, { batchSize: 11000, maxBatchingWindow: cdk.Duration.minutes(5), - })), /Maximum batch size must be between 1 and 10000 inclusive/i); + }))).toThrow(/Maximum batch size must be between 1 and 10000 inclusive/i); - test.done(); - }, - 'specific batch window'(test: Test) { + }); + + test('specific batch window', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -185,14 +184,14 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'MaximumBatchingWindowInSeconds': 300, - })); + }); + - test.done(); - }, + }); - 'fails if batch window defined for FIFO queue'(test: Test) { + test('fails if batch window defined for FIFO queue', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -201,28 +200,28 @@ export = { }); // WHEN/THEN - test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + expect(() => fn.addEventSource(new sources.SqsEventSource(q, { maxBatchingWindow: cdk.Duration.minutes(5), - })), /Batching window is not supported for FIFO queues/); + }))).toThrow(/Batching window is not supported for FIFO queues/); + - test.done(); - }, + }); - 'fails if batch window is > 5'(test: Test) { + test('fails if batch window is > 5', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); const q = new sqs.Queue(stack, 'Q'); // WHEN/THEN - test.throws(() => fn.addEventSource(new sources.SqsEventSource(q, { + expect(() => fn.addEventSource(new sources.SqsEventSource(q, { maxBatchingWindow: cdk.Duration.minutes(7), - })), /Maximum batching window must be 300 seconds or less/i); + }))).toThrow(/Maximum batching window must be 300 seconds or less/i); - test.done(); - }, - 'contains eventSourceMappingId after lambda binding'(test: Test) { + }); + + test('contains eventSourceMappingId after lambda binding', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -233,22 +232,22 @@ export = { fn.addEventSource(eventSource); // THEN - test.ok(eventSource.eventSourceMappingId); - test.done(); - }, + expect(eventSource.eventSourceMappingId).toBeDefined(); + + }); - 'eventSourceMappingId throws error before binding to lambda'(test: Test) { + test('eventSourceMappingId throws error before binding to lambda', () => { // GIVEN const stack = new cdk.Stack(); const q = new sqs.Queue(stack, 'Q'); const eventSource = new sources.SqsEventSource(q); // WHEN/THEN - test.throws(() => eventSource.eventSourceMappingId, /SqsEventSource is not yet bound to an event source mapping/); - test.done(); - }, + expect(() => eventSource.eventSourceMappingId).toThrow(/SqsEventSource is not yet bound to an event source mapping/); + + }); - 'event source disabled'(test: Test) { + test('event source disabled', () => { // GIVEN const stack = new cdk.Stack(); const fn = new TestFunction(stack, 'Fn'); @@ -260,10 +259,10 @@ export = { })); // THEN - expect(stack).to(haveResource('AWS::Lambda::EventSourceMapping', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', { 'Enabled': false, - })); + }); + - test.done(); - }, -}; + }); +}); diff --git a/packages/@aws-cdk/aws-sns/.gitignore b/packages/@aws-cdk/aws-sns/.gitignore index 86fc837df8fca..a82230b5888d0 100644 --- a/packages/@aws-cdk/aws-sns/.gitignore +++ b/packages/@aws-cdk/aws-sns/.gitignore @@ -15,4 +15,5 @@ nyc.config.js *.snk !.eslintrc.js -junit.xml \ No newline at end of file +junit.xml +!jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sns/.npmignore b/packages/@aws-cdk/aws-sns/.npmignore index 9a032ae80868c..e8acf10a468a1 100644 --- a/packages/@aws-cdk/aws-sns/.npmignore +++ b/packages/@aws-cdk/aws-sns/.npmignore @@ -24,4 +24,5 @@ tsconfig.json **/cdk.out junit.xml test/ -!*.lit.ts \ No newline at end of file +!*.lit.ts +jest.config.js \ No newline at end of file diff --git a/packages/@aws-cdk/aws-sns/jest.config.js b/packages/@aws-cdk/aws-sns/jest.config.js new file mode 100644 index 0000000000000..1f611abd50de4 --- /dev/null +++ b/packages/@aws-cdk/aws-sns/jest.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('../../../tools/cdk-build-tools/config/jest.config'); +module.exports = { + ...baseConfig, + coverageThreshold: { + global: { + branches: 70, + statements: 80, + }, + }, +}; diff --git a/packages/@aws-cdk/aws-sns/package.json b/packages/@aws-cdk/aws-sns/package.json index 9ec8371fc3a6a..c7734d512cdfd 100644 --- a/packages/@aws-cdk/aws-sns/package.json +++ b/packages/@aws-cdk/aws-sns/package.json @@ -58,6 +58,7 @@ }, "cdk-build": { "cloudformation": "AWS::SNS", + "jest": true, "env": { "AWSLINT_BASE_CONSTRUCT": true } @@ -76,13 +77,13 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/aws-s3": "0.0.0", - "@types/nodeunit": "^0.0.32", + "@aws-cdk/assertions": "0.0.0", + "@types/jest": "^26.0.24", "cdk-build-tools": "0.0.0", "cdk-integ-tools": "0.0.0", "cfn2ts": "0.0.0", - "nodeunit": "^0.11.3", - "pkglint": "0.0.0", - "@aws-cdk/assert-internal": "0.0.0" + "jest": "^26.6.3", + "pkglint": "0.0.0" }, "dependencies": { "@aws-cdk/aws-codestarnotifications": "0.0.0", diff --git a/packages/@aws-cdk/aws-sns/test/sns.test.ts b/packages/@aws-cdk/aws-sns/test/sns.test.ts new file mode 100644 index 0000000000000..b07fdce78dab0 --- /dev/null +++ b/packages/@aws-cdk/aws-sns/test/sns.test.ts @@ -0,0 +1,483 @@ +import { TemplateAssertions } from '@aws-cdk/assertions'; +import * as notifications from '@aws-cdk/aws-codestarnotifications'; +import * as iam from '@aws-cdk/aws-iam'; +import * as kms from '@aws-cdk/aws-kms'; +import * as cdk from '@aws-cdk/core'; +import * as sns from '../lib'; + +/* eslint-disable quote-props */ + +describe('Topic', () => { + describe('topic tests', () => { + test('all defaults', () => { + const stack = new cdk.Stack(); + new sns.Topic(stack, 'MyTopic'); + + TemplateAssertions.fromStack(stack).resourceCountIs('AWS::SNS::Topic', 1); + + }); + + test('specify topicName', () => { + const stack = new cdk.Stack(); + + new sns.Topic(stack, 'MyTopic', { + topicName: 'topicName', + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'TopicName': 'topicName', + }); + + + }); + + test('specify displayName', () => { + const stack = new cdk.Stack(); + + new sns.Topic(stack, 'MyTopic', { + displayName: 'displayName', + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'DisplayName': 'displayName', + }); + + + }); + + test('specify kmsMasterKey', () => { + const stack = new cdk.Stack(); + const key = new kms.Key(stack, 'CustomKey'); + + new sns.Topic(stack, 'MyTopic', { + masterKey: key, + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'KmsMasterKeyId': { 'Fn::GetAtt': ['CustomKey1E6D0D07', 'Arn'] }, + }); + + + }); + + test('specify displayName and topicName', () => { + const stack = new cdk.Stack(); + + new sns.Topic(stack, 'MyTopic', { + topicName: 'topicName', + displayName: 'displayName', + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'DisplayName': 'displayName', + 'TopicName': 'topicName', + }); + + + }); + + // NOTE: This test case should be invalid when CloudFormation problem reported in CDK issue 12386 is resolved + // see https://github.com/aws/aws-cdk/issues/12386 + test('throw with missing topicName on fifo topic', () => { + const stack = new cdk.Stack(); + + expect(() => new sns.Topic(stack, 'MyTopic', { + fifo: true, + })).toThrow(/FIFO SNS topics must be given a topic name./); + + + }); + + test('specify fifo without .fifo suffix in topicName', () => { + const stack = new cdk.Stack(); + + new sns.Topic(stack, 'MyTopic', { + fifo: true, + topicName: 'topicName', + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'FifoTopic': true, + 'TopicName': 'topicName.fifo', + }); + + + }); + + test('specify fifo with .fifo suffix in topicName', () => { + const stack = new cdk.Stack(); + + new sns.Topic(stack, 'MyTopic', { + fifo: true, + topicName: 'topicName.fifo', + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'FifoTopic': true, + 'TopicName': 'topicName.fifo', + }); + + + }); + + test('specify fifo without contentBasedDeduplication', () => { + const stack = new cdk.Stack(); + + new sns.Topic(stack, 'MyTopic', { + fifo: true, + topicName: 'topicName', + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'FifoTopic': true, + 'TopicName': 'topicName.fifo', + }); + + + }); + + test('specify fifo with contentBasedDeduplication', () => { + const stack = new cdk.Stack(); + + new sns.Topic(stack, 'MyTopic', { + contentBasedDeduplication: true, + fifo: true, + topicName: 'topicName', + }); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', { + 'ContentBasedDeduplication': true, + 'FifoTopic': true, + 'TopicName': 'topicName.fifo', + }); + + + }); + + test('throw with contentBasedDeduplication on non-fifo topic', () => { + const stack = new cdk.Stack(); + + expect(() => new sns.Topic(stack, 'MyTopic', { + contentBasedDeduplication: true, + })).toThrow(/Content based deduplication can only be enabled for FIFO SNS topics./); + + + }); + }); + + test('can add a policy to the topic', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + topic.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sns:*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { + PolicyDocument: { + Version: '2012-10-17', + Statement: [{ + 'Sid': '0', + 'Action': 'sns:*', + 'Effect': 'Allow', + 'Principal': { 'AWS': 'arn' }, + 'Resource': '*', + }], + }, + }); + + + }); + + test('give publishing permissions', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'Topic'); + const user = new iam.User(stack, 'User'); + + // WHEN + topic.grantPublish(user); + + // THEN + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', { + 'PolicyDocument': { + Version: '2012-10-17', + 'Statement': [ + { + 'Action': 'sns:Publish', + 'Effect': 'Allow', + 'Resource': stack.resolve(topic.topicArn), + }, + ], + }, + }); + + + }); + + test('TopicPolicy passed document', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'MyTopic'); + const ps = new iam.PolicyStatement({ + actions: ['service:statement0'], + principals: [new iam.ArnPrincipal('arn')], + }); + + // WHEN + new sns.TopicPolicy(stack, 'topicpolicy', { topics: [topic], policyDocument: new iam.PolicyDocument({ assignSids: true, statements: [ps] }) }); + + // THEN + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'service:statement0', + 'Effect': 'Allow', + 'Principal': { 'AWS': 'arn' }, + 'Sid': '0', + }, + ], + 'Version': '2012-10-17', + }, + 'Topics': [ + { + 'Ref': 'MyTopic86869434', + }, + ], + }); + + + }); + + test('Add statements to policy', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'MyTopic'); + + // WHEN + const topicPolicy = new sns.TopicPolicy(stack, 'TopicPolicy', { + topics: [topic], + }); + topicPolicy.document.addStatements(new iam.PolicyStatement({ + actions: ['service:statement0'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'service:statement0', + 'Effect': 'Allow', + 'Principal': { 'AWS': 'arn' }, + 'Sid': '0', + }, + ], + 'Version': '2012-10-17', + }, + 'Topics': [ + { + 'Ref': 'MyTopic86869434', + }, + ], + }); + + }); + + test('topic resource policy includes unique SIDs', () => { + const stack = new cdk.Stack(); + + const topic = new sns.Topic(stack, 'MyTopic'); + + topic.addToResourcePolicy(new iam.PolicyStatement({ + actions: ['service:statement0'], + principals: [new iam.ArnPrincipal('arn')], + })); + topic.addToResourcePolicy(new iam.PolicyStatement({ + actions: ['service:statement1'], + principals: [new iam.ArnPrincipal('arn')], + })); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { + 'PolicyDocument': { + 'Statement': [ + { + 'Action': 'service:statement0', + 'Effect': 'Allow', + 'Principal': { 'AWS': 'arn' }, + 'Sid': '0', + }, + { + 'Action': 'service:statement1', + 'Effect': 'Allow', + 'Principal': { 'AWS': 'arn' }, + 'Sid': '1', + }, + ], + 'Version': '2012-10-17', + }, + 'Topics': [ + { + 'Ref': 'MyTopic86869434', + }, + ], + }); + + + }); + + test('fromTopicArn', () => { + // GIVEN + const stack2 = new cdk.Stack(); + + // WHEN + const imported = sns.Topic.fromTopicArn(stack2, 'Imported', 'arn:aws:sns:*:123456789012:my_corporate_topic'); + + // THEN + expect(imported.topicName).toEqual('my_corporate_topic'); + expect(imported.topicArn).toEqual('arn:aws:sns:*:123456789012:my_corporate_topic'); + + }); + + test('test metrics', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'Topic'); + + // THEN + expect(stack.resolve(topic.metricNumberOfMessagesPublished())).toEqual({ + dimensions: { TopicName: { 'Fn::GetAtt': ['TopicBFC7AF6E', 'TopicName'] } }, + namespace: 'AWS/SNS', + metricName: 'NumberOfMessagesPublished', + period: cdk.Duration.minutes(5), + statistic: 'Sum', + }); + + expect(stack.resolve(topic.metricPublishSize())).toEqual({ + dimensions: { TopicName: { 'Fn::GetAtt': ['TopicBFC7AF6E', 'TopicName'] } }, + namespace: 'AWS/SNS', + metricName: 'PublishSize', + period: cdk.Duration.minutes(5), + statistic: 'Average', + }); + + + }); + + test('subscription is created under the topic scope by default', () => { + // GIVEN + const stack = new cdk.Stack(); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + topic.addSubscription({ + bind: () => ({ + protocol: sns.SubscriptionProtocol.HTTP, + endpoint: 'http://foo/bar', + subscriberId: 'my-subscription', + }), + }); + + // THEN + TemplateAssertions.fromStack(stack).resourceCountIs('AWS::SNS::Subscription', 1); + + }); + + test('if "scope" is defined, subscription will be created under that scope', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'A'); + const stack2 = new cdk.Stack(app, 'B'); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + topic.addSubscription({ + bind: () => ({ + protocol: sns.SubscriptionProtocol.HTTP, + endpoint: 'http://foo/bar', + subscriberScope: stack2, + subscriberId: 'subscriberId', + }), + }); + + // THEN + TemplateAssertions.fromStack(stack).resourceCountIs('AWS::SNS::Subscription', 0); + TemplateAssertions.fromStack(stack2).resourceCountIs('AWS::SNS::Subscription', 1); + + }); + + test('fails if topic policy has no actions', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + topic.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + principals: [new iam.ArnPrincipal('arn')], + })); + + // THEN + expect(() => app.synth()).toThrow(/A PolicyStatement must specify at least one \'action\' or \'notAction\'/); + + }); + + test('fails if topic policy has no IAM principals', () => { + // GIVEN + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const topic = new sns.Topic(stack, 'Topic'); + + // WHEN + topic.addToResourcePolicy(new iam.PolicyStatement({ + resources: ['*'], + actions: ['sns:*'], + })); + + // THEN + expect(() => app.synth()).toThrow(/A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); + + }); + + test('topic policy should be set if topic as a notifications rule target', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'my-stack'); + const topic = new sns.Topic(stack, 'Topic'); + const rule = new notifications.NotificationRule(stack, 'MyNotificationRule', { + source: { + bindAsNotificationRuleSource: () => ({ + sourceArn: 'ARN', + }), + }, + events: ['codebuild-project-build-state-succeeded'], + }); + + rule.addTarget(topic); + + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::TopicPolicy', { + PolicyDocument: { + Version: '2012-10-17', + Statement: [{ + 'Sid': '0', + 'Action': 'sns:Publish', + 'Effect': 'Allow', + 'Principal': { 'Service': 'codestar-notifications.amazonaws.com' }, + 'Resource': { 'Ref': 'TopicBFC7AF6E' }, + }], + }, + Topics: [{ + Ref: 'TopicBFC7AF6E', + }], + }); + + + }); +}); diff --git a/packages/@aws-cdk/aws-sns/test/test.subscription.ts b/packages/@aws-cdk/aws-sns/test/subscription.test.ts similarity index 76% rename from packages/@aws-cdk/aws-sns/test/test.subscription.ts rename to packages/@aws-cdk/aws-sns/test/subscription.test.ts index c8ade98bc81d5..7717b7f12c7d4 100644 --- a/packages/@aws-cdk/aws-sns/test/test.subscription.ts +++ b/packages/@aws-cdk/aws-sns/test/subscription.test.ts @@ -1,11 +1,10 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; +import { TemplateAssertions } from '@aws-cdk/assertions'; import { Queue } from '@aws-cdk/aws-sqs'; import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; import * as sns from '../lib'; -export = { - 'create a subscription'(test: Test) { +describe('Subscription', () => { + test('create a subscription', () => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); @@ -18,17 +17,17 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::SNS::Subscription', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Endpoint: 'endpoint', Protocol: 'lambda', TopicArn: { Ref: 'TopicBFC7AF6E', }, - })); - test.done(); - }, + }); + + }); - 'create a subscription with DLQ when client provides DLQ'(test: Test) { + test('create a subscription with DLQ when client provides DLQ', () => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); @@ -46,7 +45,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::SNS::Subscription', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { Endpoint: 'endpoint', Protocol: 'lambda', TopicArn: { @@ -60,12 +59,12 @@ export = { ], }, }, - })); - expect(stack).to(haveResource('AWS::SQS::Queue', { + }); + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SQS::Queue', { QueueName: 'MySubscription_DLQ', MessageRetentionPeriod: 1209600, - })); - expect(stack).to(haveResource('AWS::SQS::QueuePolicy', { + }); + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SQS::QueuePolicy', { PolicyDocument: { Statement: [ { @@ -96,11 +95,11 @@ export = { Ref: 'DeadLetterQueue9F481546', }, ], - })); - test.done(); - }, + }); + + }); - 'with filter policy'(test: Test) { + test('with filter policy', () => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); @@ -129,7 +128,7 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::SNS::Subscription', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { FilterPolicy: { color: [ 'red', @@ -149,11 +148,11 @@ export = { { numeric: ['>', 2000, '<', 3000] }, ], }, - })); - test.done(); - }, + }); - 'with existsFilter'(test: Test) { + }); + + test('with existsFilter', () => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); @@ -169,37 +168,37 @@ export = { }); // THEN - expect(stack).to(haveResource('AWS::SNS::Subscription', { + TemplateAssertions.fromStack(stack).hasResourceProperties('AWS::SNS::Subscription', { FilterPolicy: { size: [{ exists: true }], }, - })); - test.done(); - }, + }); + + }); - 'throws with raw delivery for protocol other than http, https or sqs'(test: Test) { + test('throws with raw delivery for protocol other than http, https or sqs', () => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); // THEN - test.throws(() => new sns.Subscription(stack, 'Subscription', { + expect(() => new sns.Subscription(stack, 'Subscription', { endpoint: 'endpoint', protocol: sns.SubscriptionProtocol.LAMBDA, topic, rawMessageDelivery: true, - }), /Raw message delivery/); - test.done(); - }, + })).toThrow(/Raw message delivery/); - 'throws with more than 5 attributes in a filter policy'(test: Test) { + }); + + test('throws with more than 5 attributes in a filter policy', () => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); const cond = { conditions: [] }; // THEN - test.throws(() => new sns.Subscription(stack, 'Subscription', { + expect(() => new sns.Subscription(stack, 'Subscription', { endpoint: 'endpoint', protocol: sns.SubscriptionProtocol.LAMBDA, topic, @@ -211,17 +210,17 @@ export = { e: cond, f: cond, }, - }), /5 attribute names/); - test.done(); - }, + })).toThrow(/5 attribute names/); + + }); - 'throws with more than 100 conditions in a filter policy'(test: Test) { + test('throws with more than 100 conditions in a filter policy', () => { // GIVEN const stack = new cdk.Stack(); const topic = new sns.Topic(stack, 'Topic'); // THEN - test.throws(() => new sns.Subscription(stack, 'Subscription', { + expect(() => new sns.Subscription(stack, 'Subscription', { endpoint: 'endpoint', protocol: sns.SubscriptionProtocol.LAMBDA, topic, @@ -230,7 +229,7 @@ export = { b: { conditions: [...Array.from(Array(10).keys())] }, c: { conditions: [...Array.from(Array(6).keys())] }, }, - }), /\(120\) must not exceed 100/); - test.done(); - }, -}; + })).toThrow(/\(120\) must not exceed 100/); + + }); +}); diff --git a/packages/@aws-cdk/aws-sns/test/test.sns.ts b/packages/@aws-cdk/aws-sns/test/test.sns.ts deleted file mode 100644 index 09cf051922e5e..0000000000000 --- a/packages/@aws-cdk/aws-sns/test/test.sns.ts +++ /dev/null @@ -1,570 +0,0 @@ -import { expect, haveResource } from '@aws-cdk/assert-internal'; -import * as notifications from '@aws-cdk/aws-codestarnotifications'; -import * as iam from '@aws-cdk/aws-iam'; -import * as kms from '@aws-cdk/aws-kms'; -import * as cdk from '@aws-cdk/core'; -import { Test } from 'nodeunit'; -import * as sns from '../lib'; - -/* eslint-disable quote-props */ - -export = { - 'topic tests': { - 'all defaults'(test: Test) { - const stack = new cdk.Stack(); - new sns.Topic(stack, 'MyTopic'); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - }, - }, - }); - - test.done(); - }, - - 'specify topicName'(test: Test) { - const stack = new cdk.Stack(); - - new sns.Topic(stack, 'MyTopic', { - topicName: 'topicName', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - 'Properties': { - 'TopicName': 'topicName', - }, - }, - }, - }); - - test.done(); - }, - - 'specify displayName'(test: Test) { - const stack = new cdk.Stack(); - - new sns.Topic(stack, 'MyTopic', { - displayName: 'displayName', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - 'Properties': { - 'DisplayName': 'displayName', - }, - }, - }, - }); - - test.done(); - }, - - 'specify kmsMasterKey'(test: Test) { - const stack = new cdk.Stack(); - const key = new kms.Key(stack, 'CustomKey'); - - new sns.Topic(stack, 'MyTopic', { - masterKey: key, - }); - - expect(stack).to(haveResource('AWS::SNS::Topic', { - 'KmsMasterKeyId': { 'Fn::GetAtt': ['CustomKey1E6D0D07', 'Arn'] }, - })); - - test.done(); - }, - - 'specify displayName and topicName'(test: Test) { - const stack = new cdk.Stack(); - - new sns.Topic(stack, 'MyTopic', { - topicName: 'topicName', - displayName: 'displayName', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - 'Properties': { - 'DisplayName': 'displayName', - 'TopicName': 'topicName', - }, - }, - }, - }); - - test.done(); - }, - - // NOTE: This test case should be invalid when CloudFormation problem reported in CDK issue 12386 is resolved - // see https://github.com/aws/aws-cdk/issues/12386 - 'throw with missing topicName on fifo topic'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => new sns.Topic(stack, 'MyTopic', { - fifo: true, - }), /FIFO SNS topics must be given a topic name./); - - test.done(); - }, - - 'specify fifo without .fifo suffix in topicName'(test: Test) { - const stack = new cdk.Stack(); - - new sns.Topic(stack, 'MyTopic', { - fifo: true, - topicName: 'topicName', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - 'Properties': { - 'FifoTopic': true, - 'TopicName': 'topicName.fifo', - }, - }, - }, - }); - - test.done(); - }, - - 'specify fifo with .fifo suffix in topicName'(test: Test) { - const stack = new cdk.Stack(); - - new sns.Topic(stack, 'MyTopic', { - fifo: true, - topicName: 'topicName.fifo', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - 'Properties': { - 'FifoTopic': true, - 'TopicName': 'topicName.fifo', - }, - }, - }, - }); - - test.done(); - }, - - 'specify fifo without contentBasedDeduplication'(test: Test) { - const stack = new cdk.Stack(); - - new sns.Topic(stack, 'MyTopic', { - fifo: true, - topicName: 'topicName', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - 'Properties': { - 'FifoTopic': true, - 'TopicName': 'topicName.fifo', - }, - }, - }, - }); - - test.done(); - }, - - 'specify fifo with contentBasedDeduplication'(test: Test) { - const stack = new cdk.Stack(); - - new sns.Topic(stack, 'MyTopic', { - contentBasedDeduplication: true, - fifo: true, - topicName: 'topicName', - }); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - 'Properties': { - 'ContentBasedDeduplication': true, - 'FifoTopic': true, - 'TopicName': 'topicName.fifo', - }, - }, - }, - }); - - test.done(); - }, - - 'throw with contentBasedDeduplication on non-fifo topic'(test: Test) { - const stack = new cdk.Stack(); - - test.throws(() => new sns.Topic(stack, 'MyTopic', { - contentBasedDeduplication: true, - }), /Content based deduplication can only be enabled for FIFO SNS topics./); - - test.done(); - }, - }, - - 'can add a policy to the topic'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const topic = new sns.Topic(stack, 'Topic'); - - // WHEN - topic.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - actions: ['sns:*'], - principals: [new iam.ArnPrincipal('arn')], - })); - - // THEN - expect(stack).to(haveResource('AWS::SNS::TopicPolicy', { - PolicyDocument: { - Version: '2012-10-17', - Statement: [{ - 'Sid': '0', - 'Action': 'sns:*', - 'Effect': 'Allow', - 'Principal': { 'AWS': 'arn' }, - 'Resource': '*', - }], - }, - })); - - test.done(); - }, - - 'give publishing permissions'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const topic = new sns.Topic(stack, 'Topic'); - const user = new iam.User(stack, 'User'); - - // WHEN - topic.grantPublish(user); - - // THEN - expect(stack).to(haveResource('AWS::IAM::Policy', { - 'PolicyDocument': { - Version: '2012-10-17', - 'Statement': [ - { - 'Action': 'sns:Publish', - 'Effect': 'Allow', - 'Resource': stack.resolve(topic.topicArn), - }, - ], - }, - })); - - test.done(); - }, - - 'TopicPolicy passed document'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const topic = new sns.Topic(stack, 'MyTopic'); - const ps = new iam.PolicyStatement({ - actions: ['service:statement0'], - principals: [new iam.ArnPrincipal('arn')], - }); - - // WHEN - new sns.TopicPolicy(stack, 'topicpolicy', { topics: [topic], policyDocument: new iam.PolicyDocument({ assignSids: true, statements: [ps] }) }); - - // THEN - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - }, - 'topicpolicyF8CF12FD': { - 'Type': 'AWS::SNS::TopicPolicy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'service:statement0', - 'Effect': 'Allow', - 'Principal': { 'AWS': 'arn' }, - 'Sid': '0', - }, - ], - 'Version': '2012-10-17', - }, - 'Topics': [ - { - 'Ref': 'MyTopic86869434', - }, - ], - }, - }, - }, - }); - - test.done(); - }, - - 'Add statements to policy'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const topic = new sns.Topic(stack, 'MyTopic'); - - // WHEN - const topicPolicy = new sns.TopicPolicy(stack, 'TopicPolicy', { - topics: [topic], - }); - topicPolicy.document.addStatements(new iam.PolicyStatement({ - actions: ['service:statement0'], - principals: [new iam.ArnPrincipal('arn')], - })); - - // THEN - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - }, - 'TopicPolicyA24B096F': { - 'Type': 'AWS::SNS::TopicPolicy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'service:statement0', - 'Effect': 'Allow', - 'Principal': { 'AWS': 'arn' }, - 'Sid': '0', - }, - ], - 'Version': '2012-10-17', - }, - 'Topics': [ - { - 'Ref': 'MyTopic86869434', - }, - ], - }, - }, - }, - }); - test.done(); - }, - - 'topic resource policy includes unique SIDs'(test: Test) { - const stack = new cdk.Stack(); - - const topic = new sns.Topic(stack, 'MyTopic'); - - topic.addToResourcePolicy(new iam.PolicyStatement({ - actions: ['service:statement0'], - principals: [new iam.ArnPrincipal('arn')], - })); - topic.addToResourcePolicy(new iam.PolicyStatement({ - actions: ['service:statement1'], - principals: [new iam.ArnPrincipal('arn')], - })); - - expect(stack).toMatch({ - 'Resources': { - 'MyTopic86869434': { - 'Type': 'AWS::SNS::Topic', - }, - 'MyTopicPolicy12A5EC17': { - 'Type': 'AWS::SNS::TopicPolicy', - 'Properties': { - 'PolicyDocument': { - 'Statement': [ - { - 'Action': 'service:statement0', - 'Effect': 'Allow', - 'Principal': { 'AWS': 'arn' }, - 'Sid': '0', - }, - { - 'Action': 'service:statement1', - 'Effect': 'Allow', - 'Principal': { 'AWS': 'arn' }, - 'Sid': '1', - }, - ], - 'Version': '2012-10-17', - }, - 'Topics': [ - { - 'Ref': 'MyTopic86869434', - }, - ], - }, - }, - }, - }); - - test.done(); - }, - - 'fromTopicArn'(test: Test) { - // GIVEN - const stack2 = new cdk.Stack(); - - // WHEN - const imported = sns.Topic.fromTopicArn(stack2, 'Imported', 'arn:aws:sns:*:123456789012:my_corporate_topic'); - - // THEN - test.deepEqual(imported.topicName, 'my_corporate_topic'); - test.deepEqual(imported.topicArn, 'arn:aws:sns:*:123456789012:my_corporate_topic'); - test.done(); - }, - - 'test metrics'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const topic = new sns.Topic(stack, 'Topic'); - - // THEN - test.deepEqual(stack.resolve(topic.metricNumberOfMessagesPublished()), { - dimensions: { TopicName: { 'Fn::GetAtt': ['TopicBFC7AF6E', 'TopicName'] } }, - namespace: 'AWS/SNS', - metricName: 'NumberOfMessagesPublished', - period: cdk.Duration.minutes(5), - statistic: 'Sum', - }); - - test.deepEqual(stack.resolve(topic.metricPublishSize()), { - dimensions: { TopicName: { 'Fn::GetAtt': ['TopicBFC7AF6E', 'TopicName'] } }, - namespace: 'AWS/SNS', - metricName: 'PublishSize', - period: cdk.Duration.minutes(5), - statistic: 'Average', - }); - - test.done(); - }, - - 'subscription is created under the topic scope by default'(test: Test) { - // GIVEN - const stack = new cdk.Stack(); - const topic = new sns.Topic(stack, 'Topic'); - - // WHEN - topic.addSubscription({ - bind: () => ({ - protocol: sns.SubscriptionProtocol.HTTP, - endpoint: 'http://foo/bar', - subscriberId: 'my-subscription', - }), - }); - - // THEN - expect(stack).to(haveResource('AWS::SNS::Subscription')); - test.done(); - }, - - 'if "scope" is defined, subscription will be created under that scope'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'A'); - const stack2 = new cdk.Stack(app, 'B'); - const topic = new sns.Topic(stack, 'Topic'); - - // WHEN - topic.addSubscription({ - bind: () => ({ - protocol: sns.SubscriptionProtocol.HTTP, - endpoint: 'http://foo/bar', - subscriberScope: stack2, - subscriberId: 'subscriberId', - }), - }); - - // THEN - expect(stack).notTo(haveResource('AWS::SNS::Subscription')); - expect(stack2).to(haveResource('AWS::SNS::Subscription')); - test.done(); - }, - - 'fails if topic policy has no actions'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'my-stack'); - const topic = new sns.Topic(stack, 'Topic'); - - // WHEN - topic.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - principals: [new iam.ArnPrincipal('arn')], - })); - - // THEN - test.throws(() => app.synth(), /A PolicyStatement must specify at least one \'action\' or \'notAction\'/); - test.done(); - }, - - 'fails if topic policy has no IAM principals'(test: Test) { - // GIVEN - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'my-stack'); - const topic = new sns.Topic(stack, 'Topic'); - - // WHEN - topic.addToResourcePolicy(new iam.PolicyStatement({ - resources: ['*'], - actions: ['sns:*'], - })); - - // THEN - test.throws(() => app.synth(), /A PolicyStatement used in a resource-based policy must specify at least one IAM principal/); - test.done(); - }, - - 'topic policy should be set if topic as a notifications rule target'(test: Test) { - const app = new cdk.App(); - const stack = new cdk.Stack(app, 'my-stack'); - const topic = new sns.Topic(stack, 'Topic'); - const rule = new notifications.NotificationRule(stack, 'MyNotificationRule', { - source: { - bindAsNotificationRuleSource: () => ({ - sourceArn: 'ARN', - }), - }, - events: ['codebuild-project-build-state-succeeded'], - }); - - rule.addTarget(topic); - - expect(stack).to(haveResource('AWS::SNS::TopicPolicy', { - PolicyDocument: { - Version: '2012-10-17', - Statement: [{ - 'Sid': '0', - 'Action': 'sns:Publish', - 'Effect': 'Allow', - 'Principal': { 'Service': 'codestar-notifications.amazonaws.com' }, - 'Resource': { 'Ref': 'TopicBFC7AF6E' }, - }], - }, - Topics: [{ - Ref: 'TopicBFC7AF6E', - }], - })); - - test.done(); - }, -};