Skip to content
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

chore: fix some long running E2E tests #2508

Merged
merged 2 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
830 changes: 443 additions & 387 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 @@ -7,6 +7,7 @@ export const DURATION_20_MINUTES = 20 * ONE_MINUTE;
export const DURATION_30_MINUTES = 30 * ONE_MINUTE;
export const DURATION_45_MINUTES = 45 * ONE_MINUTE;
export const DURATION_1_HOUR = 60 * ONE_MINUTE;
export const DURATION_90_MINUTES = 90 * ONE_MINUTE;

export const COUNT_1_THOUSAND = 1000;
export const COUNT_10_THOUSAND = 10000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { createNewProjectDir, deleteProjectDir } from 'amplify-category-api-e2e-
import { AmplifyGraphqlApi } from '@aws-amplify/graphql-api-construct';
import { initCDKProject, cdkDeploy, cdkDestroy } from '../../commands';
import { ValidateGraphqlOptions, validateGraphql } from '../../graphql-request';
import { DURATION_1_HOUR } from './deploy-velocity-constants';
import { DURATION_90_MINUTES } from './deploy-velocity-constants';

jest.setTimeout(DURATION_1_HOUR);
jest.setTimeout(DURATION_90_MINUTES);

export type EndpointConfig = Pick<ValidateGraphqlOptions, 'apiEndpoint' | 'apiKey'>;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
COUNT_100_THOUSAND,
DURATION_30_MINUTES,
DURATION_45_MINUTES,
MUTATION_FOUR_FIELD_CREATE,
SCHEMA_FOUR_FIELDS_FINAL_TWO_INDEXED,
SCHEMA_FOUR_FIELDS_INITIAL_TWO_INDEXED,
Expand All @@ -9,7 +9,7 @@ import { recordCountDataProvider, recordCountDataValidator, testManagedTableDepl

testManagedTableDeployment({
name: 'Replace 2 GSIs updated - 100k Records',
maxDeployDurationMs: DURATION_30_MINUTES,
maxDeployDurationMs: DURATION_45_MINUTES,
initialSchema: SCHEMA_FOUR_FIELDS_INITIAL_TWO_INDEXED,
updatedSchema: SCHEMA_FOUR_FIELDS_FINAL_TWO_INDEXED,
dataSetup: recordCountDataProvider(COUNT_100_THOUSAND, MUTATION_FOUR_FIELD_CREATE),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/* eslint-disable import/namespace */
import { DDB_AMPLIFY_MANAGED_DATASOURCE_STRATEGY } from '@aws-amplify/graphql-transformer-core';
import { createNewProjectDir, deleteProjectDir } from 'amplify-category-api-e2e-core';
import * as fs from 'fs-extra';
import * as generator from 'generate-password';
import * as path from 'path';
import { cdkDeploy, cdkDestroy, initCDKProject } from '../../../commands';
import { SqlDatabaseDetails, SqlDatatabaseController } from '../../../sql-datatabase-controller';
import { TestDefinition, dbDetailsToModelDataSourceStrategy, writeStackPrefix, writeTestDefinitions } from '../../../utils';
import {
testPrimaryContainsAssociated,
testPrimaryCpkSkOneContainsAssociated,
testPrimaryCpkSkTwoContainAssociated,
testPrimaryMultipleHasOneContainsOneHasOne,
testRelatedManyContainsAssociated,
testRelatedManyCpkSkOneContainsAssociated,
testRelatedManypkSkTwoContainsAssociated,
testRelatedOneContainsAssociated,
testRelatedOneCpkSkOneContainsAssociated,
testRelatedOneCpkSkTwoContainsAssociated,
} from './test-implementations';

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

describe('References relationships', () => {
const region = process.env.CLI_REGION ?? 'us-west-2';
const baseProjFolderName = path.basename(__filename, '.test.ts');

describe('DDB Primary, DDB Related', () => {
const projFolderName = `${baseProjFolderName}-ddb-primary-ddb-related`;
let apiEndpoint: string;
let apiKey: string;
let projRoot: string;
let currentId: number;

beforeEach(() => {
currentId = Date.now();
});

beforeAll(async () => {
projRoot = await createNewProjectDir(projFolderName);
const templatePath = path.resolve(path.join(__dirname, '..', '..', 'backends', 'configurable-sandbox-stack'));
const name = await initCDKProject(projRoot, templatePath);

const primarySchemaPath = path.resolve(path.join(__dirname, 'graphql', 'schema-primary.graphql'));
const primarySchema = fs.readFileSync(primarySchemaPath).toString();

const relatedSchemaPath = path.resolve(path.join(__dirname, 'graphql', 'schema-related.graphql'));
const relatedSchema = fs.readFileSync(relatedSchemaPath).toString();

const primarySchemaOneSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-primary-cpk-1sk.graphql'));
const primarySchemaOneSk = fs.readFileSync(primarySchemaOneSkPath).toString();

const relatedSchemaOneSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-related-cpk-1sk.graphql'));
const relatedSchemaOneSk = fs.readFileSync(relatedSchemaOneSkPath).toString();

const primarySchemaTwoSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-primary-cpk-2sk.graphql'));
const primarySchemaTwoSk = fs.readFileSync(primarySchemaTwoSkPath).toString();

const relatedSchemaTwoSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-related-cpk-2sk.graphql'));
const relatedSchemaTwoSk = fs.readFileSync(relatedSchemaTwoSkPath).toString();

const testDefinitions: Record<string, TestDefinition> = {
'ddb-primary-ddb-related': {
schema: [primarySchema, relatedSchema, primarySchemaOneSk, relatedSchemaOneSk, primarySchemaTwoSk, relatedSchemaTwoSk].join('\n'),
strategy: DDB_AMPLIFY_MANAGED_DATASOURCE_STRATEGY,
},
};

writeStackPrefix('RefDdbDdb', projRoot);
writeTestDefinitions(testDefinitions, projRoot);

const outputs = await cdkDeploy(projRoot, '--all');
apiEndpoint = outputs[name].awsAppsyncApiEndpoint;
apiKey = outputs[name].awsAppsyncApiKey;
});

afterAll(async () => {
try {
await cdkDestroy(projRoot, '--all');
} catch (err) {
console.log(`Error invoking 'cdk destroy': ${err}`);
}

deleteProjectDir(projRoot);
});

describe('Primary as source', () => {
test('Associated models included in query and mutation response with single primary key', async () => {
await testPrimaryContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with one sort key', async () => {
await testPrimaryCpkSkOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with two sort keys', async () => {
await testPrimaryCpkSkTwoContainAssociated(currentId, apiEndpoint, apiKey);
});

test('Multiple RelatedOne associated records returns one RelatedOne record', async () => {
await testPrimaryMultipleHasOneContainsOneHasOne(currentId, apiEndpoint, apiKey);
});
});

describe('RelatedOne as source', () => {
test('Associated models included in query and mutation response with single primary key', async () => {
await testRelatedOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with one sort key', async () => {
await testRelatedOneCpkSkOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with two sort keys', async () => {
await testRelatedOneCpkSkTwoContainsAssociated(currentId, apiEndpoint, apiKey);
});
});

describe('RelatedMany as source', () => {
test('Associated models included in query and mutation response with single primary key', async () => {
await testRelatedManyContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with one sort key', async () => {
await testRelatedManyCpkSkOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with two sort keys', async () => {
await testRelatedManypkSkTwoContainsAssociated(currentId, apiEndpoint, apiKey);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/* eslint-disable import/namespace */
import { DDB_AMPLIFY_MANAGED_DATASOURCE_STRATEGY } from '@aws-amplify/graphql-transformer-core';
import { createNewProjectDir, deleteProjectDir } from 'amplify-category-api-e2e-core';
import * as fs from 'fs-extra';
import * as generator from 'generate-password';
import * as path from 'path';
import { cdkDeploy, cdkDestroy, initCDKProject } from '../../../commands';
import { SqlDatabaseDetails, SqlDatatabaseController } from '../../../sql-datatabase-controller';
import { TestDefinition, dbDetailsToModelDataSourceStrategy, writeStackPrefix, writeTestDefinitions } from '../../../utils';
import {
testPrimaryContainsAssociated,
testPrimaryCpkSkOneContainsAssociated,
testPrimaryCpkSkTwoContainAssociated,
testPrimaryMultipleHasOneContainsOneHasOne,
testRelatedManyContainsAssociated,
testRelatedManyCpkSkOneContainsAssociated,
testRelatedManypkSkTwoContainsAssociated,
testRelatedOneContainsAssociated,
testRelatedOneCpkSkOneContainsAssociated,
testRelatedOneCpkSkTwoContainsAssociated,
} from './test-implementations';

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

describe('References relationships', () => {
const region = process.env.CLI_REGION ?? 'us-west-2';
const baseProjFolderName = path.basename(__filename, '.test.ts');

const [dbUsername, dbIdentifier] = generator.generateMultiple(2);
const dbname = 'default_db';
let dbDetails: SqlDatabaseDetails;

// Note that the SQL database is created with slightly non-standard naming conventions, to avoid us having to use `refersTo` in the schema
// snippets. That allows us to reuse the same snippets across both DDB and SQL data sources, simplifying the test fixture data.
const databaseController = new SqlDatatabaseController(
[
'drop table if exists `RelatedMany`;',
'drop table if exists `RelatedOne`;',
'drop table if exists `Primary`;',

// Single primary key
'create table `Primary` ( id varchar(64) primary key not null );',

'create table `RelatedMany`( id varchar(64) primary key not null, `primaryId` varchar(64));',
'create index `RelatedMany_primaryId` on `RelatedMany`(`primaryId`);',

'create table `RelatedOne`( id varchar(64) primary key not null, `primaryId` varchar(64));',
'create index `RelatedOne_primaryId` on `RelatedOne`(`primaryId`);',

// Two primary keys
'create table `PrimaryCPKSKOne` ( id varchar(64) not null, skOne varchar(64) not null, PRIMARY KEY (`id`, `skOne`) );',

'create table `RelatedManyCPKSKOne`( id varchar(64) primary key not null, `primaryId` varchar(64), `primarySkOne` varchar(64) );',
'create index `RelatedManyCPKSKOne_primaryId_skOne` on `RelatedManyCPKSKOne`(`primaryId`, `primarySkOne`);',

'create table `RelatedOneCPKSKOne`( id varchar(64) primary key not null, `primaryId` varchar(64), `primarySkOne` varchar(64) );',
'create index `RelatedOnCPKSKOne_primaryId_skOne` on `RelatedOneCPKSKOne`(`primaryId`, `primarySkOne`);',

// Three primary keys
'create table `PrimaryCPKSKTwo` ( id varchar(64) not null, skOne varchar(64) not null, skTwo varchar(64) not null, PRIMARY KEY (`id`, `skOne`, `skTwo`) );',

'create table `RelatedManyCPKSKTwo`( id varchar(64) primary key not null, `primaryId` varchar(64), `primarySkOne` varchar(64), `primarySkTwo` varchar(64) );',
'create index `RelatedManyCPKSKTwo` on `RelatedManyCPKSKTwo`(`primaryId`, `primarySkOne`, `primarySkTwo`);',

'create table `RelatedOneCPKSKTwo`( id varchar(64) primary key not null, `primaryId` varchar(64), `primarySkOne` varchar(64), `primarySkTwo` varchar(64) );',
'create index `RelatedOnCPKSKTwo_primaryId_skOne` on `RelatedOneCPKSKTwo`(`primaryId`, `primarySkOne`, `primarySkTwo`);',
],
{
identifier: dbIdentifier,
engine: 'mysql',
dbname,
username: dbUsername,
region,
},
);

beforeAll(async () => {
dbDetails = await databaseController.setupDatabase();
});

afterAll(async () => {
await databaseController.cleanupDatabase();
});

describe('DDB Primary, SQL Related', () => {
const projFolderName = `${baseProjFolderName}-ddb-primary-sql-related`;
let apiEndpoint: string;
let apiKey: string;
let projRoot: string;
let currentId: number;

beforeEach(() => {
currentId = Date.now();
});

beforeAll(async () => {
projRoot = await createNewProjectDir(projFolderName);
const templatePath = path.resolve(path.join(__dirname, '..', '..', 'backends', 'configurable-sandbox-stack'));
const name = await initCDKProject(projRoot, templatePath);

const primarySchemaPath = path.resolve(path.join(__dirname, 'graphql', 'schema-primary.graphql'));
const primarySchema = fs.readFileSync(primarySchemaPath).toString();

const relatedSchemaPath = path.resolve(path.join(__dirname, 'graphql', 'schema-related.graphql'));
const relatedSchema = fs.readFileSync(relatedSchemaPath).toString();

const primarySchemaOneSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-primary-cpk-1sk.graphql'));
const primarySchemaOneSk = fs.readFileSync(primarySchemaOneSkPath).toString();

const relatedSchemaOneSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-related-cpk-1sk.graphql'));
const relatedSchemaOneSk = fs.readFileSync(relatedSchemaOneSkPath).toString();

const primarySchemaTwoSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-primary-cpk-2sk.graphql'));
const primarySchemaTwoSk = fs.readFileSync(primarySchemaTwoSkPath).toString();

const relatedSchemaTwoSkPath = path.resolve(path.join(__dirname, 'graphql', 'schema-related-cpk-2sk.graphql'));
const relatedSchemaTwoSk = fs.readFileSync(relatedSchemaTwoSkPath).toString();

const testDefinitions: Record<string, TestDefinition> = {
'ddb-primary': {
schema: [primarySchema, primarySchemaOneSk, primarySchemaTwoSk].join('\n'),
strategy: DDB_AMPLIFY_MANAGED_DATASOURCE_STRATEGY,
},
'sql-related': {
schema: [relatedSchema, relatedSchemaOneSk, relatedSchemaTwoSk].join('\n'),
strategy: dbDetailsToModelDataSourceStrategy(dbDetails, 'sqlrelated', 'MYSQL', 'secretsManagerManagedSecret'),
},
};

writeStackPrefix('RefSqlDdb', projRoot);
writeTestDefinitions(testDefinitions, projRoot);

const outputs = await cdkDeploy(projRoot, '--all');
apiEndpoint = outputs[name].awsAppsyncApiEndpoint;
apiKey = outputs[name].awsAppsyncApiKey;
});

afterAll(async () => {
try {
await cdkDestroy(projRoot, '--all');
} catch (err) {
console.log(`Error invoking 'cdk destroy': ${err}`);
}

deleteProjectDir(projRoot);
});

describe('Primary as source', () => {
test('Associated models included in query and mutation response with single primary key', async () => {
await testPrimaryContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with one sort key', async () => {
await testPrimaryCpkSkOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with two sort keys', async () => {
await testPrimaryCpkSkTwoContainAssociated(currentId, apiEndpoint, apiKey);
});

test('Multiple RelatedOne associated records returns one RelatedOne record', async () => {
await testPrimaryMultipleHasOneContainsOneHasOne(currentId, apiEndpoint, apiKey);
});
});

describe('RelatedOne as source', () => {
test('Associated models included in query and mutation response with single primary key', async () => {
await testRelatedOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with one sort key', async () => {
await testRelatedOneCpkSkOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with two sort keys', async () => {
await testRelatedOneCpkSkTwoContainsAssociated(currentId, apiEndpoint, apiKey);
});
});

describe('RelatedMany as source', () => {
test('Associated models included in query and mutation response with single primary key', async () => {
await testRelatedManyContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with one sort key', async () => {
await testRelatedManyCpkSkOneContainsAssociated(currentId, apiEndpoint, apiKey);
});

test('Associated models included in query and mutation response with two sort keys', async () => {
await testRelatedManypkSkTwoContainsAssociated(currentId, apiEndpoint, apiKey);
});
});
});
});
Loading
Loading