-
Notifications
You must be signed in to change notification settings - Fork 820
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: v1 to v2 graphql migration test package (#8595)
* test: add new v2 schema migrator package * chore: rename package * chore: more renaming * test: use real migrator in test suite
- Loading branch information
1 parent
2cb2f4d
commit 1ba9318
Showing
13 changed files
with
399 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
{ | ||
"name": "amplify-graphql-migration-tests", | ||
"version": "1.0.0", | ||
"description": "Tests migration from v1 to v2 of the Amplify GraphQL transformer", | ||
"main": "lib/index.js", | ||
"private": true, | ||
"scripts": { | ||
"test": "jest" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/aws-amplify/amplify-cli.git", | ||
"directory": "packages/amplify-schema-migrator-tests" | ||
}, | ||
"keywords": [ | ||
"graphql", | ||
"transformer", | ||
"migration", | ||
"test" | ||
], | ||
"author": "Amazon Web Services", | ||
"license": "Apache-2.0", | ||
"jest": { | ||
"collectCoverage": true, | ||
"transform": { | ||
"^.+\\.tsx?$": "ts-jest" | ||
}, | ||
"testURL": "http://localhost", | ||
"testRegex": "((\\.|/)(test|spec))\\.(jsx?|tsx?)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx", | ||
"json", | ||
"node" | ||
] | ||
}, | ||
"devDependencies": { | ||
"@aws-amplify/graphql-auth-transformer": "0.1.0", | ||
"@aws-amplify/graphql-default-value-transformer": "0.2.0", | ||
"@aws-amplify/graphql-function-transformer": "0.4.5", | ||
"@aws-amplify/graphql-http-transformer": "0.5.5", | ||
"@aws-amplify/graphql-index-transformer": "0.4.0", | ||
"@aws-amplify/graphql-model-transformer": "0.6.4", | ||
"@aws-amplify/graphql-predictions-transformer": "0.3.5", | ||
"@aws-amplify/graphql-relational-transformer": "0.3.1", | ||
"@aws-amplify/graphql-searchable-transformer": "0.6.3", | ||
"@aws-amplify/graphql-transformer-core": "0.9.2", | ||
"@aws-amplify/graphql-transformer-interfaces": "1.10.0", | ||
"@aws-amplify/graphql-transformer-migrator": "0.1.0", | ||
"@aws-cdk/cloudformation-diff": "~1.124.0", | ||
"amplify-prompts":"1.2.0", | ||
"fs-extra": "^8.1.0", | ||
"graphql-auth-transformer": "6.24.26", | ||
"graphql-connection-transformer": "4.21.25", | ||
"graphql-dynamodb-transformer": "6.22.25", | ||
"graphql-elasticsearch-transformer": "4.12.5", | ||
"graphql-function-transformer": "2.5.24", | ||
"graphql-http-transformer": "4.18.12", | ||
"graphql-key-transformer": "2.23.25", | ||
"graphql-predictions-transformer": "2.5.24", | ||
"graphql-transformer-core": "6.30.2", | ||
"graphql-versioned-transformer": "4.17.25" | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
packages/amplify-graphql-migration-tests/src/__tests__/graphql-version-migration.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { getTestCaseRegistry } from '../test-case-registry'; | ||
import { v1transformerProvider } from '../v1-transformer-provider'; | ||
import { v2transformerProvider } from '../v2-transformer-provider'; | ||
import { migrateSchema } from '../migrate-schema-wrapper'; | ||
import { getNestedStackDiffRules } from '../nested-stack-diff-rules'; | ||
import * as cdkDiff from '@aws-cdk/cloudformation-diff'; | ||
import { ResourceImpact } from '@aws-cdk/cloudformation-diff'; | ||
|
||
describe('v1 to v2 migration', () => { | ||
test.concurrent.each(getTestCaseRegistry())( | ||
`validate $name schema migration`, | ||
async ({ name, schema, v1TransformerConfig, v2TransformerConfig }) => { | ||
console.log(name); // for some reason name substitution isn't working in the test title, so printing it here | ||
// run v1 transformer | ||
const v1Transformer = v1transformerProvider(v1TransformerConfig); | ||
const v1result = v1Transformer.transform(schema); | ||
|
||
// migrate schema from v1 to v2 | ||
const migratedSchema = await migrateSchema(schema); | ||
|
||
// run v2 transformer | ||
const v2transformer = v2transformerProvider(v2TransformerConfig); | ||
const v2result = v2transformer.transform(migratedSchema); | ||
|
||
// get initial nested stack names | ||
// TODO will probably have to update the logic a bit if we want to test @searchable migrations here as that will create a SearchableStack that we need to account for | ||
const v1nestedStackNames = Object.keys(v1result.stacks).filter(stackName => stackName !== 'ConnectionStack'); // The v1 transformer puts all connection resolvers in a 'ConnectionStack'. This stack does not defined any data resources | ||
|
||
// verify root stack diff | ||
const diff = cdkDiff.diffTemplate(v1result.rootStack, v2result.rootStack); | ||
v1nestedStackNames.forEach(stackName => { | ||
expect([ResourceImpact.WILL_UPDATE, ResourceImpact.NO_CHANGE]).toContain(diff.resources.changes[stackName].changeImpact); | ||
}); | ||
|
||
// verify nested stack diffs | ||
const nestedStackDiffRules = getNestedStackDiffRules(); | ||
v1nestedStackNames.forEach(stackName => { | ||
const nestedStackDiff = cdkDiff.diffTemplate(v1result.stacks[stackName], v2result.stacks[stackName]); | ||
nestedStackDiffRules.forEach(rule => rule(stackName, nestedStackDiff)); | ||
}); | ||
}, | ||
); | ||
}); |
6 changes: 6 additions & 0 deletions
6
packages/amplify-graphql-migration-tests/src/feature-flag-stub.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export const featureFlagProviderStub = { | ||
getBoolean: () => true, | ||
getString: () => '', | ||
getNumber: () => 0, | ||
getObject: () => ({}), | ||
}; |
20 changes: 20 additions & 0 deletions
20
packages/amplify-graphql-migration-tests/src/migrate-schema-wrapper.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { runMigration } from '@aws-amplify/graphql-transformer-migrator'; | ||
import * as fs from 'fs-extra'; | ||
import { prompter } from 'amplify-prompts'; | ||
|
||
jest.mock('fs-extra'); | ||
jest.mock('amplify-prompts'); | ||
|
||
const fs_mock = fs as jest.Mocked<typeof fs>; | ||
const prompter_mock = prompter as jest.Mocked<typeof prompter>; | ||
|
||
export type AuthMode = 'apiKey' | 'iam' | 'userPools' | 'oidc'; | ||
|
||
export const migrateSchema = async (schema: string, authMode: AuthMode = 'apiKey'): Promise<string> => { | ||
fs_mock.writeFile.mockClear(); | ||
prompter_mock.pick.mockResolvedValue('Yes'); | ||
await runMigration([{ schema, filePath: 'testPath' }], authMode); | ||
const transformedSchema = fs_mock.writeFile.mock.calls[0][1]; | ||
expect(typeof transformedSchema).toBe('string'); | ||
return transformedSchema; | ||
}; |
60 changes: 60 additions & 0 deletions
60
packages/amplify-graphql-migration-tests/src/nested-stack-diff-rules.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { ResourceImpact, TemplateDiff } from '@aws-cdk/cloudformation-diff'; | ||
|
||
export const getNestedStackDiffRules = (): NestedStackDiffRule[] => [ | ||
onlyUpdatesTableNameProperty, | ||
tableNameResolvesToSameName, | ||
dataSourceLogicalIdsAreSame, | ||
]; | ||
|
||
/** | ||
* The table name is not actually updated but the way it's defined is changed (tableNameResolvesToSameName will check the table name) | ||
* This check asserts that no other table properties were changed by the migration (GSIs, LSIs, etc) | ||
* @param stackName The name of the nested stack | ||
* @param diff The diff of the nested stack | ||
*/ | ||
const onlyUpdatesTableNameProperty = (stackName: string, diff: TemplateDiff) => { | ||
const propertyUpdates = diff.resources.changes[`${stackName}Table`].propertyUpdates; | ||
try { | ||
expect(Object.keys(propertyUpdates)).toEqual(['TableName']); // The table name should resolve to the same value but the way it's defined is different so it shows up here as a diff | ||
} catch (err) { | ||
console.error(`Expected only TableName update for table ${stackName}Table. Instead got updates:`); | ||
console.log(JSON.stringify(propertyUpdates, undefined, 2)); | ||
throw err; | ||
} | ||
}; | ||
|
||
const tableNameResolvesToSameName = (stackName: string, diff: TemplateDiff) => { | ||
const propertyUpdates = diff.resources.changes[`${stackName}Table`].propertyUpdates; | ||
const newTableName = propertyUpdates.TableName.newValue; | ||
expect(newTableName['Fn::Join']).toBeDefined(); | ||
const joinParams = newTableName['Fn::Join']; | ||
const joinStr = joinParams[0] as string; | ||
const joinElements = joinParams[1] as any[]; | ||
|
||
const apiId = 'testApiId'; | ||
const env = 'testEnv'; | ||
|
||
const replacedElements = joinElements.map(el => { | ||
if (typeof el?.Ref === 'string') { | ||
if (el.Ref.startsWith('referencetotransformerrootstackGraphQLAPI')) { | ||
return apiId; | ||
} | ||
if (el.Ref.startsWith('referencetotransformerrootstackenv')) { | ||
return env; | ||
} | ||
} | ||
return el; | ||
}); | ||
const finalTableName = replacedElements.join(joinStr); | ||
expect(finalTableName).toEqual(`${stackName}-${apiId}-${env}`); | ||
}; | ||
|
||
const dataSourceLogicalIdsAreSame = (_: string, diff: TemplateDiff) => { | ||
const areDataSourcesReplaced = Object.values(diff.resources.changes) | ||
.filter(diff => diff.resourceType === 'AWS::AppSync::DataSource') | ||
.map(diff => diff.changeImpact === ResourceImpact.WILL_REPLACE) | ||
.reduce((acc, it) => acc && it, true); | ||
expect(areDataSourcesReplaced).toBe(true); | ||
}; | ||
|
||
export type NestedStackDiffRule = (stackName: string, diff: TemplateDiff) => void; |
46 changes: 46 additions & 0 deletions
46
packages/amplify-graphql-migration-tests/src/test-case-registry.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { TestEntry } from './test-case-types'; | ||
|
||
/** | ||
* REGISTER TEST CASES HERE | ||
*/ | ||
export const getTestCaseRegistry = (): TestEntry[] => [ | ||
{ | ||
name: 'basic bi-di has-one and has-many connection', | ||
schema: basicBiDiRelationSchema, | ||
}, | ||
/* | ||
{ | ||
name: 'add additional tests with a descriptive name', | ||
schema: schemaName // define the schema below and reference it here. If the schema is exceptionally large, consider importing it from another file | ||
v1TransformerConfig: // if the tests needs custom v1 transformer config, include it here (the framework currently has limited support for additional config so you may need to make updates) | ||
v2TransformerConfig: // same for v2 transformer | ||
} | ||
*/ | ||
]; | ||
|
||
/* | ||
DEFINE TEST SCHEMAS BELOW | ||
*/ | ||
|
||
const basicBiDiRelationSchema = /* GraphQL */ ` | ||
type Blog @model { | ||
id: ID! | ||
name: String! | ||
postID: ID | ||
post: Post @connection(fields: ["postID"]) | ||
} | ||
type Post @model { | ||
id: ID! | ||
title: String! | ||
blogID: ID! | ||
blog: Blog @connection(fields: ["blogID"]) | ||
comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) | ||
} | ||
type Comment @model @key(name: "byPost", fields: ["postID"]) { | ||
id: ID! | ||
postID: ID! | ||
post: Post @connection(fields: ["postID"]) | ||
} | ||
`; |
20 changes: 20 additions & 0 deletions
20
packages/amplify-graphql-migration-tests/src/test-case-types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { TransformerPluginProvider } from '@aws-amplify/graphql-transformer-interfaces'; | ||
import { ITransformer } from 'graphql-transformer-core'; | ||
|
||
// Defines a single test input | ||
export type TestEntry = { | ||
name: string; | ||
schema: string; | ||
v1TransformerConfig?: Partial<V1TransformerTestConfig>; | ||
v2TransformerConfig?: Partial<V2TransformerTestConfig>; | ||
}; | ||
|
||
// If we need to vary other transformer config per test we can add additional parameters here | ||
export type V1TransformerTestConfig = { | ||
transformers: ITransformer[]; | ||
}; | ||
|
||
// If we need to vary other transformer config per test we can add additional parameters here | ||
export type V2TransformerTestConfig = { | ||
transformers: TransformerPluginProvider[]; | ||
}; |
30 changes: 30 additions & 0 deletions
30
packages/amplify-graphql-migration-tests/src/v1-transformer-provider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer'; | ||
import { ModelConnectionTransformer } from 'graphql-connection-transformer'; | ||
import { VersionedModelTransformer } from 'graphql-versioned-transformer'; | ||
import { HttpTransformer } from 'graphql-http-transformer'; | ||
import { KeyTransformer } from 'graphql-key-transformer'; | ||
import { GraphQLTransform } from 'graphql-transformer-core'; | ||
import { featureFlagProviderStub } from './feature-flag-stub'; | ||
import { V1TransformerTestConfig } from './test-case-types'; | ||
|
||
const defaultConfig: V1TransformerTestConfig = { | ||
transformers: [ | ||
new DynamoDBModelTransformer(), | ||
new VersionedModelTransformer(), | ||
new HttpTransformer(), | ||
new KeyTransformer(), | ||
new ModelConnectionTransformer(), | ||
], | ||
}; | ||
|
||
export const v1transformerProvider = (config: Partial<V1TransformerTestConfig> = {}): GraphQLTransform => { | ||
const subbedConfig: V1TransformerTestConfig = { ...defaultConfig, ...config }; | ||
|
||
return new GraphQLTransform({ | ||
transformers: subbedConfig.transformers, | ||
transformConfig: { | ||
Version: 5, | ||
}, | ||
featureFlags: featureFlagProviderStub, | ||
}); | ||
}; |
57 changes: 57 additions & 0 deletions
57
packages/amplify-graphql-migration-tests/src/v2-transformer-provider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { GraphQLTransform } from '@aws-amplify/graphql-transformer-core'; | ||
import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; | ||
import { AuthTransformer } from '@aws-amplify/graphql-auth-transformer'; | ||
import { FunctionTransformer } from '@aws-amplify/graphql-function-transformer'; | ||
import { HttpTransformer } from '@aws-amplify/graphql-http-transformer'; | ||
import { IndexTransformer, PrimaryKeyTransformer } from '@aws-amplify/graphql-index-transformer'; | ||
import { | ||
BelongsToTransformer, | ||
HasManyTransformer, | ||
HasOneTransformer, | ||
ManyToManyTransformer, | ||
} from '@aws-amplify/graphql-relational-transformer'; | ||
import { DefaultValueTransformer } from '@aws-amplify/graphql-default-value-transformer'; | ||
import { TransformerPluginProvider, AppSyncAuthConfiguration } from '@aws-amplify/graphql-transformer-interfaces'; | ||
import { featureFlagProviderStub } from './feature-flag-stub'; | ||
import { V2TransformerTestConfig } from './test-case-types'; | ||
|
||
export const v2transformerProvider = (config: Partial<V2TransformerTestConfig> = {}): GraphQLTransform => { | ||
const transform = new GraphQLTransform({ | ||
transformers: config.transformers ?? getDefaultTransformers(), | ||
authConfig: defaultAuthConfig, | ||
featureFlags: featureFlagProviderStub, | ||
sandboxModeEnabled: true, | ||
}); | ||
|
||
return transform; | ||
}; | ||
|
||
const getDefaultTransformers = () => { | ||
const modelTransformer = new ModelTransformer(); | ||
const indexTransformer = new IndexTransformer(); | ||
const hasOneTransformer = new HasOneTransformer(); | ||
|
||
const authTransformer = new AuthTransformer(); | ||
const transformers: TransformerPluginProvider[] = [ | ||
modelTransformer, | ||
new FunctionTransformer(), | ||
new HttpTransformer(), | ||
new PrimaryKeyTransformer(), | ||
indexTransformer, | ||
new BelongsToTransformer(), | ||
new HasManyTransformer(), | ||
hasOneTransformer, | ||
new ManyToManyTransformer(modelTransformer, indexTransformer, hasOneTransformer, authTransformer), | ||
new DefaultValueTransformer(), | ||
authTransformer, | ||
]; | ||
|
||
return transformers; | ||
}; | ||
|
||
const defaultAuthConfig: AppSyncAuthConfiguration = { | ||
defaultAuthentication: { | ||
authenticationType: 'API_KEY', | ||
}, | ||
additionalAuthenticationProviders: [], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"extends": "../../tsconfig.base.json", | ||
"compilerOptions": { | ||
"outDir": "./lib", | ||
"rootDir": "./src", | ||
}, | ||
"references": [ | ||
{"path": "../amplify-function-plugin-interface"}, | ||
{"path": "../graphql-transformer-core"}, | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
export { attemptV2TransformerMigration } from './schema-migrator'; | ||
export { attemptV2TransformerMigration, runMigration } from './schema-migrator'; |
Oops, something went wrong.