From 71cb421d3b38bcc3f1fbfad3028b25df5fd2cb77 Mon Sep 17 00:00:00 2001 From: Romain Marcadier-Muller Date: Mon, 1 Jul 2019 15:31:54 +0200 Subject: [PATCH] fix(code): make CfnResource#_toCloudFormation null-safe (#3121) The `CfnResource#_toCloudFormation` method creates a `PostResolveToken` with a post-processor that was not ready to handle the absence of `Properties` on the resolved value. It is however possible that `Properties` are missing when an object is created with the default configuration (e.g: by `new sqs.CfnQueue(this, 'Queue');`). This change makes the post-processor function correctly handle `undefined` in this case. Related #3093 --- packages/@aws-cdk/core/lib/cfn-resource.ts | 3 +- .../@aws-cdk/core/test/test.cfn-resource.ts | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 packages/@aws-cdk/core/test/test.cfn-resource.ts diff --git a/packages/@aws-cdk/core/lib/cfn-resource.ts b/packages/@aws-cdk/core/lib/cfn-resource.ts index edb7d3f87a8ea..31dc062f5ce43 100644 --- a/packages/@aws-cdk/core/lib/cfn-resource.ts +++ b/packages/@aws-cdk/core/lib/cfn-resource.ts @@ -230,7 +230,8 @@ export class CfnResource extends CfnRefElement { Metadata: ignoreEmpty(this.cfnOptions.metadata), Condition: this.cfnOptions.condition && this.cfnOptions.condition.logicalId }, props => { - props.Properties = this.renderProperties(props.Properties); + const renderedProps = this.renderProperties(props.Properties || {}); + props.Properties = renderedProps && (Object.values(renderedProps).find(v => !!v) ? renderedProps : undefined); return deepMerge(props, this.rawOverrides); }) } diff --git a/packages/@aws-cdk/core/test/test.cfn-resource.ts b/packages/@aws-cdk/core/test/test.cfn-resource.ts new file mode 100644 index 0000000000000..db83634ecccd3 --- /dev/null +++ b/packages/@aws-cdk/core/test/test.cfn-resource.ts @@ -0,0 +1,29 @@ +import nodeunit = require('nodeunit'); +import core = require('../lib'); + +export = nodeunit.testCase({ + '._toCloudFormation': { + 'does not call renderProperties with an undefined value'(test: nodeunit.Test) { + const app = new core.App(); + const stack = new core.Stack(app, 'TestStack'); + const resource = new core.CfnResource(stack, 'DefaultResource', { type: 'Test::Resource::Fake' }); + + let called = false; + (resource as any).renderProperties = (val: any) => { + called = true; + test.notEqual(val, null); + }; + + test.deepEqual(app.synth().getStack(stack.stackName).template, { + Resources: { + DefaultResource: { + Type: 'Test::Resource::Fake' + } + } + }); + test.ok(called, `renderProperties must be called called`); + + test.done(); + } + } +});