-
Notifications
You must be signed in to change notification settings - Fork 89
chore: migrate pg array objects e2e test in gen2 cdk #2906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bbd311d
8439764
5d1456e
55840d7
96e9fd9
a8ecafb
f1f08be
8aeaa60
36bce02
4e3e3df
869e7b8
18e6714
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import generator from 'generate-password'; | ||
| import { getResourceNamesForStrategyName, ImportedRDSType } from '@aws-amplify/graphql-transformer-core'; | ||
| import { getRDSTableNamePrefix } from 'amplify-category-api-e2e-core'; | ||
| import { SqlDatatabaseController } from '../sql-datatabase-controller'; | ||
| import { DURATION_1_HOUR } from '../utils/duration-constants'; | ||
| import { testGraphQLAPIArrayAndObjects } from '../sql-tests-common/sql-array-objects'; | ||
|
|
||
| jest.setTimeout(DURATION_1_HOUR); | ||
|
|
||
| describe('CDK GraphQL Transformer deployments with Postgres SQL datasources', () => { | ||
| const projFolderName = 'pgmodels'; | ||
|
|
||
| // sufficient password length that meets the requirements for RDS cluster/instance | ||
| const [username, password, identifier] = generator.generateMultiple(3, { length: 11 }); | ||
| const region = process.env.CLI_REGION ?? 'us-west-2'; | ||
| const engine = 'postgres'; | ||
|
|
||
| const databaseController: SqlDatatabaseController = new SqlDatatabaseController( | ||
| [ | ||
| `CREATE TABLE "${getRDSTableNamePrefix()}contact" ("id" INT PRIMARY KEY, "firstname" VARCHAR(20), "lastname" VARCHAR(50), "tags" VARCHAR[], "address" JSON)`, | ||
| ], | ||
| { | ||
| identifier, | ||
| engine, | ||
| username, | ||
| password, | ||
| region, | ||
| }, | ||
| ); | ||
|
|
||
| const strategyName = `${engine}DBStrategy`; | ||
| const resourceNames = getResourceNamesForStrategyName(strategyName); | ||
|
|
||
| beforeAll(async () => { | ||
| await databaseController.setupDatabase(); | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| await databaseController.cleanupDatabase(); | ||
| }); | ||
|
|
||
| const constructTestOptions = (connectionConfigName: string) => ({ | ||
| projFolderName, | ||
| region, | ||
| connectionConfigName, | ||
| dbController: databaseController, | ||
| resourceNames, | ||
| }); | ||
|
|
||
| testGraphQLAPIArrayAndObjects( | ||
| constructTestOptions('connectionUri'), | ||
| 'RDS Postgres Model Directive using Connection String SSM parameter', | ||
| ImportedRDSType.POSTGRESQL, | ||
| ); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { FieldMap } from '../../../utils/sql-crudl-helper'; | ||
|
|
||
| export const contactFieldMap: FieldMap = { | ||
| id: true, | ||
| firstname: true, | ||
| lastname: true, | ||
| tags: true, | ||
| address: { | ||
| city: true, | ||
| state: true, | ||
| street: true, | ||
| zip: true, | ||
| }, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| type Contact @refersTo(name: "e2e_test_contact") @model { | ||
| id: Int! @primaryKey | ||
| firstname: String | ||
| lastname: String | ||
| tags: [String] | ||
| address: ContactAddress | ||
| } | ||
|
|
||
| type ContactAddress { | ||
| city: String! | ||
| state: String! | ||
| street: String! | ||
| zip: String! | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { FieldMap } from '../../../utils/sql-crudl-helper'; | ||
|
|
||
| export const toDoFieldMap: FieldMap = { | ||
| id: true, | ||
| description: true, | ||
| }; | ||
|
|
||
| export const studentFieldMap: FieldMap = { | ||
| studentId: true, | ||
| classId: true, | ||
| firstName: true, | ||
| lastName: true, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| type Todo @model @refersTo(name: "e2e_test_todos") { | ||
| id: ID! @primaryKey | ||
| description: String! | ||
| } | ||
| type Student @model @refersTo(name: "e2e_test_students") { | ||
| studentId: Int! @primaryKey(sortKeyFields: ["classId"]) | ||
| classId: String! | ||
| firstName: String | ||
| lastName: String | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,255 @@ | ||
| import * as path from 'path'; | ||
| import * as fs from 'fs-extra'; | ||
| import { LambdaClient, GetProvisionedConcurrencyConfigCommand } from '@aws-sdk/client-lambda'; | ||
| import { ImportedRDSType } from '@aws-amplify/graphql-transformer-core'; | ||
| import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync'; | ||
| import { createNewProjectDir, deleteProjectDir } from 'amplify-category-api-e2e-core'; | ||
| import { initCDKProject, cdkDeploy, cdkDestroy } from '../commands'; | ||
| import { SqlDatatabaseController } from '../sql-datatabase-controller'; | ||
| import { CRUDLHelper } from '../utils/sql-crudl-helper'; | ||
| import { contactFieldMap } from './schemas/sql-array-objects/field-map'; | ||
| import { ONE_MINUTE } from '../utils/duration-constants'; | ||
|
|
||
| export const testGraphQLAPIArrayAndObjects = ( | ||
| options: { | ||
| projFolderName: string; | ||
| region: string; | ||
| connectionConfigName: string; | ||
| dbController: SqlDatatabaseController; | ||
| resourceNames: { sqlLambdaAliasName: string }; | ||
| }, | ||
| testBlockDescription: string, | ||
| engine: ImportedRDSType, | ||
| ): void => { | ||
| describe(`${testBlockDescription} - ${engine}`, () => { | ||
| let projRoot; | ||
| let region, lambdaFunctionName, lambdaAliasName; | ||
|
|
||
| let dbController: SqlDatatabaseController; | ||
| let contactTableCRUDLHelper: CRUDLHelper; | ||
|
|
||
| beforeAll(async () => { | ||
| ({ | ||
| region, | ||
| dbController, | ||
| resourceNames: { sqlLambdaAliasName: lambdaAliasName }, | ||
| } = options); | ||
| const { projFolderName, connectionConfigName } = options; | ||
|
|
||
| const templatePath = path.resolve(path.join(__dirname, '..', '__tests__', 'backends', 'sql-models')); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now or in the next PR: Can we migrate this test to use the configurable stack so we can (eventually) remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thoughts of using an universal
I could try to utilize the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for your thoughts on this. For now, let's defer any move to configurable-stack, and we can consider a holistic design later. |
||
| const schemaPath = path.resolve(path.join(__dirname, '..', 'sql-tests-common', 'schemas', 'sql-array-objects', 'schema.graphql')); | ||
| const schemaConfigString = fs.readFileSync(schemaPath).toString(); | ||
|
|
||
| projRoot = await createNewProjectDir(projFolderName); | ||
| const name = await initCDKProject(projRoot, templatePath); | ||
| dbController.writeDbDetails(projRoot, connectionConfigName, schemaConfigString); | ||
| const outputs = await cdkDeploy(projRoot, '--all', { postDeployWaitMs: ONE_MINUTE }); | ||
| const { awsAppsyncApiEndpoint: apiEndpoint, awsAppsyncApiKey: apiKey } = outputs[name]; | ||
| lambdaFunctionName = outputs[name].SQLFunctionName; | ||
|
|
||
| const appSyncClient = new AWSAppSyncClient({ | ||
| url: apiEndpoint, | ||
| region, | ||
| disableOffline: true, | ||
| auth: { | ||
| type: AUTH_TYPE.API_KEY, | ||
| apiKey, | ||
| }, | ||
| }); | ||
|
|
||
| contactTableCRUDLHelper = new CRUDLHelper(appSyncClient, 'Contact', 'Contacts', contactFieldMap); | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| try { | ||
| await cdkDestroy(projRoot, '--all'); | ||
| await dbController.clearDatabase(); | ||
| } catch (err) { | ||
| console.log(`Error invoking 'cdk destroy': ${err}`); | ||
| } | ||
|
|
||
| deleteProjectDir(projRoot); | ||
| }); | ||
|
|
||
| test(`check CRUDL on contact table with array and objects - ${engine}`, async () => { | ||
| // Create Contact Mutation | ||
| const contact1 = await contactTableCRUDLHelper.create({ | ||
| id: 1, | ||
| firstname: 'David', | ||
| lastname: 'Smith', | ||
| tags: ['tag1', 'tag2'], | ||
| address: { | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '123 Main St', | ||
| zip: '98115', | ||
| }, | ||
| }); | ||
| const contact2 = await contactTableCRUDLHelper.create({ | ||
| id: 2, | ||
| firstname: 'Chris', | ||
| lastname: 'Sundersingh', | ||
| tags: ['tag3', 'tag4'], | ||
| address: { | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '456 Another St', | ||
| zip: '98119', | ||
| }, | ||
| }); | ||
|
|
||
| expect(contact1).toBeDefined(); | ||
| expect(contact1.id).toEqual(1); | ||
| expect(contact1.firstname).toEqual('David'); | ||
| expect(contact1.lastname).toEqual('Smith'); | ||
| expect(contact1.tags).toEqual(expect.arrayContaining(['tag1', 'tag2'])); | ||
| expect(contact1.address).toEqual( | ||
| expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '123 Main St', | ||
| zip: '98115', | ||
| }), | ||
| ); | ||
|
|
||
| // Get Contact Query | ||
| const getContact1 = await contactTableCRUDLHelper.get({ id: contact1.id }); | ||
|
|
||
| expect(getContact1.id).toEqual(contact1.id); | ||
| expect(getContact1.firstname).toEqual('David'); | ||
| expect(getContact1.lastname).toEqual('Smith'); | ||
| expect(getContact1.tags).toEqual(expect.arrayContaining(['tag1', 'tag2'])); | ||
| expect(getContact1.address).toEqual( | ||
| expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '123 Main St', | ||
| zip: '98115', | ||
| }), | ||
| ); | ||
|
|
||
| // Update Contact Query | ||
| const updateContact1 = await contactTableCRUDLHelper.update({ | ||
| id: contact1.id, | ||
| firstname: 'David', | ||
| lastname: 'Jones', | ||
| tags: ['tag1', 'tag2', 'tag3'], | ||
| address: { | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '12345 Main St', | ||
| zip: '98110', | ||
| }, | ||
| }); | ||
|
|
||
| expect(updateContact1.id).toEqual(contact1.id); | ||
| expect(updateContact1.firstname).toEqual('David'); | ||
| expect(updateContact1.lastname).toEqual('Jones'); | ||
| expect(updateContact1.tags).toEqual(expect.arrayContaining(['tag1', 'tag2', 'tag3'])); | ||
| expect(updateContact1.address).toEqual( | ||
| expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '12345 Main St', | ||
| zip: '98110', | ||
| }), | ||
| ); | ||
|
|
||
| // Get Contact Query after update | ||
| const getUpdatedContact1 = await contactTableCRUDLHelper.get({ id: contact1.id }); | ||
|
|
||
| expect(getUpdatedContact1.id).toEqual(contact1.id); | ||
| expect(getUpdatedContact1.firstname).toEqual('David'); | ||
| expect(getUpdatedContact1.lastname).toEqual('Jones'); | ||
| expect(getUpdatedContact1.tags).toEqual(expect.arrayContaining(['tag1', 'tag2', 'tag3'])); | ||
| expect(getUpdatedContact1.address).toEqual( | ||
| expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '12345 Main St', | ||
| zip: '98110', | ||
| }), | ||
| ); | ||
|
|
||
| // List Contact Query | ||
| const listContact = await contactTableCRUDLHelper.list(); | ||
|
|
||
| expect(listContact.items.length).toEqual(2); | ||
| expect(listContact.items).toEqual( | ||
| expect.arrayContaining([ | ||
| expect.objectContaining({ | ||
| id: contact1.id, | ||
| firstname: 'David', | ||
| lastname: 'Jones', | ||
| tags: expect.arrayContaining(['tag1', 'tag2', 'tag3']), | ||
| address: expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '12345 Main St', | ||
| zip: '98110', | ||
| }), | ||
| }), | ||
| expect.objectContaining({ | ||
| id: contact2.id, | ||
| firstname: 'Chris', | ||
| lastname: 'Sundersingh', | ||
| tags: expect.arrayContaining(['tag3', 'tag4']), | ||
| address: expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '456 Another St', | ||
| zip: '98119', | ||
| }), | ||
| }), | ||
| ]), | ||
| ); | ||
|
|
||
| // Delete Contact Mutation | ||
| const deleteContact1 = await contactTableCRUDLHelper.delete({ id: contact1.id }); | ||
|
|
||
| expect(deleteContact1.id).toEqual(contact1.id); | ||
| expect(deleteContact1.firstname).toEqual('David'); | ||
| expect(deleteContact1.lastname).toEqual('Jones'); | ||
| expect(deleteContact1.tags).toEqual(expect.arrayContaining(['tag1', 'tag2', 'tag3'])); | ||
| expect(deleteContact1.address).toEqual( | ||
| expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '12345 Main St', | ||
| zip: '98110', | ||
| }), | ||
| ); | ||
|
|
||
| // List Contact Query after delete | ||
| const listContactAfterDelete = await contactTableCRUDLHelper.list(); | ||
|
|
||
| expect(listContactAfterDelete.items.length).toEqual(1); | ||
| expect(listContactAfterDelete.items).toEqual( | ||
| expect.arrayContaining([ | ||
| expect.objectContaining({ | ||
| id: contact2.id, | ||
| firstname: 'Chris', | ||
| lastname: 'Sundersingh', | ||
| tags: expect.arrayContaining(['tag3', 'tag4']), | ||
| address: expect.objectContaining({ | ||
| city: 'Seattle', | ||
| state: 'WA', | ||
| street: '456 Another St', | ||
| zip: '98119', | ||
| }), | ||
| }), | ||
| ]), | ||
| ); | ||
| }); | ||
|
|
||
| test(`check SQL Lambda provisioned concurrency - ${engine}`, async () => { | ||
| const client = new LambdaClient({ region }); | ||
| const command = new GetProvisionedConcurrencyConfigCommand({ | ||
| FunctionName: lambdaFunctionName, | ||
| Qualifier: lambdaAliasName, | ||
| }); | ||
| const response = await client.send(command); | ||
| expect(response.RequestedProvisionedConcurrentExecutions).toEqual(2); | ||
| }); | ||
| }); | ||
| }; | ||
Uh oh!
There was an error while loading. Please reload this page.