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

feat: templategen command e2e integration tests #13993

Merged
merged 6 commits into from
Oct 29, 2024

Conversation

Sanayshah2
Copy link
Contributor

Description of changes

Added e2e integration test for templategen command which runs as a part of the yarn e2e-migration command

Description of how you validated changes

Manually checked and verified the deployed stack resources, assertion statements

Checklist

  • PR description included
  • yarn test passes
  • Tests are changed or added
  • Relevant documentation is changed or added (and PR referenced)
  • New AWS SDK calls or CloudFormation actions have been added to relevant test and service IAM policies
  • Pull request labels are added

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@Sanayshah2 Sanayshah2 requested a review from a team as a code owner October 23, 2024 21:41
return commands;
}

export function getCommandsFromReadme(readmeContent: string) {
Copy link
Contributor Author

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)

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);
Copy link
Contributor Author

@Sanayshah2 Sanayshah2 Oct 23, 2024

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[]) {

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.

Copy link
Contributor Author

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.

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:

  1. Self documented code. Otherwise, it is difficult to review, maintain, and extend in the future.
  2. 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.
  3. 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.

Copy link
Contributor Author

@Sanayshah2 Sanayshah2 Oct 24, 2024

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.

Copy link
Contributor Author

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 -


const { gen2ResourceIds, gen2ResourceDetails } = await getGen2ResourceDetails(projRoot, category);
assert.deepEqual(gen1ResourceIds, gen2ResourceIds);
assert.deepEqual(gen1ResourceDetails, gen2ResourceDetails);

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.

Copy link
Contributor Author

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.

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 {
Copy link
Contributor

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);
Copy link
Contributor

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.

@Sanayshah2 Sanayshah2 requested a review from sobolk October 25, 2024 19:21
Comment on lines 21 to 22
projName = `test${Math.floor(Math.random() * 1000000)}`;
bucketName = `testbucket${Math.floor(Math.random() * 1000000)}`;
Copy link
Member

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.

Copy link
Contributor Author

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
Copy link
Member

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 ?

Copy link
Contributor Author

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');
Copy link
Member

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 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irrelevant and removed - b28e101

Comment on lines 1 to 9
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];
}
}
Copy link
Member

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]
 }

}

Copy link
Contributor Author

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.

Comment on lines 14 to 15
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [gen1ClientIdWeb, gen1ClientId] = gen1ClientIds;
Copy link
Member

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.

Copy link
Contributor Author

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

@Sanayshah2 Sanayshah2 merged commit 184b085 into aws-amplify:migrations Oct 29, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants