diff --git a/packages/aws-cdk/lib/api/evaluate-cloudformation-template.ts b/packages/aws-cdk/lib/api/evaluate-cloudformation-template.ts index 61d6a750b4482..405e51d7c2f9b 100644 --- a/packages/aws-cdk/lib/api/evaluate-cloudformation-template.ts +++ b/packages/aws-cdk/lib/api/evaluate-cloudformation-template.ts @@ -7,30 +7,30 @@ export interface ListStackResources { } export class LazyListStackResources implements ListStackResources { - private stackResources: AWS.CloudFormation.StackResourceSummary[] | undefined; + private stackResources: Promise | undefined; constructor(private readonly sdk: ISDK, private readonly stackName: string) { } public async listStackResources(): Promise { if (this.stackResources === undefined) { - this.stackResources = await this.getStackResources(); + this.stackResources = this.getStackResources(undefined); } return this.stackResources; } - private async getStackResources(): Promise { + private async getStackResources(nextToken: string | undefined): Promise { const ret = new Array(); - let nextToken: string | undefined; - do { - const stackResourcesResponse = await this.sdk.cloudFormation().listStackResources({ - StackName: this.stackName, - NextToken: nextToken, - }).promise(); + return this.sdk.cloudFormation().listStackResources({ + StackName: this.stackName, + NextToken: nextToken, + }).promise().then(async stackResourcesResponse => { ret.push(...(stackResourcesResponse.StackResourceSummaries ?? [])); - nextToken = stackResourcesResponse.NextToken; - } while (nextToken); - return ret; + if (stackResourcesResponse.NextToken) { + ret.push(...await this.getStackResources(stackResourcesResponse.NextToken)); + } + return ret; + }); } } diff --git a/packages/aws-cdk/test/api/lazy-list-stack-resources.test.ts b/packages/aws-cdk/test/api/lazy-list-stack-resources.test.ts new file mode 100644 index 0000000000000..64d0b98d62733 --- /dev/null +++ b/packages/aws-cdk/test/api/lazy-list-stack-resources.test.ts @@ -0,0 +1,29 @@ +import * as AWS from 'aws-sdk'; +import { LazyListStackResources } from '../../lib/api/evaluate-cloudformation-template'; +import { MockSdk } from '../util/mock-sdk'; + +describe('Lazy ListStackResources', () => { + test('correctly caches calls to the CloudFormation API', async () => { + // GIVEN + const listStackResMock: jest.Mock = jest.fn(); + const mockSdk = new MockSdk(); + mockSdk.stubCloudFormation({ + listStackResources: listStackResMock, + }); + listStackResMock.mockReturnValue({ + StackResourceSummaries: [], + NextToken: undefined, + }); + const res = new LazyListStackResources(mockSdk, 'StackName'); + + // WHEN + void res.listStackResources(); + void res.listStackResources(); + void res.listStackResources(); + const result = await res.listStackResources(); + + // THEN + expect(result.length).toBe(0); + expect(listStackResMock).toHaveBeenCalledTimes(1); + }); +});