Skip to content

Commit

Permalink
fix(amplify-table): describe ttl rate limit (#2410)
Browse files Browse the repository at this point in the history
* fix(amplify-table): describe ttl rate limit

* add e2e tests

* add update e2e test

* fix unit test

* resolve conflict

* add error name check

* fix: address CRs

* chore: update code comments

* chore: add comments for custom ddb input
  • Loading branch information
AaronZyLee authored Apr 9, 2024
1 parent 045ece2 commit 0d2ea6a
Show file tree
Hide file tree
Showing 12 changed files with 807 additions and 379 deletions.
711 changes: 360 additions & 351 deletions codebuild_specs/e2e_workflow.yml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('CDK amplify table 3', () => {
let updateTemplatePath;
updateTemplatePath = path.resolve(path.join(__dirname, 'backends', 'amplify-table', 'simple-todo', 'updateKeySchema', 'disabled'));
updateCDKAppWithTemplate(projRoot, updateTemplatePath);
await expect(() => cdkDeploy(projRoot, '--all')).rejects.toThrow();
await expect(cdkDeploy(projRoot, '--all')).rejects.toThrow();
const tableAfterFailure = await getDDBTable(tableName, region);
expect(tableAfterFailure.Table.KeySchema[0]).toEqual({
AttributeName: 'id',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as path from 'path';
import { createNewProjectDir, deleteProjectDir, getDDBTable } from 'amplify-category-api-e2e-core';
import { cdkDestroy, initCDKProject, cdkDeploy, updateCDKAppWithTemplate } from '../commands';

jest.setTimeout(1000 * 60 * 60 /* 1 hour */);

describe('CDK amplify table 4', () => {
let projRoot: string;
let projFolderName: string;

beforeEach(async () => {
projFolderName = 'cdkamplifytable4';
projRoot = await createNewProjectDir(projFolderName);
});

afterEach(async () => {
try {
await cdkDestroy(projRoot, '--all');
} catch (_) {
/* No-op */
}

deleteProjectDir(projRoot);
});

test('should not throw limit exceed error when creating a large number of tables with datastore enabled', async () => {
const templatePath = path.resolve(path.join(__dirname, 'backends', 'amplify-table', 'rate-limit', 'createTableTtl'));
await initCDKProject(projRoot, templatePath);
await expect(cdkDeploy(projRoot, '--all')).resolves.not.toThrow();
});
test('should not throw limit exceed error when creating a large number of tables with datastore disabled at first and enabled in second deployment', async () => {
const templatePath = path.resolve(path.join(__dirname, 'backends', 'amplify-table', 'rate-limit', 'updateTableTtl', 'disabled'));
await initCDKProject(projRoot, templatePath);
await expect(cdkDeploy(projRoot, '--all')).resolves.not.toThrow();
// deploy with datastore enabled
let updateTemplatePath;
updateTemplatePath = path.resolve(path.join(__dirname, 'backends', 'amplify-table', 'rate-limit', 'updateTableTtl', 'enabled'));
updateCDKAppWithTemplate(projRoot, updateTemplatePath);
await expect(cdkDeploy(projRoot, '--all')).resolves.not.toThrow();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env node
import 'source-map-support/register';
import { App, Stack, Duration } from 'aws-cdk-lib';
// @ts-ignore
import { AmplifyGraphqlApi, AmplifyGraphqlDefinition } from '@aws-amplify/graphql-api-construct';

const packageJson = require('../package.json');

const app = new App();
const stack = new Stack(app, packageJson.name.replace(/_/g, '-'), {
env: { region: process.env.CLI_REGION || 'us-west-2' },
});
const schema =
`input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }\n` +
Array.from({ length: 60 }, (_, i) => i + 1)
.map(
(number) =>
`type Todo${number} @model {
id: ID!
}
`,
)
.join('\n');
new AmplifyGraphqlApi(stack, 'GraphqlApi', {
apiName: 'MyGraphQLApi',
definition: AmplifyGraphqlDefinition.fromString(schema, {
dbType: 'DYNAMODB',
provisionStrategy: 'AMPLIFY_TABLE',
}),
dataStoreConfiguration: {
project: {
detectionType: 'VERSION',
handlerType: 'AUTOMERGE',
},
},
authorizationModes: {
apiKeyConfig: { expires: Duration.days(7) },
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env node
import 'source-map-support/register';
import { App, Stack, Duration } from 'aws-cdk-lib';
// @ts-ignore
import { AmplifyGraphqlApi, AmplifyGraphqlDefinition } from '@aws-amplify/graphql-api-construct';

const packageJson = require('../package.json');

const app = new App();
const stack = new Stack(app, packageJson.name.replace(/_/g, '-'), {
env: { region: process.env.CLI_REGION || 'us-west-2' },
});
const schema =
`input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }\n` +
Array.from({ length: 60 }, (_, i) => i + 1)
.map(
(number) =>
`type Todo${number} @model {
id: ID!
}
`,
)
.join('\n');
new AmplifyGraphqlApi(stack, 'GraphqlApi', {
apiName: 'MyGraphQLApi',
definition: AmplifyGraphqlDefinition.fromString(schema, {
dbType: 'DYNAMODB',
provisionStrategy: 'AMPLIFY_TABLE',
}),
authorizationModes: {
apiKeyConfig: { expires: Duration.days(7) },
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env node
import 'source-map-support/register';
import { App, Stack, Duration } from 'aws-cdk-lib';
// @ts-ignore
import { AmplifyGraphqlApi, AmplifyGraphqlDefinition } from '@aws-amplify/graphql-api-construct';

const packageJson = require('../package.json');

const app = new App();
const stack = new Stack(app, packageJson.name.replace(/_/g, '-'), {
env: { region: process.env.CLI_REGION || 'us-west-2' },
});
const schema =
`input AMPLIFY { globalAuthRule: AuthRule = { allow: public } }\n` +
Array.from({ length: 60 }, (_, i) => i + 1)
.map(
(number) =>
`type Todo${number} @model {
id: ID!
}
`,
)
.join('\n');
new AmplifyGraphqlApi(stack, 'GraphqlApi', {
apiName: 'MyGraphQLApi',
definition: AmplifyGraphqlDefinition.fromString(schema, {
dbType: 'DYNAMODB',
provisionStrategy: 'AMPLIFY_TABLE',
}),
dataStoreConfiguration: {
project: {
detectionType: 'VERSION',
handlerType: 'AUTOMERGE',
},
},
authorizationModes: {
apiKeyConfig: { expires: Duration.days(7) },
},
});
3 changes: 2 additions & 1 deletion packages/amplify-graphql-model-transformer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
"src/**/*.ts"
],
"coveragePathIgnorePatterns": [
"/__tests__/"
"/__tests__/",
".d.ts"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,65 @@ Object {
}
`;

exports[`Custom Resource Lambda Tests Extract table definition input from event test should extract the correct old table definition from event object 1`] = `
Object {
"attributeDefinitions": Array [
Object {
"attributeName": "todoId",
"attributeType": "S",
},
Object {
"attributeName": "name",
"attributeType": "S",
},
Object {
"attributeName": "name2",
"attributeType": "S",
},
],
"billingMode": "PROVISIONED",
"globalSecondaryIndexes": Array [
Object {
"indexName": "byName2",
"keySchema": Array [
Object {
"attributeName": "name2",
"keyType": "HASH",
},
],
"projection": Object {
"projectionType": "ALL",
},
"provisionedThroughput": Object {
"readCapacityUnits": 5,
"writeCapacityUnits": 5,
},
},
],
"keySchema": Array [
Object {
"attributeName": "todoId",
"keyType": "HASH",
},
Object {
"attributeName": "name",
"keyType": "RANGE",
},
],
"provisionedThroughput": Object {
"readCapacityUnits": 5,
"writeCapacityUnits": 5,
},
"sseSpecification": Object {
"sseEnabled": true,
},
"streamSpecification": Object {
"streamViewType": "NEW_AND_OLD_IMAGES",
},
"tableName": "mockTableName",
}
`;

exports[`Custom Resource Lambda Tests Extract table definition input from event test should extract the correct table definition from event object and parse it into create table input 1`] = `
Object {
"attributeDefinitions": Array [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
getSseUpdate,
getPointInTimeRecoveryUpdate,
getDeletionProtectionUpdate,
extractOldTableInputFromEvent,
isTtlModified,
} from '../resources/amplify-dynamodb-table/amplify-table-manager-lambda/amplify-table-manager-handler';
import * as CustomDDB from '../resources/amplify-dynamodb-table/amplify-table-types';
import {
Expand Down Expand Up @@ -538,6 +540,79 @@ describe('Custom Resource Lambda Tests', () => {
const createTableInput = toCreateTableInput(tableDef);
expect(createTableInput).toMatchSnapshot();
});
it('should extract the correct old table definition from event object', () => {
const mockEvent = {
ServiceToken: 'mockServiceToken',
ResponseURL: 'mockResponseURL',
StackId: 'mockStackId',
RequestId: 'mockRequestId',
LogicalResourceId: 'mockLogicalResourceId',
ResourceType: 'mockResourceType',
RequestType: 'Create' as RequestType,
ResourceProperties: {
ServiceToken: 'mockServiceToken',
},
OldResourceProperties: {
ServiceToken: 'mockServiceToken',
tableName: 'mockTableName',
attributeDefinitions: [
{
attributeName: 'todoId',
attributeType: 'S',
},
{
attributeName: 'name',
attributeType: 'S',
},
{
attributeName: 'name2',
attributeType: 'S',
},
],
keySchema: [
{
attributeName: 'todoId',
keyType: 'HASH',
},
{
attributeName: 'name',
keyType: 'RANGE',
},
],
globalSecondaryIndexes: [
{
indexName: 'byName2',
keySchema: [
{
attributeName: 'name2',
keyType: 'HASH',
},
],
projection: {
projectionType: 'ALL',
},
provisionedThroughput: {
readCapacityUnits: '5',
writeCapacityUnits: '5',
},
},
],
billingMode: 'PROVISIONED',
provisionedThroughput: {
readCapacityUnits: '5',
writeCapacityUnits: '5',
},
sseSpecification: {
sseEnabled: 'true',
},
streamSpecification: {
streamViewType: 'NEW_AND_OLD_IMAGES',
},
},
};
const tableDef = extractOldTableInputFromEvent(mockEvent);
expect(tableDef).toMatchSnapshot();
});
});
describe('Non GSI update', () => {
let currentState: TableDescription;
Expand Down Expand Up @@ -1011,4 +1086,49 @@ describe('Custom Resource Lambda Tests', () => {
});
});
});
describe('isTtlModified', () => {
it('return false if two ttl are undefined', () => {
expect(isTtlModified(undefined, undefined)).toBe(false);
});
it('return false if two ttl are same', () => {
const oldTtl = {
enabled: true,
attributeName: '_ttl',
};
const newTtl = {
enabled: true,
attributeName: '_ttl',
};
expect(isTtlModified(oldTtl, newTtl)).toBe(false);
});
it('return true if one of the ttl is undefined', () => {
const newTtl = {
enabled: true,
attributeName: '_ttl',
};
expect(isTtlModified(undefined, newTtl)).toBe(true);
});
it('return true if ttl switch is different', () => {
const oldTtl = {
enabled: true,
attributeName: '_ttl',
};
const newTtl = {
enabled: false,
attributeName: '_ttl',
};
expect(isTtlModified(oldTtl, newTtl)).toBe(true);
});
it('return true if ttl attribute name is different', () => {
const oldTtl = {
enabled: true,
attributeName: '_ttl',
};
const newTtl = {
enabled: true,
attributeName: '_ttl2',
};
expect(isTtlModified(oldTtl, newTtl)).toBe(true);
});
});
});
Loading

0 comments on commit 0d2ea6a

Please sign in to comment.