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(e2e): enable e2e tests to run directly against Atlas #6381

Merged
merged 7 commits into from
Oct 22, 2024

Conversation

syn-zhu
Copy link
Contributor

@syn-zhu syn-zhu commented Oct 18, 2024

Description

https://jira.mongodb.org/browse/CLOUDP-274595

Enable running compass E2E tests directly against a deployed Atlas environment.

Additionally, enable specifying a test filter as env var to support only running a subset of tests.

Example usage:

export CONNECTION_STRING_1='mongodb+srv://<username>:<password>@connection-1.dkur9.mongodb-dev.net/?retryWrites=true&w=majority&appName=connection-1'
export CONNECTION_NAME_1=connection-1
export CONNECTION_STRING_2='mongodb+srv://<username>:<password>@connection-2.dkur9.mongodb-dev.net/?retryWrites=true&w=majority&appName=connection-2'
export CONNECTION_NAME_2=connection-2
export ATLAS_DOMAIN=cloud-dev.mongodb.com
export ATLAS_GROUP_ID=66ce1716209aca269796919b
export COOKIES_FILE=/Users/siyanzhu/compass/packages/compass-e2e-tests/cloud-dev.mongodb.com_cookies.json
export E2E_TEST_FILTER=collection-rename

npm run test-web  

^This would run the collection-rename test against cloud-dev, for group 66ce1716209aca269796919b.

The current implementation assumes that the actual clusters have already been created beforehand. Later on, we will do this step using the MMS e2e utilities.

Currently, the collection-rename test has been tried and is working. Will do each of the remaining tests incrementally, and make any additional changes along the way.

Checklist

Motivation and Context

  • Bugfix
  • New feature
  • Dependency update
  • Misc

Open Questions

Dependents

Types of changes

  • Backport Needed
  • Patch (non-breaking change which fixes an issue)
  • Minor (non-breaking change which adds functionality)
  • Major (fix or feature that would cause existing functionality to change)

Comment on lines 800 to 806
const cookiesFile = process.env.COOKIES_FILE;
if (!cookiesFile) {
throw new Error(
'ATLAS_DOMAIN is set but COOKIES_FILE is not. Please set COOKIES_FILE to the path of the cookies file.'
);
}
const cookies = JSON.parse(await fs.readFile(cookiesFile, 'utf8'));
Copy link
Contributor Author

@syn-zhu syn-zhu Oct 18, 2024

Choose a reason for hiding this comment

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

Eventually, the plan is to package npm run test-web as a container image, which can be pulled in MMS e2e task.

MMS already has a bunch of utilities for e2e test setup, in particular:

  • Creating a new randomly generated test user
  • logging in as that user
  • Creating a new group
  • Creating new clusters in that group

Thus, we don't need to reimplement all of those here. Instead, we can do those setup steps first, and then just save the cookies that are needed for authentication.

Then, when we run the compass e2e test container, we just pass in the cookies, the group, and the names of the created clusters.

Comment on lines 810 to 812
cookie.name.includes('mmsa-') ||
cookie.name.includes('mdb-sat') ||
cookie.name.includes('mdb-srt')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we add this link as a comment here so that we have the reference and documentation in the code?

'ATLAS_DOMAIN is set but COOKIES_FILE is not. Please set COOKIES_FILE to the path of the cookies file.'
);
}
const cookies = JSON.parse(await fs.readFile(cookiesFile, 'utf8'));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you add some type definitions for this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean like, for the cookies object?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, something like:

Suggested change
const cookies = JSON.parse(await fs.readFile(cookiesFile, 'utf8'));
type StoredAtlasCloudCookies = {...some shape}[]
const cookies: StoredAtlasCloudCookies = JSON.parse(await fs.readFile(cookiesFile, 'utf8'));

We probably don't need any strict validation, but without the type it's unclear what's the expected shape for the content of the COOKIES_FILE file and taking into account that it will be generated in a completely separate repo, it's probably our best way of documenting this

updateMongoDBServerInfo();
if (!ATLAS_DOMAIN) {
debug('Getting mongodb server info');
updateMongoDBServerInfo();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Various checks in tests rely on this information existing, you can't just skip it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah I think I need to update the function to use the variable instead of hardcoded address like it currently does

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, probably can use DEFAULT_CONNECTION_STRING_1 there insteasd of just port, this is aligned more with what's expected

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines 290 to 295
for (let i = 0; i < tests.length; ++i) {
if (tests[i] === FIRST_TEST) {
[tests[i], tests[0]] = [tests[0], tests[i]];
break;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because I added the test filtering feature, and this line previously was always including the FIRST_TEST.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, gotcha, was kinda hard to understand from the code. Maybe better to be a bit more explicit about it?

Suggested change
for (let i = 0; i < tests.length; ++i) {
if (tests[i] === FIRST_TEST) {
[tests[i], tests[0]] = [tests[0], tests[i]];
break;
}
}
const shouldRunAllTests = e2eTestFilter === '*';
const tests = shouldRunAllTests ? <logic to move FIRST_TEST to the front> : <just exactly what glob returned>

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, will update

Copy link
Contributor Author

@syn-zhu syn-zhu Oct 21, 2024

Choose a reason for hiding this comment

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

Actually, looking at this again, I think it's more like we want to move time-to-first-query.test.ts to the front only if it is one of the tests we will run (it may still be included even if a filter is used).

So technically, we need to check if it's in the full array, and that point we are already iterating the array, so we probably don't need to disambiguate the two cases here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sure, if the intent is to be able to pick up more than one file, this makes sense. Can we rewrite this using a sort then instead of in place swapping so that the code is readable and the intent is clear?

await browser.setupDefaultConnections();
// no need to setup connections if we are running against Atlas
if (!ATLAS_DOMAIN) {
await browser.setupDefaultConnections();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess it's just temporarily only in this file? You'd need to do this in almost every test file and the pattern is to try to keep the test code as similar as possible (not to mention that changing this logic if we start adding things like that everywhere would be very hard)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, in Atlas when you create new clusters, then the connections start showing up automatically in Data Explore. So there is no extra step needed to "setup" the connections via the connection creation modal.

So, I actually do think we would skip this step for every test if we're running against Atlas. Are there any concerns about this?

Copy link
Collaborator

@gribnoysup gribnoysup Oct 21, 2024

Choose a reason for hiding this comment

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

If switch statements are generic like that and would apply to every test case, we add them in the helper methods themselves, not in the test case, so again, if this is just temporary because that's the only test case you are adding, that's fine, but for follow-up PRs we'd need to move this logic out of test cases

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe I can add this check into the function itself? Would that be better?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh oops, just saw you already suggested that lol

@@ -46,6 +46,8 @@ let MONGODB_USE_ENTERPRISE =

// should we test compass-web (true) or compass electron (false)?
export const TEST_COMPASS_WEB = process.argv.includes('--test-compass-web');
export const ATLAS_DOMAIN = process.env.ATLAS_DOMAIN;
Copy link
Collaborator

Choose a reason for hiding this comment

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

For all these new variables you're adding, can we make the names more distinct to indicate the use-case better? Especially the CONNECTION_ ones, a lot of things rely on these, so just allowing arbitrary overrides without context is not great

Copy link
Contributor Author

@syn-zhu syn-zhu Oct 21, 2024

Choose a reason for hiding this comment

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

Sure, do you have some concrete suggestions?

For the connection_ ones in particular, do you just mean adding ATLAS_ to the name or something?

And for this one as well, let me know how I can make it more specific.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, a common prefix we can stick on all of them is probably the way to go, something like ATLAS_CLOUD_EXTERNAL_URL_TESTING_, just so it's clear it's specifically for this "testing a deployed atlas cloud" scenario, not a generic way to control these variables

Copy link
Collaborator

Choose a reason for hiding this comment

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

Or rather TEST_ATLAS_CLOUD_EXTERNAL_URL_ to match existing ones

@syn-zhu syn-zhu requested a review from gribnoysup October 21, 2024 14:08
@syn-zhu syn-zhu requested review from gribnoysup and removed request for gribnoysup October 21, 2024 20:07
Comment on lines 116 to 117
process.env.TEST_ATLAS_CLOUD_EXTERNAL_CONNECTION_STRING_1 ||
`mongodb://127.0.0.1:${String(MONGODB_TEST_SERVER_PORT)}`,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
process.env.TEST_ATLAS_CLOUD_EXTERNAL_CONNECTION_STRING_1 ||
`mongodb://127.0.0.1:${String(MONGODB_TEST_SERVER_PORT)}`,
DEFAULT_CONNECTION_STRING_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.

The /test suffix doesn't make a difference here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

DEFAULT_CONNECTION_STRING_1 has the /test suffix in its definition, but the one here doesn't.

I think that's supposed to refer to the auth DB that is used? if you think it won't make a difference then I can change it to what you suggested.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep, doesn't make a difference, it's a valid connection string

Comment on lines +810 to +811
// Navigate to a 404 page to set cookies
await browser.navigateTo(`https://${TEST_ATLAS_CLOUD_EXTERNAL_URL}/404`);
Copy link
Collaborator

@gribnoysup gribnoysup Oct 22, 2024

Choose a reason for hiding this comment

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

Actually, not sure I understand, why are we doing this if we're setting cookies from a file below? Can we just use all the cookies from a file?

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 API only allows you to set cookies for the domain you're actually on haha

idk why, but it's in the documentation here: https://webdriver.io/docs/api/browser/setCookies/

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, okay, I thought we're going on this page so that the set-cookie header from the backend can set some cookies, not so that the browser.setCookies call can work, got it!

// Navigate to a 404 page to set cookies
await browser.navigateTo(`https://${TEST_ATLAS_CLOUD_EXTERNAL_URL}/404`);

const cookiesFile = process.env.COOKIES_FILE;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
const cookiesFile = process.env.COOKIES_FILE;
const cookiesFile = process.env.TEST_ATLAS_CLOUD_EXTERNAL_COOKIES_FILE;

Comment on lines 829 to 836
await browser.setCookies({
name: cookie.name,
value: cookie.value,
domain: cookie.domain,
path: cookie.path,
secure: cookie.secure,
httpOnly: cookie.httpOnly,
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

setCookies takes an array, you don't need to do this in sequence

Copy link
Collaborator

@gribnoysup gribnoysup left a comment

Choose a reason for hiding this comment

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

We should rename the rest of some specific Atlas Cloud test related variables (cookie file is the only one left I think, at least the one I noticed on re-review), otherwise a few nits, but looks good to merge

@syn-zhu syn-zhu merged commit add5de6 into main Oct 22, 2024
22 of 25 checks passed
@syn-zhu syn-zhu deleted the run-e2e-against-atlas branch October 22, 2024 16:04
gribnoysup added a commit that referenced this pull request Oct 23, 2024
…runner

This also includes re-applying changes from #6381 from scratch
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.

2 participants