diff --git a/packages/@aws-cdk/assertions/lib/private/outputs.ts b/packages/@aws-cdk/assertions/lib/private/outputs.ts index 39509698d0e43..a24d44881d300 100644 --- a/packages/@aws-cdk/assertions/lib/private/outputs.ts +++ b/packages/@aws-cdk/assertions/lib/private/outputs.ts @@ -20,7 +20,7 @@ export function hasOutput(template: Template, logicalId: string, props: any): st } if (result.closestResult === undefined) { - return `No outputs named ${logicalId} found in the template.`; + return `No outputs named ${logicalId} found in the template (found: ${Object.keys(section).join(', ')})`; } return [ diff --git a/packages/@aws-cdk/aws-docdb/test/endpoint.test.ts b/packages/@aws-cdk/aws-docdb/test/endpoint.test.ts index 72a1b699779ce..fa58338182e2c 100644 --- a/packages/@aws-cdk/aws-docdb/test/endpoint.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/endpoint.test.ts @@ -1,8 +1,7 @@ import { Token } from '@aws-cdk/core'; import { Endpoint } from '../lib'; -// A numeric CDK token (see: https://docs.aws.amazon.com/cdk/latest/guide/tokens.html#tokens_number) -const CDK_NUMERIC_TOKEN = -1.8881545897087626e+289; +const CDK_NUMERIC_TOKEN = Token.asNumber({ Ref: 'abc' }); describe('Endpoint', () => { test('accepts tokens for the port value', () => { diff --git a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts index a55a23df02421..db0e8f6feb38b 100644 --- a/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts +++ b/packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts @@ -862,6 +862,27 @@ describe('serverless cluster', () => { vpcSubnets, })).toThrow(/A VPC is required to use vpcSubnets in ServerlessCluster. Please add a VPC or remove vpcSubnets/); }); + + test('can call exportValue on endpoint.port', () => { + // GIVEN + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + const cluster = new ServerlessCluster(stack, 'Database', { + engine: DatabaseClusterEngine.AURORA_MYSQL, + credentials: { username: 'admin' }, + vpc, + }); + + // WHEN + stack.exportValue(cluster.clusterEndpoint.port); + + // THEN + const template = Template.fromStack(stack); + template.hasOutput('ExportsOutputFnGetAttDatabaseB269D8BBEndpointPort3ACB3F51', { + Value: { 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'] }, + Export: { Name: 'Default:ExportsOutputFnGetAttDatabaseB269D8BBEndpointPort3ACB3F51' }, + }); + }); }); function testStack(app?: cdk.App, id?: string): cdk.Stack { diff --git a/packages/@aws-cdk/core/lib/token.ts b/packages/@aws-cdk/core/lib/token.ts index 9b87a0792fa2b..72b6d74118ac2 100644 --- a/packages/@aws-cdk/core/lib/token.ts +++ b/packages/@aws-cdk/core/lib/token.ts @@ -99,6 +99,10 @@ export class Token { * Return a resolvable representation of the given value */ public static asAny(value: any): IResolvable { + // First, reverse any encoding that was already done (so we end up with an IResolvable + // if it was a token). + value = Tokenization.reverse(value) ?? value; + // Then, either return the IResolvable we resolved to, or wrap in an Intrinsic return isResolvableObject(value) ? value : new Intrinsic(value); } diff --git a/packages/@aws-cdk/core/test/tokens.test.ts b/packages/@aws-cdk/core/test/tokens.test.ts index 62cd683da6ac2..03384be3d7f0d 100644 --- a/packages/@aws-cdk/core/test/tokens.test.ts +++ b/packages/@aws-cdk/core/test/tokens.test.ts @@ -523,6 +523,21 @@ describe('tokens', () => { expect(resolved).toEqual({ value: 123 }); }); + test('Tokens are still reversible after having been encoded multiple times', () => { + // GIVEN + const original = new Intrinsic(123); + + // WHEN + let x: any = original; + x = Token.asString(x); + x = Token.asNumber(x); + x = Token.asList(x); + x = Token.asString(x); + + // THEN + expect(Tokenization.reverse(x)).toBe(original); + }); + test('regex detects all stringifications of encoded tokens', () => { expect(stringContainsNumberTokens(`${createTokenDouble(0)}`)).toBeTruthy(); expect(stringContainsNumberTokens(`${createTokenDouble(Math.pow(2, 48) - 1)}`)).toBeTruthy(); // MAX_ENCODABLE_INTEGER