Skip to content

Commit 8f7d6be

Browse files
Merge remote-tracking branch 'origin/main' into beta-releases
2 parents b57dc53 + cf59b59 commit 8f7d6be

File tree

8 files changed

+223
-53
lines changed

8 files changed

+223
-53
lines changed

.evergreen/functions.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -683,11 +683,8 @@ functions:
683683
env:
684684
<<: *compass-env
685685
DEBUG: ${debug|}
686-
COMPASS_E2E_ATLAS_CLOUD_SANDBOX_CLOUD_CONFIG: 'qa'
687686
COMPASS_E2E_ATLAS_CLOUD_SANDBOX_USERNAME: ${e2e_tests_compass_web_atlas_username}
688687
COMPASS_E2E_ATLAS_CLOUD_SANDBOX_PASSWORD: ${e2e_tests_compass_web_atlas_password}
689-
COMPASS_E2E_ATLAS_CLOUD_SANDBOX_DBUSER_USERNAME: ${e2e_tests_compass_web_atlas_db_username}
690-
COMPASS_E2E_ATLAS_CLOUD_SANDBOX_DBUSER_PASSWORD: ${e2e_tests_compass_web_atlas_password}
691688
MCLI_PUBLIC_API_KEY: ${e2e_tests_mcli_public_api_key}
692689
MCLI_PRIVATE_API_KEY: ${e2e_tests_mcli_private_api_key}
693690
MCLI_ORG_ID: ${e2e_tests_mcli_org_id}
Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,62 @@
11
#!/bin/bash
22

3+
RUN_ID="$(date +"%s")-$(git rev-parse --short HEAD)"
4+
DELETE_AFTER="$(date -u -Iseconds -d '+2 hours' 2>/dev/null || date -u -Iseconds -v '+2H')"
5+
6+
# This script helps to automatically provision Atlas cluster for running the e2e
7+
# tests against. In CI this will always create a new cluster and delete it when
8+
# the test run is finished. You can also use this script locally to run e2e
9+
# tests against a "logged in" Atlas Cloud experience in compass-web sandbox.
10+
#
11+
# While the provisioning of clusters is automated, you should be aware that it
12+
# requires some extra environmental variables to be available when you are
13+
# running it. If you want to be able to run these e2e tests locally, following
14+
# steps are required:
15+
#
16+
# - Create a test Atlas user on one of the testing environments (-dev / -qa).
17+
# You can only use your work emails with a subaddress to create those (e.g,
18+
19+
#
20+
# - Setup a new org and project. Save the org id and project id for later.
21+
#
22+
# - Create a new API key (Access Manager > Project Access > Create Application >
23+
# API Key) for the project you created and save the public and private keys.
24+
#
25+
# - (Optional) Deploy a cluster with a required configuration through Atlas
26+
# Cloud UI. If you skip the step, the script will deploy a default cluster for
27+
# you.
28+
#
29+
# - Make sure that you have the following environmental variables provided to
30+
# the script below:
31+
#
32+
# MCLI_OPS_MANAGER_URL API base url matching the environment you used to
33+
# create your user (https://cloud{-dev,-qa}.mongodb.com/)
34+
# MCLI_PUBLIC_API_KEY Public API key
35+
# MCLI_PRIVATE_API_KEY Private API key
36+
# MCLI_ORG_ID Org ID
37+
# MCLI_PROJECT_ID Project ID
38+
#
39+
# COMPASS_E2E_ATLAS_CLOUD_SANDBOX_USERNAME Cloud user you created
40+
# COMPASS_E2E_ATLAS_CLOUD_SANDBOX_PASSWORD Cloud user password
41+
#
42+
# - Source the script followed by running the tests to make sure that some
43+
# variables exported from this script are available for the test env:
44+
#
45+
# (ATLAS_CLOUD_TEST_CLUSTER_NAME="TestCluster" source .evergreen/start-atlas-cloud-cluster.sh \
46+
# && npm run -w compass-e2e-tests test web -- --test-atlas-cloud-sandbox --test-filter="atlas-cloud/**/*")
47+
48+
_ATLAS_CLOUD_TEST_CLUSTER_NAME=${ATLAS_CLOUD_TEST_CLUSTER_NAME:-""}
49+
350
# Atlas limits the naming to something like /^[\w\d-]{,23}$/ (and will auto
451
# truncate if it's too long) so we're very limited in terms of how unique this
552
# name can be. Hopefully the epoch + part of git hash is enough for these to not
653
# overlap when tests are running
7-
ATLAS_CLOUD_TEST_CLUSTER_NAME="e2e-$(date +"%s")-$(git rev-parse HEAD)"
54+
DEFAULT_ATLAS_CLOUD_TEST_CLUSTER_NAME="e2e-$RUN_ID"
55+
56+
ATLAS_CLUSTER_NAME="${_ATLAS_CLOUD_TEST_CLUSTER_NAME:-$DEFAULT_ATLAS_CLOUD_TEST_CLUSTER_NAME}"
57+
58+
ATLAS_TEST_DB_USERNAME="testuser-$RUN_ID"
59+
ATLAS_TEST_DB_PASSWORD="$(head -c 32 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')"
860

961
function atlascli() {
1062
docker run \
@@ -17,23 +69,59 @@ function atlascli() {
1769
}
1870

1971
cleanup() {
20-
echo "Scheduling Atlas deployment \`$ATLAS_CLOUD_TEST_CLUSTER_NAME\` for deletion..."
21-
atlascli clusters delete $ATLAS_CLOUD_TEST_CLUSTER_NAME --force
72+
# Assuming that we want to preserve the cluster if the name was provided
73+
# outside of script. Helpful when trying to run the tests locally, you can
74+
# automatically create a cluster with a custom name for the first time, but
75+
# then re-use it when running the tests again. Don't forget to clean it up
76+
# after you're done!
77+
if [ -z "$_ATLAS_CLOUD_TEST_CLUSTER_NAME" ]; then
78+
echo "Scheduling Atlas deployment \`$ATLAS_CLUSTER_NAME\` for deletion..."
79+
atlascli clusters delete $ATLAS_CLUSTER_NAME --force
80+
else
81+
echo "Custom cluster name provided ($_ATLAS_CLOUD_TEST_CLUSTER_NAME), skipping cluster cleanup"
82+
fi
83+
echo "Deleting Atlas db user \`$ATLAS_TEST_DB_USERNAME\`..."
84+
atlascli dbusers delete $ATLAS_TEST_DB_USERNAME --force
2285
}
2386

2487
trap cleanup EXIT
2588

26-
echo "Creating Atlas deployment \`$ATLAS_CLOUD_TEST_CLUSTER_NAME\` to test against..."
27-
atlascli clusters create $ATLAS_CLOUD_TEST_CLUSTER_NAME \
89+
echo "Allowing access from current ip..."
90+
atlascli accessList create \
91+
--currentIp \
92+
--deleteAfter "$DELETE_AFTER"
93+
94+
echo "Creating Atlas db user \`$ATLAS_TEST_DB_USERNAME\`..."
95+
atlascli dbusers create atlasAdmin \
96+
--username "$ATLAS_TEST_DB_USERNAME" \
97+
--password "$ATLAS_TEST_DB_PASSWORD" \
98+
--deleteAfter "$DELETE_AFTER" # so that it's autoremoved if cleaning up failed for some reason
99+
100+
export COMPASS_E2E_ATLAS_CLOUD_SANDBOX_DBUSER_USERNAME="$ATLAS_TEST_DB_USERNAME"
101+
export COMPASS_E2E_ATLAS_CLOUD_SANDBOX_DBUSER_PASSWORD="$ATLAS_TEST_DB_PASSWORD"
102+
103+
echo "Creating Atlas deployment \`$ATLAS_CLUSTER_NAME\` to test against..."
104+
atlascli clusters create $ATLAS_CLUSTER_NAME \
28105
--provider AWS \
29106
--region US_EAST_1 \
30107
--tier M10
31108

32109
echo "Waiting for the deployment to be provisioned..."
33-
atlascli clusters watch "$ATLAS_CLOUD_TEST_CLUSTER_NAME"
110+
atlascli clusters watch $ATLAS_CLUSTER_NAME
34111

35112
echo "Getting connection string for provisioned cluster..."
36-
ATLAS_CLOUD_TEST_CLUSTER_CONNECTION_STRING_JSON="$(atlascli clusters connectionStrings describe $ATLAS_CLOUD_TEST_CLUSTER_NAME -o json)"
113+
CONNECTION_STRINGS_JSON="$(atlascli clusters connectionStrings describe $ATLAS_CLUSTER_NAME -o json)"
114+
115+
export COMPASS_E2E_ATLAS_CLOUD_SANDBOX_CLOUD_CONFIG=$(
116+
if [[ "$MCLI_OPS_MANAGER_URL" =~ "-dev" ]]; then
117+
echo "dev"
118+
elif [[ "$MCLI_OPS_MANAGER_URL" =~ "-qa" ]]; then
119+
echo "qa"
120+
else
121+
echo "prod"
122+
fi
123+
)
124+
echo "Cloud config: $COMPASS_E2E_ATLAS_CLOUD_SANDBOX_CLOUD_CONFIG"
37125

38-
export COMPASS_E2E_ATLAS_CLOUD_SANDBOX_DEFAULT_CONNECTIONS="{\"$ATLAS_CLOUD_TEST_CLUSTER_NAME\": $ATLAS_CLOUD_TEST_CLUSTER_CONNECTION_STRING_JSON}"
126+
export COMPASS_E2E_ATLAS_CLOUD_SANDBOX_DEFAULT_CONNECTIONS="{\"$ATLAS_CLUSTER_NAME\": $CONNECTION_STRINGS_JSON}"
39127
echo "Cluster connections: $COMPASS_E2E_ATLAS_CLOUD_SANDBOX_DEFAULT_CONNECTIONS"

THIRD-PARTY-NOTICES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
The following third-party software is used by and included in **Mongodb Compass**.
2-
This document was automatically generated on Tue Oct 29 2024.
2+
This document was automatically generated on Sun Nov 03 2024.
33

44
## List of dependencies
55

docs/tracking-plan.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# Compass Tracking Plan
33

4-
Generated on Tue, Oct 29, 2024 at 05:29 PM
4+
Generated on Sun, Nov 3, 2024 at 03:17 AM
55

66
## Table of Contents
77

@@ -148,6 +148,7 @@ Generated on Tue, Oct 29, 2024 at 05:29 PM
148148

149149
### Schema
150150
- [Schema Analyzed](#event--SchemaAnalyzedEvent)
151+
- [Schema Exported](#event--SchemaExportedEvent)
151152

152153
### Schema Validation
153154
- [Schema Validation Added](#event--SchemaValidationAddedEvent)
@@ -1801,6 +1802,25 @@ This event is fired when user analyzes the schema.
18011802
- **connection_id** (optional): `string | undefined`
18021803
- The id of the connection associated to this event.
18031804

1805+
<a name="event--SchemaExportedEvent"></a>
1806+
1807+
### Schema Exported
1808+
1809+
This event is fired when user shares the schema.
1810+
1811+
**Properties**:
1812+
1813+
- **has_schema** (required): `boolean`
1814+
- Indicates whether the schema was analyzed before sharing.
1815+
- **schema_width** (required): `number`
1816+
- The number of fields at the top level.
1817+
- **schema_depth** (required): `number`
1818+
- The number of nested levels.
1819+
- **geo_data** (required): `boolean`
1820+
- Indicates whether the schema contains geospatial data.
1821+
- **connection_id** (optional): `string | undefined`
1822+
- The id of the connection associated to this event.
1823+
18041824

18051825
## Schema Validation
18061826

packages/compass-e2e-tests/helpers/compass-web-sandbox.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,44 @@ export async function spawnCompassWebSandboxAndSignInToAtlas(
132132

133133
debug('Waiting for the auth to finish ...');
134134

135-
const res = await authenticatePromise;
135+
let authenticatedPromiseSettled = false;
136+
137+
// Atlas Cloud will periodically remind user to enable MFA (which we can't
138+
// enable in e2e CI environment), so to account for that, in parallel to
139+
// waiting for auth to finish, we'll wait for the MFA screen to show up and
140+
// skip it if it appears
141+
const [, settledRes] = await Promise.allSettled([
142+
(async () => {
143+
const remindMeLaterButton = 'button*=Remind me later';
144+
145+
await electronProxyRemote.waitUntil(
146+
async () => {
147+
return (
148+
authenticatedPromiseSettled ||
149+
(await electronProxyRemote.$(remindMeLaterButton).isDisplayed())
150+
);
151+
},
152+
// Takes awhile for the redirect to land on this reminder page when it
153+
// happens, so no need to bombard the browser with displayed checks
154+
{ interval: 2000 }
155+
);
156+
157+
if (authenticatedPromiseSettled) {
158+
return;
159+
}
160+
161+
await electronProxyRemote.$(remindMeLaterButton).click();
162+
})(),
163+
authenticatePromise.finally(() => {
164+
authenticatedPromiseSettled = true;
165+
}),
166+
]);
167+
168+
if (settledRes.status === 'rejected') {
169+
throw settledRes.reason;
170+
}
171+
172+
const res = settledRes.value;
136173

137174
if (res.ok === false || !(await res.json()).projectId) {
138175
throw new Error(

packages/compass-e2e-tests/helpers/test-runner-context.ts

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
} from '@mongodb-js/connection-info';
55
import type { MongoClusterOptions } from 'mongodb-runner';
66
import yargs from 'yargs';
7-
import type { Argv } from 'yargs';
7+
import type { Argv, CamelCase } from 'yargs';
88
import { hideBin } from 'yargs/helpers';
99
import Debug from 'debug';
1010
import fs from 'fs';
@@ -106,15 +106,17 @@ function buildDesktopArgs(yargs: Argv) {
106106
* make sure that the tests in mms are also updated to account for that
107107
*/
108108
const atlasCloudExternalArgs = [
109-
'test-atlas-cloud-external',
110109
'atlas-cloud-external-url',
111110
'atlas-cloud-external-project-id',
112111
'atlas-cloud-external-cookies-file',
113112
'atlas-cloud-external-default-connections-file',
114113
] as const;
115114

115+
type AtlasCloudExternalArgs =
116+
| typeof atlasCloudExternalArgs[number]
117+
| CamelCase<typeof atlasCloudExternalArgs[number]>;
118+
116119
const atlasCloudSandboxArgs = [
117-
'test-atlas-cloud-sandbox',
118120
'atlas-cloud-sandbox-cloud-config',
119121
'atlas-cloud-sandbox-username',
120122
'atlas-cloud-sandbox-password',
@@ -123,6 +125,10 @@ const atlasCloudSandboxArgs = [
123125
'atlas-cloud-sandbox-default-connections',
124126
] as const;
125127

128+
type AtlasCloudSandboxArgs =
129+
| typeof atlasCloudSandboxArgs[number]
130+
| CamelCase<typeof atlasCloudSandboxArgs[number]>;
131+
126132
let testEnv: 'desktop' | 'web' | undefined;
127133

128134
function buildWebArgs(yargs: Argv) {
@@ -191,13 +197,9 @@ function buildWebArgs(yargs: Argv) {
191197
description:
192198
'Stringified JSON with connections that are expected to be available in the Atlas project',
193199
})
194-
.implies(
195-
Object.fromEntries(
196-
atlasCloudSandboxArgs.map((arg) => {
197-
return [arg, atlasCloudSandboxArgs];
198-
})
199-
)
200-
)
200+
.implies({
201+
'test-atlas-cloud-sandbox': atlasCloudSandboxArgs,
202+
})
201203
.option('test-atlas-cloud-external', {
202204
type: 'boolean',
203205
description:
@@ -221,13 +223,9 @@ function buildWebArgs(yargs: Argv) {
221223
description:
222224
'File with JSON array of connections (following ConnectionInfo schema) that are expected to be available in the Atlas project',
223225
})
224-
.implies(
225-
Object.fromEntries(
226-
atlasCloudExternalArgs.map((arg) => {
227-
return [arg, atlasCloudExternalArgs];
228-
})
229-
)
230-
)
226+
.implies({
227+
'test-atlas-cloud-external': atlasCloudExternalArgs,
228+
})
231229
.conflicts({
232230
'test-atlas-cloud-external': 'test-atlas-cloud-sandbox',
233231
'test-atlas-cloud-sandbox': 'test-atlas-cloud-external',
@@ -310,42 +308,23 @@ export function assertTestingWeb(ctx = context): asserts ctx is WebParsedArgs {
310308
export function isTestingAtlasCloudExternal(
311309
ctx = context
312310
): ctx is WebParsedArgs & {
313-
[K in
314-
| 'testAtlasCloudExternal'
315-
| 'atlasCloudExternalUrl'
316-
| 'atlasCloudExternalProjectId'
317-
| 'atlasCloudExternalCookiesFile'
318-
| 'atlasCloudExternalDefaultConnectionsFile']: NonNullable<
319-
WebParsedArgs[K]
320-
>;
311+
[K in AtlasCloudExternalArgs]: NonNullable<WebParsedArgs[K]>;
321312
} {
322313
return isTestingWeb(ctx) && !!ctx.testAtlasCloudExternal;
323314
}
324315

325316
export function isTestingAtlasCloudSandbox(
326317
ctx = context
327318
): ctx is WebParsedArgs & {
328-
[K in
329-
| 'testAtlasCloudSandbox'
330-
| 'atlasCloudSandboxUsername'
331-
| 'atlasCloudSandboxPassword'
332-
| 'atlasCloudSandboxDbuserUsername'
333-
| 'atlasCloudSandboxDbuserPassword'
334-
| 'atlasCloudSandboxDefaultConnections']: NonNullable<WebParsedArgs[K]>;
319+
[K in AtlasCloudSandboxArgs]: NonNullable<WebParsedArgs[K]>;
335320
} {
336321
return isTestingWeb(ctx) && !!ctx.testAtlasCloudSandbox;
337322
}
338323

339324
export function assertTestingAtlasCloudSandbox(
340325
ctx = context
341326
): asserts ctx is WebParsedArgs & {
342-
[K in
343-
| 'testAtlasCloudSandbox'
344-
| 'atlasCloudSandboxUsername'
345-
| 'atlasCloudSandboxPassword'
346-
| 'atlasCloudSandboxDbuserUsername'
347-
| 'atlasCloudSandboxDbuserPassword'
348-
| 'atlasCloudSandboxDefaultConnections']: NonNullable<WebParsedArgs[K]>;
327+
[K in AtlasCloudSandboxArgs]: NonNullable<WebParsedArgs[K]>;
349328
} {
350329
if (!isTestingAtlasCloudSandbox(ctx)) {
351330
throw new Error(`Expected tested runtime to be web w/ Atlas Cloud account`);

packages/compass-schema/src/stores/store.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ export type SchemaStore = StoreWithStateMixin<SchemaState> & {
8787
dataService: DataService;
8888

8989
handleSchemaShare(): void;
90+
_trackSchemaShared(hasSchema: boolean): void;
91+
9092
onSchemaSampled(): void;
9193
geoLayerAdded(
9294
field: string,
@@ -162,6 +164,7 @@ export function activateSchemaPlugin(
162164
JSON.stringify(this.state.schema, null, ' ')
163165
);
164166
const hasSchema = this.state.schema !== null;
167+
this._trackSchemaShared(hasSchema);
165168
openToast(
166169
'share-schema',
167170
hasSchema
@@ -181,6 +184,21 @@ export function activateSchemaPlugin(
181184
);
182185
},
183186

187+
_trackSchemaShared(this: SchemaStore, hasSchema: boolean) {
188+
const { schema } = this.state;
189+
// Use a function here to a) ensure that the calculations here
190+
// are only made when telemetry is enabled and b) that errors from
191+
// those calculations are caught and logged rather than displayed to
192+
// users as errors from the core schema sharing logic.
193+
const trackEvent = () => ({
194+
has_schema: hasSchema,
195+
schema_width: schema?.fields?.length ?? 0,
196+
schema_depth: schema ? calculateSchemaDepth(schema) : 0,
197+
geo_data: schema ? schemaContainsGeoData(schema) : false,
198+
});
199+
track('Schema Exported', trackEvent, connectionInfoRef.current);
200+
},
201+
184202
/**
185203
* Initialize the schema store.
186204
*

0 commit comments

Comments
 (0)