1+ const fs = require ( 'fs' )
2+ const rp = require ( 'request-promise' )
3+
4+ describe ( 'template.yaml' , ( ) => {
5+ // NOTE: These tests all assume that the CFN template has already been packaged *PER REGION*!
6+ const cfnTimeout = 75 ,
7+ // run the test with a timeout of slightly longer than double the CFN stack timeout
8+ testTimeout = 1000 * 60 * cfnTimeout * 2 + 1
9+ const _console = console . log
10+
11+ async function commonTest ( region , stackMiddlefix ) {
12+ let unixTimestamp = Math . floor ( new Date ( ) / 1000 ) ,
13+ stackName = `cfn-integ-${ stackMiddlefix } -${ unixTimestamp } ` ,
14+ s3Params = {
15+ // CFN, when reading the template from S3, requires the S3 bucket to be in the same region as the CFN stack...
16+ Bucket : `dev-portal-integ-${ region } ` ,
17+ Body : fs . readFileSync ( `./cloudformation/packaged-${ region } .yaml` ) ,
18+ Key : stackName
19+ } ,
20+ cfnParams = {
21+ StackName : stackName ,
22+ Capabilities : [ 'CAPABILITY_NAMED_IAM' , 'CAPABILITY_AUTO_EXPAND' ] ,
23+ Parameters : [
24+ {
25+ ParameterKey : 'DevPortalSiteS3BucketName' ,
26+ ParameterValue : `integ-${ stackMiddlefix } -${ unixTimestamp } -dev-portal-test`
27+ } ,
28+ {
29+ ParameterKey : 'ArtifactsS3BucketName' ,
30+ ParameterValue : `integ-${ stackMiddlefix } -${ unixTimestamp } -artifact-bucket`
31+ } ,
32+ {
33+ ParameterKey : 'DevPortalCustomersTableName' ,
34+ ParameterValue : `Customers${ unixTimestamp } `
35+ } ,
36+ {
37+ ParameterKey : 'CognitoDomainNameOrPrefix' ,
38+ ParameterValue : `integ-${ stackMiddlefix } -${ unixTimestamp } `
39+ }
40+ ] ,
41+ // RoleARN: 'STRING_VALUE',
42+ TimeoutInMinutes : cfnTimeout
43+ }
44+
45+ console . log ( 'commonTest' , region )
46+
47+ const AWS = require ( 'aws-sdk' )
48+ AWS . config . update ( { region : region } )
49+
50+ // pin versions of SDKs
51+ const cfn = new AWS . CloudFormation ( { region : region } ) ,
52+ s3 = new AWS . S3 ( { region : region } ) ,
53+ logger = function ( input ) {
54+ _console ( `${ region } :${ stackName } :${ input } ` )
55+ }
56+
57+ // Upload the packaged template to S3, then use the resulting URL in the CFN createStack call
58+ // This is necessary because the file is too large to deliver in-line to CFN
59+ cfnParams . TemplateURL = ( await s3 . upload ( s3Params ) . promise ( ) ) . Location
60+
61+ logger ( 'createStack call starting.' )
62+ await cfn . createStack ( cfnParams ) . promise ( )
63+ logger ( 'createStack call succeeded.' )
64+
65+ logger ( 'stackExists waiter starting.' )
66+ await cfn . waitFor ( 'stackExists' , { StackName : stackName } ) . promise ( )
67+ logger ( 'stackExists waiter succeeded.' )
68+
69+ logger ( 'stackCreateComplete waiter starting.' )
70+ let devPortalUrl =
71+ ( await cfn . waitFor ( 'stackCreateComplete' , { StackName : stackName } ) . promise ( ) ) . Stacks [ 0 ] . Outputs
72+ . find ( ( output ) => output . OutputKey === 'WebsiteURL' ) . OutputValue
73+ logger ( 'stackCreateComplete waiter succeeded.' )
74+
75+ logger ( `verifying that stack is available at ${ devPortalUrl } .` )
76+ let staticIndex = await rp ( devPortalUrl )
77+
78+ expect ( staticIndex . includes ( '<title>Developer Portal</title>' ) ) . toBeTruthy ( )
79+ logger ( `verified that stack is available at ${ devPortalUrl } .` )
80+
81+ // add RoleArn: ... later
82+ logger ( 'deleteStack call starting.' )
83+ await cfn . deleteStack ( { StackName : stackName } ) . promise ( )
84+ logger ( 'deleteStack call succeeded.' )
85+
86+ logger ( 'stackDeleteComplete waiter starting.' )
87+ await cfn . waitFor ( 'stackDeleteComplete' , { StackName : stackName } ) . promise ( )
88+ logger ( 'stackDeleteComplete waiter succeeded.' )
89+
90+ // pass the test; we successfully stood the stack up and tore it down
91+ expect ( true ) . toBe ( true )
92+
93+ return true
94+ }
95+
96+ test . concurrent ( 'should stand up and tear down the stack in IAD' , async ( ) => {
97+ return commonTest ( 'us-east-1' , 'us-east-1' )
98+ } , testTimeout )
99+
100+ test . concurrent ( 'should stand up and tear down the stack in a non-IAD region' , async ( ) => {
101+ return commonTest ( 'us-west-2' , 'us-west-2' )
102+ } , testTimeout )
103+
104+ // Implement these! Hardest part will be having test ACM certs in the account
105+ // test('should stand up and tear down a custom domain stack in IAD', async () => {
106+ // return commonTest('us-east-1', 'domain-us-east-1')
107+ // }, testTimeout)
108+ //
109+ // test('should stand up and tear down a custom domain stack in a non-IAD region', async () => {
110+ // return commonTest('us-west-2', 'domain-us-west-2')
111+ // }, testTimeout)
112+ } )
0 commit comments