-
Notifications
You must be signed in to change notification settings - Fork 825
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
feat: templategen command e2e integration tests #13993
Conversation
return commands; | ||
} | ||
|
||
export function getCommandsFromReadme(readmeContent: string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Referencing the comment from the previous PR: #13984 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: give some sample of the readme fie, like the step 1 portion, would be helpful to visualize the file format.
|
||
async function executeStep3(cwd: string, commands: string[], bucketName: string) { | ||
toggleEnvVariable('BUCKET_NAME', 'SET', bucketName); | ||
await executeCommand(commands[1], cwd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Referencing the comment from the previous PR: #13984 (comment)
return stackRefactorId; | ||
} | ||
|
||
async function executeStep1(cwd: string, commands: string[]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the commands[0] and [1] in step1? To make the code self documented, assert that the commands[x] is the command you expected. i.e assert(command[x] has prefix npx amplify....
).
Similarly for step 2 and step 3 pls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These assertions are handled in the unit tests which checks if every command is generated correctly and matches the expected string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, yet I still think we need to add these assertion here for below reasons:
- Self documented code. Otherwise, it is difficult to review, maintain, and extend in the future.
- Easy to identify bugs. Specifically, if some command changes, unit test will adapt in the same CR. However, this e2e may (or may not) fail at random places which would take time to debug.
- Unit test vs e2e serve different purposes, yet may share some assertions. It is best to decouple them and avoid making assumptions. E2e should be from end-user perspective, and it, by itself, should give us confident on the UX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohh, makes sense. Thanks, will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I believe, every step waits for the status to be complete and if the command doesn't get parsed correctly, the test would fail at that specific step which is reflected in the stackStatus. We are waiting for that to be complete and only then move forward, so we would know for sure which specific command failed.
Also, there are definitely some changes in the steps once the other teams resolve the bugs, so every time there is a small change, the e2e tests will every time have to be changed.
Also, if I assert every step having some prefix, won't it defeat the Black Box Testing purpose?
This line asserts the exact command in unit tests -
amplify-cli/packages/amplify-migration-template-gen/src/migration-readme-generator.test.ts
Line 67 in bc4a662
expect(fs.appendFile).toHaveBeenCalledWith( |
|
||
const { gen2ResourceIds, gen2ResourceDetails } = await getGen2ResourceDetails(projRoot, category); | ||
assert.deepEqual(gen1ResourceIds, gen2ResourceIds); | ||
assert.deepEqual(gen1ResourceDetails, gen2ResourceDetails); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add assertion that these gen1ResourceIds no longer exists in gen1 stacks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gen2ResourceIds
are fetched from the Outputs
after the final npx ampx sandbox
which is the final step for stack refactor. I believe the resources can only be present in one stack and CFN doesn't allow it to be in two stacks. So, I think the assertion that gen1ResourceIds no longer exists in gen1 stacks gets handled there since we are making sure the ids are fetched from the outputs and not reusing gen2ResourceIds
. Also, to do this assertion, I would have to make a separate call to get the nested stack name and other call for assertion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fair point!
export async function getGen2ResourceDetails(projRoot: string, category: RefactorCategory) { | ||
if (category === 'auth') { | ||
return await getGen2AuthResourceDetails(projRoot); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: explicitly check for storage
if we ever expand to other categories.
} | ||
|
||
export async function stackRefactor(projRoot: string, category: RefactorCategory, bucketName: string) { | ||
const { gen1ResourceIds, gen1ResourceDetails } = await getGen1ResourceDetails(projRoot, category); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice work on this method. Its clean and readable.
projName = `test${Math.floor(Math.random() * 1000000)}`; | ||
bucketName = `testbucket${Math.floor(Math.random() * 1000000)}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have generateRandomShortId
somewhere in amplify-e2e-core
for this kind of thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out! b28e101
await copyFunctionFile(projRoot, 'function', gen1FunctionName); | ||
await copyGen1Schema(projRoot, projName); | ||
|
||
// TODO: replace below line with correct package version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this comment still relevant ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Irrelevant and removed - b28e101
// TODO: replace below line with correct package version | ||
await updatePackageDependency(projRoot, '@aws-amplify/backend', '0.0.0-test-20241003180022'); | ||
await updatePackageDependency(projRoot, '@aws-amplify/backend'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are todo comments relevant still ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Irrelevant and removed - b28e101
type EnvVariableAction = 'SET' | 'DELETE'; | ||
|
||
export function toggleEnvVariable(name: string, option: EnvVariableAction, value?: string) { | ||
if (option === 'SET') { | ||
process.env[name] = value; | ||
} else if (option === 'DELETE') { | ||
delete process.env[name]; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH. this doesn't seem to be providing lot of simplification over calling process.env
directly. It's just changing syntax of how we set and unset variable without much value added.
If we want to build something that takes care of scope of env vars I'd suggest to do something like this.
function runWithEnvVarialbe(name: string, value: string, callable: ()=> void) => {
process.env[name] = value;
try {
callable();
} finally {
delete process.env[name]
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but I think even this wouldn't quite work, because there are a few steps which involve setting an env var, and then based on those steps running correctly, the stdout of those commands, gives another envvar which need to be set. So, if the case where I had an env var used for specific steps and then other steps use other vars, this would work well. But for this use case, I think simply going with setEnvVariable
and deleteEnvVariable
functions would be simple to read and understand.
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const [gen1ClientIdWeb, gen1ClientId] = gen1ClientIds; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't do this.
If this will be used earlier then this should be added later in follow up PR.
Otherwise if follow up never happens we're left with debt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted. I'll keep this in mind. b28e101
Description of changes
Added e2e integration test for templategen command which runs as a part of the
yarn e2e-migration
commandDescription of how you validated changes
Manually checked and verified the deployed stack resources, assertion statements
Checklist
yarn test
passesBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.