Skip to content

Commit 19ba7cf

Browse files
authored
Merge pull request #14189 from aws-amplify/gen2-migrations-execute
2 parents af01ce7 + 094e7a7 commit 19ba7cf

13 files changed

Lines changed: 215 additions & 335 deletions

packages/amplify-migration-e2e/src/__tests__/migration_codegen_e2e.test.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import path from 'node:path';
22
import assert from 'node:assert';
3-
import { createNewProjectDir, generateRandomShortId, npmInstall } from '@aws-amplify/amplify-e2e-core';
3+
import { createNewProjectDir, generateRandomShortId, getSocialProviders, npmInstall } from '@aws-amplify/amplify-e2e-core';
44
import { createGen2Renderer } from '@aws-amplify/amplify-gen2-codegen';
55
import { copyFunctionFile, removeErrorThrowsFromFunctionFile } from '../function_utils';
6-
import { copyGen1Schema } from '../api_utils';
76
import {
87
cleanupProjects,
98
setupAndPushDefaultGen1Project,
@@ -54,25 +53,40 @@ void describe('Gen 2 Codegen E2E tests', () => {
5453
await cleanupProjects(projRoot, projName);
5554
});
5655

57-
void it.only('should init a project & add auth, function, storage, api with defaults & perform full migration codegen flow', async () => {
56+
void it('should init a project & add auth, function, storage, api with defaults & perform full migration codegen flow', async () => {
57+
// Arrange
5858
await setupAndPushDefaultGen1Project(projRoot, projName);
59+
60+
// Act
5961
const { gen1UserPoolId, gen1ClientIds, gen1IdentityPoolId, gen1FunctionName, gen1BucketName, gen1GraphqlApiId, gen1Region, envName } =
6062
await assertDefaultGen1Setup(projRoot);
6163
runCodegenCommand(projRoot);
6264
copyFunctionFile(projRoot, 'function', gen1FunctionName);
63-
copyGen1Schema(projRoot, projName);
6465
removeErrorThrowsFromFunctionFile(projRoot, 'function', extractFunctionResourceName(gen1FunctionName, envName));
6566
updateAmplifyBackendPackagesVersion(projRoot);
6667
npmInstall(projRoot);
6768
const gen2StackName = await runGen2SandboxCommand(projRoot, projName);
69+
70+
// Assert
6871
await assertAuthResource(projRoot, gen1UserPoolId, gen1ClientIds, gen1IdentityPoolId, gen1Region);
6972
await assertStorageResource(projRoot, gen1BucketName, gen1Region);
7073
await assertFunctionResource(projRoot, gen2StackName, gen1FunctionName, gen1Region);
7174
await assertDataResource(projRoot, gen2StackName, gen1GraphqlApiId, gen1Region);
7275
});
7376

7477
void it('should init a project where all possible auth options are selected and perform full migration codegen flow ', async () => {
78+
// Arrange
79+
const socialProviders = getSocialProviders();
80+
Object.entries(socialProviders).forEach(([socialProvider, value]) => {
81+
// we expect APPLE_PRIVATE_KEY_2 in process.env but getSocialProviders returns as APPLE_PRIVATE_KEY
82+
if (socialProvider === 'APPLE_PRIVATE_KEY') {
83+
socialProvider = 'APPLE_PRIVATE_KEY_2';
84+
}
85+
process.env[socialProvider] = process.env[socialProvider] ?? value;
86+
});
7587
await setupAndPushAuthWithMaxOptionsGen1Project(projRoot, projName);
88+
89+
// Act
7690
const { gen1UserPoolId, gen1ClientIds, gen1IdentityPoolId, gen1FunctionName, gen1Region } = await assertAuthWithMaxOptionsGen1Setup(
7791
projRoot,
7892
);
@@ -84,19 +98,26 @@ void describe('Gen 2 Codegen E2E tests', () => {
8498
await toggleSandboxSecrets(projRoot, projName, 'set');
8599
const gen2StackName = await runGen2SandboxCommand(projRoot, projName);
86100
await toggleSandboxSecrets(projRoot, projName, 'remove');
101+
102+
// Assert
87103
await assertAuthResource(projRoot, gen1UserPoolId, gen1ClientIds, gen1IdentityPoolId, gen1Region);
88104
await assertFunctionResource(projRoot, gen2StackName, gen1FunctionName, gen1Region);
89105
});
90106

91107
void it('should init a project where default auth, all possible s3 bucket resource options are selected and perform full migration codegen flow ', async () => {
108+
// Arrange
92109
await setupAndPushStorageWithMaxOptionsGen1Project(projRoot, projName);
93-
const { gen1UserPoolId, gen1ClientIds, gen1BucketName, gen1IdentityPoolId, gen1Region, gen1FunctionName } =
110+
111+
// Act
112+
const { gen1UserPoolId, gen1ClientIds, gen1BucketName, gen1IdentityPoolId, gen1Region, gen1FunctionName, envName } =
94113
await assertStorageWithMaxOptionsGen1Setup(projRoot);
95114
runCodegenCommand(projRoot);
96115
updateAmplifyBackendPackagesVersion(projRoot);
97116
npmInstall(projRoot);
98117
removeErrorThrowsFromFunctionFile(projRoot, 'storage', extractFunctionResourceName(gen1FunctionName, envName));
99118
await runGen2SandboxCommand(projRoot, projName);
119+
120+
// Assert
100121
await assertAuthResource(projRoot, gen1UserPoolId, gen1ClientIds, gen1IdentityPoolId, gen1Region);
101122
await assertStorageResource(projRoot, gen1BucketName, gen1Region);
102123
});

packages/amplify-migration-e2e/src/__tests__/migration_templategen_e2e.test.ts

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,59 @@
11
import path from 'node:path';
22
import assert from 'node:assert';
3-
import { createNewProjectDir, npmInstall, deleteS3Bucket, generateRandomShortId } from '@aws-amplify/amplify-e2e-core';
3+
import { createNewProjectDir, npmInstall, generateRandomShortId } from '@aws-amplify/amplify-e2e-core';
44
import { assertDefaultGen1Setup } from '../assertions';
5-
import { setupAndPushDefaultGen1Project, runCodegenCommand, runGen2SandboxCommand, cleanupProjects } from '..';
6-
import { copyFunctionFile } from '../function_utils';
7-
import { copyGen1Schema } from '../api_utils';
8-
import { createS3Bucket } from '../sdk_calls';
9-
import { runExecuteCommand, runRevertCommand } from '../templategen';
5+
import {
6+
setupAndPushDefaultGen1Project,
7+
runCodegenCommand,
8+
runGen2SandboxCommand,
9+
cleanupProjects,
10+
extractFunctionResourceName,
11+
updateAmplifyBackendPackagesVersion,
12+
} from '..';
13+
import { copyFunctionFile, removeErrorThrowsFromFunctionFile } from '../function_utils';
14+
import { assertExecuteCommand, RefactorCategory, runExecuteCommand, runGen2DeployPostExecute, runRevertCommand } from '../templategen';
15+
16+
const CATEGORIES_TO_MOVE: RefactorCategory[] = ['auth', 'storage'];
1017

1118
void describe('Templategen E2E tests', () => {
1219
void describe('Full Migration Templategen Flow', () => {
1320
let projRoot: string;
1421
let projName: string;
15-
let bucketName: string;
1622

1723
beforeEach(async () => {
1824
const baseDir = process.env.INIT_CWD ?? process.cwd();
1925
projRoot = await createNewProjectDir('templategen_e2e_flow_test', path.join(baseDir, '..', '..'));
2026
projName = `test${generateRandomShortId()}`;
21-
bucketName = `testbucket${generateRandomShortId()}`;
2227
});
2328

2429
afterEach(async () => {
2530
await cleanupProjects(projRoot, projName);
26-
await deleteS3Bucket(bucketName);
2731
});
2832

2933
void it('should init a project & add auth, function, storage, api with defaults & perform refactor', async () => {
34+
// Arrange
3035
await setupAndPushDefaultGen1Project(projRoot, projName);
31-
const { gen1StackName, gen1FunctionName } = await assertDefaultGen1Setup(projRoot);
32-
assert(gen1StackName);
33-
runCodegenCommand(projRoot);
34-
copyFunctionFile(projRoot, 'function', gen1FunctionName);
35-
copyGen1Schema(projRoot, projName);
36-
npmInstall(projRoot);
37-
const gen2StackName = await runGen2SandboxCommand(projRoot, projName);
38-
assert(gen2StackName);
39-
runExecuteCommand(projRoot, gen1StackName, gen2StackName);
40-
});
4136

42-
void it('should init a project & add auth, function, storage, api with defaults, perform refactor and revert to the original state', async () => {
43-
await setupAndPushDefaultGen1Project(projRoot, projName);
44-
const { gen1StackName, gen1FunctionName, gen1Region } = await assertDefaultGen1Setup(projRoot);
45-
await createS3Bucket(bucketName, gen1Region);
37+
// Act
38+
const { gen1StackName, gen1FunctionName, envName } = await assertDefaultGen1Setup(projRoot);
4639
assert(gen1StackName);
4740
runCodegenCommand(projRoot);
4841
copyFunctionFile(projRoot, 'function', gen1FunctionName);
49-
copyGen1Schema(projRoot, projName);
42+
removeErrorThrowsFromFunctionFile(projRoot, 'function', extractFunctionResourceName(gen1FunctionName, envName));
43+
updateAmplifyBackendPackagesVersion(projRoot);
5044
npmInstall(projRoot);
45+
// Below env is only needed for CI/CD deployments and is expected to be set by customers for their app
46+
// To emulate the migration in sandbox, we set it explicitly.
47+
process.env.AMPLIFY_GEN_1_ENV_NAME = envName;
5148
const gen2StackName = await runGen2SandboxCommand(projRoot, projName);
5249
assert(gen2StackName);
50+
5351
runExecuteCommand(projRoot, gen1StackName, gen2StackName);
52+
await runGen2DeployPostExecute(projRoot, projName, envName, CATEGORIES_TO_MOVE);
53+
54+
// Assert
55+
await assertExecuteCommand(projRoot, CATEGORIES_TO_MOVE);
56+
5457
runRevertCommand(projRoot, gen1StackName, gen2StackName);
5558
});
5659
});

packages/amplify-migration-e2e/src/assertions.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { removeProperties } from '.';
1313
import { $TSAny } from '@aws-amplify/amplify-cli-core';
1414
import assert from 'node:assert';
1515

16+
const DATA_SOURCE_PROPS_TO_REMOVE = ['dataSourceArn', 'serviceRoleArn', 'dynamodbConfig'];
17+
1618
export async function assertUserPool(gen1Meta: $TSAny, gen1Region: string) {
1719
const { UserPoolId: gen1UserPoolId } = Object.keys(gen1Meta.auth).map((key) => gen1Meta.auth[key])[0].output;
1820
const cloudUserPool = await getUserPool(gen1UserPoolId, gen1Region);
@@ -129,17 +131,24 @@ export async function assertAuthWithMaxOptionsGen1Setup(projRoot: string) {
129131

130132
export async function assertStorageWithMaxOptionsGen1Setup(projRoot: string) {
131133
const gen1Meta = getProjectMeta(projRoot);
134+
const gen1StackName = gen1Meta.providers.awscloudformation.StackName;
132135
const gen1Region = gen1Meta.providers.awscloudformation.Region;
133136
const { gen1BucketName } = await assertStorage(gen1Meta, gen1Region);
134137
const { gen1UserPoolId } = await assertUserPool(gen1Meta, gen1Region);
135138
const { gen1FunctionName } = await assertFunction(gen1Meta, gen1Region);
136139
assert.match(gen1FunctionName, /S3Trigger/);
137140
const { gen1ClientIds } = await assertUserPoolClients(gen1Meta, gen1Region);
138141
const { gen1IdentityPoolId } = await assertIdentityPool(gen1Meta, gen1Region);
142+
const envName = gen1StackName.split('-')[2];
139143

140-
return { gen1UserPoolId, gen1ClientIds, gen1BucketName, gen1IdentityPoolId, gen1Region, gen1FunctionName };
144+
return { gen1UserPoolId, gen1ClientIds, gen1BucketName, gen1IdentityPoolId, gen1Region, gen1FunctionName, envName };
141145
}
142146

147+
const extractUserPoolNamePrefix = (userPoolName: string) => {
148+
const [userPoolNamePrefix] = userPoolName.split('-');
149+
return userPoolNamePrefix;
150+
};
151+
143152
async function assertUserPoolResource(projRoot: string, gen1UserPoolId: string, gen1Region: string) {
144153
const gen1Resource = await getResourceDetails('AWS::Cognito::UserPool', gen1UserPoolId, gen1Region);
145154
removeProperties(gen1Resource, ['ProviderURL', 'ProviderName', 'UserPoolId', 'Arn', 'LambdaConfig.PostConfirmation']);
@@ -156,6 +165,8 @@ async function assertUserPoolResource(projRoot: string, gen1UserPoolId: string,
156165
const gen2UserPoolId = gen2Meta.auth.user_pool_id;
157166
const gen2Region = gen2Meta.auth.aws_region;
158167
const gen2Resource = await getResourceDetails('AWS::Cognito::UserPool', gen2UserPoolId, gen2Region);
168+
gen1Resource.UserPoolName = extractUserPoolNamePrefix(gen1Resource.UserPoolName);
169+
gen2Resource.UserPoolName = extractUserPoolNamePrefix(gen2Resource.UserPoolName);
159170
if (gen1Resource.LambdaConfig.PostConfirmation) assert(gen2Resource.LambdaConfig.PostConfirmation);
160171
removeProperties(gen2Resource, ['ProviderURL', 'ProviderName', 'UserPoolId', 'Arn', 'LambdaConfig.PostConfirmation']);
161172
// TODO: remove below line after EmailMessage, EmailSubject, SmsMessage, SmsVerificationMessage, EmailVerificationMessage, EmailVerificationSubject, AccountRecoverySetting inconsistency is fixed
@@ -275,7 +286,7 @@ export async function assertFunctionResource(projRoot: string, gen2StackName: st
275286
const gen1Resource = await getResourceDetails('AWS::Lambda::Function', gen1FunctionName, gen1Region);
276287
removeProperties(gen1Resource, ['Arn', 'FunctionName', 'LoggingConfig.LogGroup', 'Role']);
277288
// TODO: remove below line after Tags inconsistency is fixed
278-
removeProperties(gen1Resource, ['Tags']);
289+
removeProperties(gen1Resource, ['Tags', 'Environment']);
279290

280291
const gen2Meta = getProjectOutputs(projRoot);
281292
const gen2Region = gen2Meta.auth.aws_region;
@@ -285,15 +296,15 @@ export async function assertFunctionResource(projRoot: string, gen2StackName: st
285296
assert(gen2Resource.FunctionName);
286297
removeProperties(gen2Resource, ['Arn', 'FunctionName', 'LoggingConfig.LogGroup', 'Role']);
287298
// TODO: remove below line after Environment.Variables.AMPLIFY_SSM_ENV_CONFIG, Tags inconsistency is fixed
288-
removeProperties(gen2Resource, ['Environment.Variables.AMPLIFY_SSM_ENV_CONFIG', 'Tags']);
299+
removeProperties(gen2Resource, ['Environment.Variables.AMPLIFY_SSM_ENV_CONFIG', 'Tags', 'Environment']);
289300

290301
expect(gen2Resource).toEqual(gen1Resource);
291302
}
292303

293304
export async function assertDataResource(projRoot: string, gen2StackName: string, gen1GraphqlApiId: string, gen1Region: string) {
294305
const gen1Resource = await getAppSyncApi(gen1GraphqlApiId, gen1Region);
295306
const gen1DataSource = (await getAppSyncDataSource(gen1GraphqlApiId, 'TodoTable', gen1Region)) as Record<string, unknown>;
296-
removeProperties(gen1DataSource, ['dataSourceArn', 'serviceRoleArn']);
307+
removeProperties(gen1DataSource, DATA_SOURCE_PROPS_TO_REMOVE);
297308
removeProperties(gen1Resource.graphqlApi as Record<string, unknown>, ['name', 'apiId', 'arn', 'uris', 'tags', 'dns']);
298309
// TODO: remove below line after authenticationType inconsistency is fixed
299310
removeProperties(gen1Resource.graphqlApi as Record<string, unknown>, ['authenticationType']);
@@ -304,7 +315,7 @@ export async function assertDataResource(projRoot: string, gen2StackName: string
304315
const gen2GraphqlApiId = outputs?.find((output) => output.OutputKey === 'awsAppsyncApiId')?.OutputValue ?? '';
305316
const gen2Resource = await getAppSyncApi(gen2GraphqlApiId, gen2Region);
306317
const gen2DataSource = (await getAppSyncDataSource(gen2GraphqlApiId, 'TodoTable', gen1Region)) as Record<string, unknown>;
307-
removeProperties(gen2DataSource, ['dataSourceArn', 'serviceRoleArn']);
318+
removeProperties(gen2DataSource, DATA_SOURCE_PROPS_TO_REMOVE);
308319
removeProperties(gen2Resource.graphqlApi as Record<string, unknown>, [
309320
'name',
310321
'apiId',

packages/amplify-migration-e2e/src/gen1ResourceDetailsFetcher.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import path from 'path';
22
import { RefactorCategory } from './templategen';
33
import { getProjectMeta } from '@aws-amplify/amplify-e2e-core';
44
import { assertIdentityPool, assertStorage, assertUserPool, assertUserPoolClients } from './assertions';
5-
import { getResourceDetails } from './sdk_calls';
65

76
async function getGen1AuthResourceDetails(projRoot: string) {
87
const gen1ProjRoot = path.join(projRoot, '.amplify', 'migration');
@@ -14,13 +13,7 @@ async function getGen1AuthResourceDetails(projRoot: string) {
1413
const gen1ClientIdWeb = gen1ClientIds[0];
1514
const gen1ResourceIds = [gen1UserPoolId, gen1IdentityPoolId, gen1ClientIdWeb];
1615

17-
const gen1ResourceDetails = await Promise.all([
18-
getResourceDetails('AWS::Cognito::UserPool', gen1UserPoolId, gen1Region),
19-
getResourceDetails('AWS::Cognito::IdentityPool', gen1IdentityPoolId, gen1Region),
20-
getResourceDetails('AWS::Cognito::UserPoolClient', `${gen1UserPoolId}|${gen1ClientIdWeb}`, gen1Region),
21-
]);
22-
23-
return { gen1ResourceIds, gen1ResourceDetails };
16+
return { gen1ResourceIds };
2417
}
2518

2619
async function getGen1StorageResourceDetails(projRoot: string) {
@@ -29,14 +22,14 @@ async function getGen1StorageResourceDetails(projRoot: string) {
2922
const gen1Region = gen1Meta.providers.awscloudformation.Region;
3023
const { gen1BucketName } = await assertStorage(gen1Meta, gen1Region);
3124
const gen1ResourceIds = [gen1BucketName];
32-
const gen1ResourceDetails = await getResourceDetails('AWS::S3::Bucket', gen1BucketName, gen1Region);
33-
return { gen1ResourceIds, gen1ResourceDetails };
25+
return { gen1ResourceIds };
3426
}
3527

3628
export async function getGen1ResourceDetails(projRoot: string, category: RefactorCategory) {
3729
if (category === 'auth') {
3830
return await getGen1AuthResourceDetails(projRoot);
39-
} else {
31+
} else if (category === 'storage') {
4032
return await getGen1StorageResourceDetails(projRoot);
4133
}
34+
throw new Error(`Invalid category for getting Gen 1 resource details ${category}`);
4235
}
Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,28 @@
11
import { getProjectOutputs } from './projectOutputs';
2-
import { getResourceDetails } from './sdk_calls';
32
import { RefactorCategory } from './templategen';
43

54
async function getGen2AuthResourceDetails(projRoot: string) {
65
const gen2Meta = getProjectOutputs(projRoot);
7-
const gen2Region = gen2Meta.auth.aws_region;
86
const gen2UserPoolId = gen2Meta.auth.user_pool_id;
97
const gen2ClientIdWeb = gen2Meta.auth.user_pool_client_id;
108
const gen2IdentityPoolId = gen2Meta.auth.identity_pool_id;
119
const gen2ResourceIds = [gen2UserPoolId, gen2IdentityPoolId, gen2ClientIdWeb];
1210

13-
const gen2ResourceDetails = await Promise.all([
14-
getResourceDetails('AWS::Cognito::UserPool', gen2UserPoolId, gen2Region),
15-
getResourceDetails('AWS::Cognito::IdentityPool', gen2IdentityPoolId, gen2Region),
16-
getResourceDetails('AWS::Cognito::UserPoolClient', `${gen2UserPoolId}|${gen2ClientIdWeb}`, gen2Region),
17-
]);
18-
19-
return { gen2ResourceIds, gen2ResourceDetails };
11+
return { gen2ResourceIds };
2012
}
2113

2214
async function getGen2StorageResourceDetails(projRoot: string) {
2315
const gen2Meta = getProjectOutputs(projRoot);
24-
const gen2Region = gen2Meta.auth.aws_region;
2516
const gen2BucketName = gen2Meta.storage.bucket_name;
2617
const gen2ResourceIds = [gen2BucketName];
27-
const gen2ResourceDetails = await getResourceDetails('AWS::S3::Bucket', gen2BucketName, gen2Region);
28-
return { gen2ResourceIds, gen2ResourceDetails };
18+
return { gen2ResourceIds };
2919
}
3020

3121
export async function getGen2ResourceDetails(projRoot: string, category: RefactorCategory) {
3222
if (category === 'auth') {
3323
return await getGen2AuthResourceDetails(projRoot);
34-
} else {
24+
} else if (category === 'storage') {
3525
return await getGen2StorageResourceDetails(projRoot);
3626
}
27+
throw new Error(`Invalid category for getting Gen 2 resource details ${category}`);
3728
}

0 commit comments

Comments
 (0)