diff --git a/packages/amplify-graphql-api-construct-tests/src/__tests__/migration/migration-validation.test.ts b/packages/amplify-graphql-api-construct-tests/src/__tests__/migration/migration-validation.test.ts index 138f163293..1065afef16 100644 --- a/packages/amplify-graphql-api-construct-tests/src/__tests__/migration/migration-validation.test.ts +++ b/packages/amplify-graphql-api-construct-tests/src/__tests__/migration/migration-validation.test.ts @@ -60,51 +60,117 @@ describe('Migration table import validation', () => { deleteProjectDir(gen1ProjRoot); }); - /* - AttributeDefintions - done - KeySchema - GlobalSecondaryIndexes - done - BillingModeSummary - done - ProvisionedThroughput - StreamSpecification - SSEDescription - DeletionProtectionEnabled - */ - - // Test cases for test.each need to be defined before beforeAll. - // The tests cases need data defined in beforeAll. - // Define the test name first then get the definition later (after beforeAll). - // For each test case, there should be a matching key in the test definitions. - // The test definitions include a schema, overrides, and the expected error messages. - const testCases = ['extraGSIOnGen2', 'billingMode']; - const getTestDefinition = (testCaseName: string): [TestDefinition, string, string[]] => { - const testDefinitions: Record = { - extraGSIOnGen2: [ - { - schema: /* GraphQL */ ` - type Todo @model @auth(rules: [{ allow: public }]) { - id: ID! - content: String @index - } - `, - strategy: { - dbType: 'DYNAMODB' as const, - provisionStrategy: 'IMPORTED_AMPLIFY_TABLE' as const, - tableName: dataSourceMapping.Todo, - }, - }, - '', - [ - 'AttributeDefintions does not match the expected value.\nActual: [{"AttributeName":"id","AttributeType":"S"}]\nExpected: [{"AttributeType":"S","AttributeName":"id"},{"AttributeType":"S","AttributeName":"content"}]', - 'GlobalSecondaryIndexes does not match the expected value.\nActual: undefined\nExpected: [{"IndexName":"todosByContent","KeySchema":[{"AttributeName":"content","KeyType":"HASH"}],"Projection":{"ProjectionType":"ALL"},"ProvisionedThroughput":{"WriteCapacityUnits":5,"ReadCapacityUnits":5}}]', - ], + type TestCase = [ + // test name + string, + // Overrides to apply to the stack. If empty, no overrides are applied. + // The overrides should export a function called applyOverrides that takes an AmplifyGraphqlApi object. + string, + // Expected CloudFormation error messages + string[], + ]; + const testCases: TestCase[] = [ + [ + 'extraGSIOnGen2', + '', + [ + 'AttributeDefintions does not match the expected value.\nActual: [{"AttributeName":"id","AttributeType":"S"}]\nExpected: [{"AttributeType":"S","AttributeName":"id"},{"AttributeType":"S","AttributeName":"content"}]', + 'GlobalSecondaryIndexes does not match the expected value.\nActual: undefined\nExpected: [{"IndexName":"todosByContent","KeySchema":[{"AttributeName":"content","KeyType":"HASH"}],"Projection":{"ProjectionType":"ALL"},"ProvisionedThroughput":{"WriteCapacityUnits":5,"ReadCapacityUnits":5}}]', ], - billingMode: [ - { + ], + [ + 'billingMode', + ` + import { AmplifyGraphqlApi } from '@aws-amplify/graphql-api-construct'; + import { BillingMode } from 'aws-cdk-lib/aws-dynamodb'; + + export const applyOverrides = (api: AmplifyGraphqlApi): void => { + const todoTable = api.resources.cfnResources.additionalCfnResources['Todo']; + todoTable.addOverride('Properties.billingMode', BillingMode.PROVISIONED); + }; + `, + [ + 'BillingModeSummary does not match the expected value.\nActual: {"BillingMode":"PAY_PER_REQUEST"}\nExpected: {"BillingMode":"PROVISIONED"}', + ], + ], + [ + 'keySchema', + ` + import { AmplifyGraphqlApi } from '@aws-amplify/graphql-api-construct'; + import { BillingMode } from 'aws-cdk-lib/aws-dynamodb'; + + export const applyOverrides = (api: AmplifyGraphqlApi): void => { + const todoTable = api.resources.cfnResources.additionalCfnResources['Todo']; + todoTable.addOverride('Properties.keySchema', [{ attributeName: 'fakekey', keyType: 'HASH' }]); + }; + `, + [ + 'KeySchema does not match the expected value.\nActual: [{"AttributeName":"id","KeyType":"HASH"}]\nExpected: [{"AttributeName":"fakekey","KeyType":"HASH"}]', + ], + ], + [ + 'provisionedThroughput', + ` + import { AmplifyGraphqlApi } from '@aws-amplify/graphql-api-construct'; + import { BillingMode } from 'aws-cdk-lib/aws-dynamodb'; + + export const applyOverrides = (api: AmplifyGraphqlApi): void => { + const todoTable = api.resources.cfnResources.additionalCfnResources['Todo']; + todoTable.addOverride('Properties.provisionedThroughput', { + ReadCapacityUnits: 5, + WriteCapacityUnits: 5, + }); + }; + `, + [ + 'ProvisionedThroughput does not match the expected value.\nActual: {"ReadCapacityUnits":0,"WriteCapacityUnits":0}\nExpected: {"WriteCapacityUnits":5,"ReadCapacityUnits":5}', + ], + ], + [ + 'streamSpecification', + ` + import { AmplifyGraphqlApi } from '@aws-amplify/graphql-api-construct'; + import { BillingMode } from 'aws-cdk-lib/aws-dynamodb'; + + export const applyOverrides = (api: AmplifyGraphqlApi): void => { + const todoTable = api.resources.cfnResources.additionalCfnResources['Todo']; + todoTable.addOverride('Properties.streamSpecification', { + streamViewType: "KEYS_ONLY" + }); + }; + `, + [ + 'StreamSpecification does not match the expected value.\nActual: {"StreamEnabled":true,"StreamViewType":"NEW_AND_OLD_IMAGES"}\nExpected: {"StreamEnabled":true,"StreamViewType":"KEYS_ONLY"}', + ], + ], + [ + 'sseDescription', + '', + ['SSEDescription does not match the expected value.\nActual: undefined\nExpected: {"SSEType":"KMS","Status":"ENABLED"}'], + ], + [ + 'deletionProtectionEnabled', + ` + import { AmplifyGraphqlApi } from '@aws-amplify/graphql-api-construct'; + import { BillingMode } from 'aws-cdk-lib/aws-dynamodb'; + + export const applyOverrides = (api: AmplifyGraphqlApi): void => { + const todoTable = api.resources.cfnResources.additionalCfnResources['Todo']; + todoTable.addOverride('Properties.deletionProtectionEnabled', true); + }; + `, + ['DeletionProtectionEnabled does not match the expected value.\nActual: false\nExpected: true'], + ], + ]; + test.each(testCases)('%s', async (testCaseName, overrides, expectedErrors) => { + writeStackConfig(gen2ProjRoot, { prefix: gen2ProjFolderName }); + writeTestDefinitions( + { + [testCaseName]: { schema: /* GraphQL */ ` type Todo @model @auth(rules: [{ allow: public }]) { id: ID! - content: String + content: String @index } `, strategy: { @@ -113,28 +179,9 @@ describe('Migration table import validation', () => { tableName: dataSourceMapping.Todo, }, }, - ` - import { AmplifyGraphqlApi } from '@aws-amplify/graphql-api-construct'; - import { BillingMode } from 'aws-cdk-lib/aws-dynamodb'; - - export const applyOverrides = (api: AmplifyGraphqlApi): void => { - const todoTable = api.resources.cfnResources.additionalCfnResources['Todo']; - todoTable.addOverride('Properties.billingMode', BillingMode.PROVISIONED); - }; - `, - [ - 'BillingModeSummary does not match the expected value.\nActual: {"BillingMode":"PAY_PER_REQUEST"}\nExpected: {"BillingMode":"PROVISIONED"}', - ], - ], - }; - - return testDefinitions[testCaseName]; - }; - - test.each(testCases.map((testCase) => [testCase]))('%s', async (testCaseName) => { - const [testDefinition, overrides, expectedErrors] = getTestDefinition(testCaseName); - writeStackConfig(gen2ProjRoot, { prefix: gen2ProjFolderName }); - writeTestDefinitions({ [testCaseName]: testDefinition }, gen2ProjRoot); + }, + gen2ProjRoot, + ); // if no overrides are provided, use the default applyOverrides function (no-op) if (overrides) { writeOverrides(overrides, gen2ProjRoot); diff --git a/yarn.lock b/yarn.lock index ef70adf9ae..363a4924c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10322,9 +10322,9 @@ async@^2.6.4: lodash "^4.17.14" async@^3.2.0, async@^3.2.3, async@^3.2.4: - version "3.2.5" - resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + version "3.2.6" + resolved "https://registry.npmjs.org/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynciterator.prototype@^1.0.0: version "1.0.0"