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: adds quality gate for rerunning e2e spec files that are new or have been modified #24556

Open
wants to merge 28 commits into
base: develop
Choose a base branch
from

Conversation

seaona
Copy link
Contributor

@seaona seaona commented May 16, 2024

Description

This PR adds a quality gate for new or modified e2e spec files. Whenever there is a PR which modifies or changes a test, this will be run more times, in order to prevent introducing a flakiness accidentally. It is done as follows:

  • Identifies any new or modified e2e file from inside the test/ folder using git diff and using these 2 filters:
    • file.filename.startsWith('test/e2e/') &&
    • file.filename.endsWith('.spec.js') || file.filename.endsWith('.spec.ts')
  • Copies the given specs x5 times in the list of testpaths to execute -> this number is arbitrary, we could modify it to any value we want. The reason for taking this approach instead of changing the retrial number is to benefit of the parallelization, as @HowardBraham pointed out in a comment.
  • Since we already had a flag which could support the re-running successful tests, --retry-until-failure I just leveraged this into the for loop for each test, and if that testcase was identified as new/modified, the flag is added so the new tests fail fast without retrials

Incremental git fetch depth within shallow clone

We use git fetch with incremental depth as @danjm suggested. The ci environment uses a shallow clone, meaning we won't be able to succeed just by using git diff as it won't find the merge base. For fixing that, we start with a git fetch depth of 5, and keep incrementing the depth it the error is no merge base up until 50. Beyond 50, the job will fail and the PR should Update branch, so we are able to do the git diff successfully. The assumption here is that if the branch is that behind, they would need to update their branch anyway possibly due to conflicts with develop.

Open in GitHub Codespaces

Related issues

Fixes: #24009

Manual testing steps

  1. Check ci runs (notice previous runs had failing and changed tests on purpose, in order to try the different scenarios described below)

Screenshots/Recordings

Git diff with incremental git fetch

Example on how this works: https://app.circleci.com/pipelines/github/MetaMask/metamask-extension/85809/workflows/1d7a4658-1dd9-460f-9fd4-518858982329/jobs/3115301

Screenshot from 2024-06-06 11-20-00

=============================================== [UPDATE with the new code changes]

  • 🟢 Case 1: A test has changed -> it's rerun 1+5 times and it's successful (it will be run in different buckets)

https://app.circleci.com/pipelines/github/MetaMask/metamask-extension/85823/workflows/d5de5e43-48b4-4b98-b2f8-863e7e30e39e/jobs/3116106/parallel-runs/7?filterBy=ALL

  • 🟢 Case 2: A test has changed, but it has a mistake in the code (intentionally to simulate a flaky test) -> it fails immediately and there are no more retries. Also the rest of the tests, are retried if they failed as usual

https://app.circleci.com/pipelines/github/MetaMask/metamask-extension/85823/workflows/d5de5e43-48b4-4b98-b2f8-863e7e30e39e/jobs/3116106/parallel-runs/7?filterBy=ALL

reruns-old-no-reruns-new.mp4
  • 🟢 Case 3: A PR has no test spec files changed -> nothing different happens

Note: since we are using parallelization, this means that the same test new/edit spec can be placed in different buckets, so if it fails, it can fail in different buckets at the same time.

Screenshot from 2024-06-06 12-23-31

Pre-merge author checklist

  • I’ve followed MetaMask Coding Standards.
  • I've completed the PR template to the best of my ability
  • I’ve included tests if applicable
  • I’ve documented my code using JSDoc format if applicable
  • I’ve applied the right labels on the PR (see labeling guidelines). Not required for external contributors.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Copy link
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

test/e2e/run-all.js Outdated Show resolved Hide resolved
@seaona seaona changed the title chore: quality gate mock alt chore: adds quality gate for rerunning e2e spec files that are new or have been modified May 16, 2024
@@ -212,12 +213,26 @@ async function main() {

console.log('My test list:', myTestList);

const changedOrNewTests = await fetchChangedE2eFiles();
console.log('Spec files that will be re-run:', changedOrNewTests);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is left for debugging purposes

Copy link
Contributor

Choose a reason for hiding this comment

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

You're going to sacrifice some parallel execution speed by doing it this way. It also only has to be done if it's running on CircleCI, and not locally.

It would be a better approach if at the top of function runningOnCircleCI(), you looked at testPaths and then duplicated 5 times each thing that was also in changedOrNewTests.

This would allow it to distribute the workload evenly across the VMs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you for your suggestion @HowardBraham That's definetly a good point! I was thinking it would be negligible given the small amount of retries, but it's true that we can benefit from parallelization witha small tweak. I'll add the changes 🙇‍♀️

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changes added 👍

test/e2e/run-all.js Outdated Show resolved Hide resolved
test/e2e/run-all.js Outdated Show resolved Hide resolved
if (retryUntilFailure) {
return null;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

before it assumed that if we reach the max retries, it was an error and throw the error with rejection message 'Retry limit reached', but in the case of using retryUntilFailure, reaching the max retry limit it's actually a good thing, as it means the test has not failed. That's why in this case I'm returning just null

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we rename this parameter stopAfterOneFailure for better clarity?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed 👍

Copy link

codecov bot commented May 21, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 65.70%. Comparing base (0dc77eb) to head (c3dbacf).
Report is 32 commits behind head on develop.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop   #24556   +/-   ##
========================================
  Coverage    65.70%   65.70%           
========================================
  Files         1369     1369           
  Lines        54366    54366           
  Branches     14149    14149           
========================================
  Hits         35718    35718           
  Misses       18648    18648           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@metamaskbot
Copy link
Collaborator

Builds ready [71bbf50]
Page Load Metrics (623 ± 464 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint60133882110
domContentLoaded95417126
load482385623966464
domInteractive95417126
Bundle size diffs
  • background: 0 Bytes (0.00%)
  • ui: 0 Bytes (0.00%)
  • common: 0 Bytes (0.00%)

@seaona seaona marked this pull request as ready for review May 21, 2024 15:08
@seaona seaona requested review from kumavis and a team as code owners May 21, 2024 15:08
@seaona seaona self-assigned this May 21, 2024
DDDDDanica
DDDDDanica previously approved these changes May 21, 2024
vthomas13
vthomas13 previously approved these changes May 21, 2024
@seaona seaona added the DO-NOT-MERGE Pull requests that should not be merged label May 22, 2024
@@ -0,0 +1,33 @@
const axios = require('axios');
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure, but we might be able to avoid a fetch to github here, and instead just use git. Not sure if we have the repo and git history in the right time and place on CI to do it, but it would be good if we could: more efficient than a network request, and not dependent on network conditions or the github api possibly being down.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you Dan! That is a good point. I have an alternative branch where I explored a bit the git ci option, however it was not straight-forward and I believe we might need to tweak some things on the config.yml file in order to accomplish it. I decided to go for this option to not over-engineer it, but for the reason you mention it might be worth to try the ci option a bit further.

https://app.circleci.com/pipelines/github/MetaMask/metamask-extension/80853/workflows/9ac00125-66fc-400d-82ac-3f22b4c928c1/jobs/2859112

Copy link
Contributor

@legobeat legobeat May 23, 2024

Choose a reason for hiding this comment

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

I didn't try but something like this might work?

gitDiff = await git.diffSummary(['--name-only',  `origin/develop...${process.env.CIRCLE_SHA1}`, 'test/**/*.spec.*s']);

https://github.com/MetaMask/metamask-extension/blob/develop/development/generate-rc-commits.js#L2

https://github.com/steveukx/git-js?tab=readme-ov-file#git-diff

Copy link
Contributor

Choose a reason for hiding this comment

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

Does the local git command like that work if you're doing a shallow checkout? Also, the way this is written, it will be hitting the GitHub API hundreds of times per workflow (because there are hundreds of parallel machines running the workflow). Perhaps do it in prep-deps, and then persist_to_workspace?

Copy link
Contributor

@legobeat legobeat May 24, 2024

Choose a reason for hiding this comment

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

Good point on the shallow checkout. Could prob be addressed by a clever enough git fetch invocation (possibly in prep-deps)..? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you for the suggestions 🙏 ❤️ In the shallow clone we do this:

 git clone --depth 1 --no-checkout "$CIRCLE_REPOSITORY_URL" .
 git fetch --depth 1 origin "$CIRCLE_SHA1"  

I was thinking we would need to do git fetch develop explicitly to get available the develop branch commits in the ci environment? 🤔 I'm also not sure if we would need to increase the depth too here 🤔 I can investigate this further

Copy link
Contributor Author

Choose a reason for hiding this comment

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

logic for git fetch with depth and git diff has been added

Comment on lines 229 to 236
const retryIndex = args.indexOf('--retries');
if (retryIndex !== -1) {
args.splice(retryIndex, 2);
}

const extraArgs = isTestChangedOrNew
? ['--retry-until-failure', `--retries=${retriesForChangedOrNewTests}`]
: [];
Copy link
Contributor

Choose a reason for hiding this comment

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

There's no need for this duct-taped workaround complexity. Look at line 191 in this file. Just put retries into extraArgs down here instead of args up there.

Copy link
Contributor

Choose a reason for hiding this comment

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

(if you go with my other suggestion about runningOnCircleCI though, you can probably remove most of this anyway)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you!! if we follow the approach of copying the spec files x5 times on runningOnCircleCI then we can indeed remove all of this logic. Just something I'm wondering, would it be okay then to treat each of those new specs the same as rest (same flags)? or we still want them to fail immediately with no-retries?

Given that @legobeat has a PR for reducing test retries, maybe it's fine to treat all the tests equally; then there's no need to add any extra flag, and just copy the spec file x times in the test list from runningOnCiircleCi, and this would simplify a lot the logic

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ℹ️ retries has been removed and instead we add them in the testpaths x5 times, so we benefit from parallelization.
Now only the argument for failing fast is passed here

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/24787?quickstart=1)

## **Related issues**

Fixes:

## **Manual testing steps**

1. Go to this page...
2.
3.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
@seaona seaona dismissed stale reviews from vthomas13 and DDDDDanica via 1c728ac May 27, 2024 14:13
@seaona seaona requested a review from a team as a code owner May 27, 2024 14:13
echo "$DIFF_RESULT"

# Store the output of git diff
git diff --name-only develop..."$CIRCLE_SHA1" >> changed-files/changed-files.txt
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe this should be a diff with origin/develop? because above there is the code to git fetch origin develop, but those commits are not pulled locally

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you for the suggestion, I tried it but it does not seem to make any difference 🤔

Screenshot from 2024-06-04 11-53-08

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 problem was that the branch was way behind the depth. Updating the branch fixed it

@seaona seaona marked this pull request as draft June 4, 2024 09:38
@seaona seaona removed the DO-NOT-MERGE Pull requests that should not be merged label Jun 6, 2024
@seaona seaona marked this pull request as ready for review June 6, 2024 10:34
}

async function gitDiffWithRetry() {
const depths = [5, 10, 15, 20, 30, 40, 50];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

to consume fewer resources, we start with small depth jumps +5 and later on we increment with +10 jumps

console.error('An error occurred:', error.message);
process.exit(1);
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

leaving all the logs so we are able to debug ci if needed

@metamaskbot
Copy link
Collaborator

Builds ready [c3dbacf]
Page Load Metrics (49 ± 3 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint68937973
domContentLoaded911910
load42654963
domInteractive911910
Bundle size diffs
  • background: 0 Bytes (0.00%)
  • ui: 0 Bytes (0.00%)
  • common: 0 Bytes (0.00%)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Needs dev review
Development

Successfully merging this pull request may close these issues.

Flakiness quality gate for new tests
7 participants