From 0210d865ff6434c28528fa2e3fddb703aa8442be Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Thu, 6 Mar 2025 14:34:34 +0100 Subject: [PATCH 1/4] chore(web): bind sandbox proxies to ipv4 to avoid dealing with localhost dns resolution --- packages/compass-web/scripts/electron-proxy.js | 2 +- packages/compass-web/scripts/ws-proxy.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compass-web/scripts/electron-proxy.js b/packages/compass-web/scripts/electron-proxy.js index 5481fa54b83..1e87c92c817 100644 --- a/packages/compass-web/scripts/electron-proxy.js +++ b/packages/compass-web/scripts/electron-proxy.js @@ -344,7 +344,7 @@ void electronApp.dock?.hide(); logger.log('[electron-proxy] starting proxy server on port %s', PROXY_PORT); -const proxyServer = expressProxy.listen(PROXY_PORT, 'localhost'); +const proxyServer = expressProxy.listen(PROXY_PORT, '0.0.0.0'); /** * Keeping a track of websocket proxy sockets so that we can clean them up on diff --git a/packages/compass-web/scripts/ws-proxy.js b/packages/compass-web/scripts/ws-proxy.js index 4e4aa4a84ab..a9138f752f4 100644 --- a/packages/compass-web/scripts/ws-proxy.js +++ b/packages/compass-web/scripts/ws-proxy.js @@ -10,7 +10,7 @@ const { WebSocketServer } = require('ws'); * every follow-up message is directly written to the opened socket stream */ function createWebSocketProxy(port = 1337, logger = console) { - const wsServer = new WebSocketServer({ host: 'localhost', port }, () => { + const wsServer = new WebSocketServer({ host: '0.0.0.0', port }, () => { logger.log('ws server listening at %s', wsServer.options.port); }); From 6de797e7d4b02b9cb0972fabb6f070f26c1ef9e0 Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Thu, 6 Mar 2025 14:35:19 +0100 Subject: [PATCH 2/4] chore: always rebuild webpack config when building compass(-web) --- packages/compass-web/package.json | 1 + packages/compass/package.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/compass-web/package.json b/packages/compass-web/package.json index bfa45bc7b76..dfaa262861b 100644 --- a/packages/compass-web/package.json +++ b/packages/compass-web/package.json @@ -37,6 +37,7 @@ "scripts": { "prepublishOnly": "npm run compile && compass-scripts check-exports-exist", "compile": "npm run webpack -- --mode production", + "prewebpack": "echo \"making sure compass webpack config is up to date...\" && npm run compile --workspace=@mongodb-js/webpack-config-compass", "webpack": "webpack-compass", "postcompile": "npm run typescript", "typescript": "tsc -p tsconfig-build.json --emitDeclarationOnly", diff --git a/packages/compass/package.json b/packages/compass/package.json index 1da800c08f5..1d38cd41777 100644 --- a/packages/compass/package.json +++ b/packages/compass/package.json @@ -141,12 +141,13 @@ "scripts": { "install": "node scripts/download-fonts.js && node scripts/download-csfle.js", "electron-rebuild": "node scripts/electron-rebuild.js", - "prestart": "npm run electron-rebuild && npm run compile --workspace=@mongodb-js/webpack-config-compass", + "prestart": "npm run electron-rebuild", "start": "HADRON_DISTRIBUTION=${HADRON_DISTRIBUTION:-compass} npm run webpack serve -- --mode development", "test-electron": "npm run test-main && npm run test-renderer", "test-main": "xvfb-maybe electron-mocha --no-sandbox \"./src/main/**/*.spec.*\" \"./src/main/**/*.test.*\"", "test-renderer": "xvfb-maybe electron-mocha --no-sandbox --config ./.mocharc.renderer.js \"./src/app/**/*.spec.*\"", "check": "npm run typecheck && npm run lint && npm run depcheck", + "prewebpack": "echo \"making sure compass webpack config is up to date...\" && npm run compile --workspace=@mongodb-js/webpack-config-compass", "webpack": "webpack-compass", "compile": "npm run webpack -- --mode production", "postcompile": "npm run generate-3rd-party-notices", From 32f7aa49f3a2add7423bad6c895ef3095585c294 Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Thu, 6 Mar 2025 17:57:14 +0100 Subject: [PATCH 3/4] chore(e2e): add Dockerfile for e2e test runner --- packages/compass-e2e-tests/Dockerfile | 101 ++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 packages/compass-e2e-tests/Dockerfile diff --git a/packages/compass-e2e-tests/Dockerfile b/packages/compass-e2e-tests/Dockerfile new file mode 100644 index 00000000000..85d95f00f71 --- /dev/null +++ b/packages/compass-e2e-tests/Dockerfile @@ -0,0 +1,101 @@ +# This Dockerfile builds and image that allows you to run compass e2e tests +# in a docker container without the need to do all the extra setup +# +# Usage: +# +# # build the image first, by default compass repo will by pulled from remote +# docker build \ +# --platform=linux/amd64 \ +# -f ./packages/compass-e2e-tests/Dockerfile . +# +# # you can build from a specific compass repo revision +# docker build \ +# --platform=linux/amd64 \ +# --build-arg="COMPASS_VERSION=#v1.45.0" \ +# -f ./packages/compass-e2e-tests/Dockerfile . +# +# # you can also build from local +# docker build \ +# --platform=linux/amd64 \ +# --build-arg="COMPASS_REPO=./" \ +# -f ./packages/compass-e2e-tests/Dockerfile . +# +# # run all web tests (default command) +# docker run --rm -it +# +# # run with a custom command (this runs filtered tests for desktop) +# docker run --rm -it desktop --test-filter=time-to-first-query +# +# # e2e env configuration is also supported (this runs filtered web tests) +# docker run -e COMPASS_E2E_TEST_FILTER="time-to-first-query" --rm -it + +FROM ubuntu:20.04 +USER root + +ARG NVM_VERSION="0.40.1" +ARG NODE_VERSION="20.16.0" +ENV NODE_VERSION=${NODE_VERSION} +ARG NPM_VERSION="10.2.4" +ENV NPM_VERSION=${NPM_VERSION} +# By default will pull compass from git, can be overriden with a local path +ARG COMPASS_REPO="https://github.com/mongodb-js/compass.git" +# When COMPASS_REPO points to the git repository, can be used to fetch repo with +# a certain tag / branch. Should start with #: `#v1.42.0` +ARG COMPASS_VERSION="" + +WORKDIR /tmp/compass + +ADD ${COMPASS_REPO}${COMPASS_VERSION} . +ADD https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh install_nvm.sh + +ENV DEBIAN_FRONTEND=noninteractive +# Default address, this will become available before we start running tests +ENV DBUS_SESSION_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket +# Required by some compass deps +ENV CXX=gcc-11 + +RUN <./entrypoint.sh +chmod +x ./entrypoint.sh +EOF + +ENV DEBUG="compass-e2e-tests*,electron*,hadron*,mongo*" +ENV MONGODB_VERSION="8.0.x-enterprise" +ENV MONGODB_RUNNER_VERSION="8.0.x-enterprise" +ENV COMPASS_E2E_WEBDRIVER_WAITFOR_TIMEOUT="240000" +ENV COMPASS_E2E_WEBDRIVER_WAITFOR_INTERVAL="1000" + +ENTRYPOINT ["./entrypoint.sh"] +CMD ["web"] From 43931d6b47c0f96a3aa157b21bcf6206ca5c0a00 Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Thu, 6 Mar 2025 18:04:22 +0100 Subject: [PATCH 4/4] chore(e2e): separate chrome flags and compass flags --- .../helpers/chrome-startup-flags.ts | 27 ++++++++++--------- .../helpers/compass-web-sandbox.ts | 15 +++++++++-- packages/compass-e2e-tests/helpers/compass.ts | 9 +++++-- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/packages/compass-e2e-tests/helpers/chrome-startup-flags.ts b/packages/compass-e2e-tests/helpers/chrome-startup-flags.ts index fc7ac6dc1b6..05c528a3e4f 100644 --- a/packages/compass-e2e-tests/helpers/chrome-startup-flags.ts +++ b/packages/compass-e2e-tests/helpers/chrome-startup-flags.ts @@ -1,7 +1,7 @@ // Copied from https://github.com/webdriverio/webdriverio/blob/1825c633aead82bc650dff1f403ac30cff7c7cb3/packages/devtools/src/constants.ts // These are the default flags that webdriverio uses to start Chrome driver. // NOTE: this has since been removed along with the devtools automation protocol https://github.com/webdriverio/webdriverio/commit/28e64e439ffc36a95f24aeda9f1d21111429dfa3#diff-6ea151d6c0687197931735239f397b7f5f0140a588c5b2b82ff584bbe73be069 -const DEFAULT_WEBDRIVER_FLAGS = [ +export const DEFAULT_WEBDRIVER_FLAGS = [ // suppresses Save Password prompt window '--enable-automation', // do not block popups @@ -45,7 +45,7 @@ const DEFAULT_WEBDRIVER_FLAGS = [ ]; // These flags are used to start Chrome driver based on the CI requirements. -const CI_FLAGS = [ +export const CI_FLAGS = [ // Chromecast feature that is enabled by default in some chrome versions // and breaks the app on Ubuntu '--media-router=0', @@ -55,21 +55,24 @@ const CI_FLAGS = [ // Seeing gpu init related errors on at least RHEL, especially when starting // the CLI '--disable-gpu', + '--num-raster-threads=0', + // Seems like disabling gpu is not always enough to prevent chromium from + // spawning it anyway, activating in process gpu seems to help with that + // + // See https://github.com/electron/electron/issues/28164 and + // https://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome/ + '--in-process-gpu', ]; -// These flags are used to start Chrome driver based on the Compass requirements. -const COMPASS_FLAGS = [ +// The shared set of flags that are used to start Chrome when running Compass +// desktop and web tests in CLI or GUI mode. +export const CHROME_STARTUP_FLAGS = [...DEFAULT_WEBDRIVER_FLAGS, ...CI_FLAGS]; + +// These flags are used to start Chrome based on the Compass requirements. +export const COMPASS_FLAGS = [ // Allow options such as --user-data-dir to pass through the command line // flag validation code. '--ignore-additional-command-line-flags', // Use the Atlas dev server for generative ai and atlas requests (cloud-dev). '--atlasServiceBackendPreset=atlas-dev', ]; - -// The shared set of flags that are used to start Chrome driver when running Compass -// tests in CLI or GUI mode. -export const CHROME_STARTUP_FLAGS = [ - ...DEFAULT_WEBDRIVER_FLAGS, - ...CI_FLAGS, - ...COMPASS_FLAGS, -]; diff --git a/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts b/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts index 0019ec04482..c4e642ffc51 100644 --- a/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts +++ b/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts @@ -11,6 +11,7 @@ import { } from './test-runner-paths'; import type { ConnectionInfo } from '@mongodb-js/connection-info'; import ConnectionString from 'mongodb-connection-string-url'; +import { CHROME_STARTUP_FLAGS } from './chrome-startup-flags'; const debug = Debug('compass-e2e-tests:compass-web-sandbox'); @@ -31,7 +32,16 @@ const wait = (ms: number) => { export function spawnCompassWebSandbox() { const proc = crossSpawn.spawn( 'npm', - ['run', '--unsafe-perm', 'start', '--workspace', '@mongodb-js/compass-web'], + [ + 'run', + '--unsafe-perm', + '--workspace', + '@mongodb-js/compass-web', + 'start', + '--', + '--no-sandbox', + '--in-process-gpu', + ], { env: process.env } ); proc.stdout.pipe(process.stdout); @@ -56,7 +66,7 @@ export async function waitForCompassWebSandboxToBeReady( } // No point in trying to fetch sandbox URL right away, give the spawn script // some time to run - await wait(2000); + await wait(5000); try { const res = await fetch(sandboxUrl); serverReady = res.ok; @@ -90,6 +100,7 @@ export async function spawnCompassWebSandboxAndSignInToAtlas( 'goog:chromeOptions': { binary: ELECTRON_PATH, args: [ + ...CHROME_STARTUP_FLAGS, `--user-data-dir=${COMPASS_WEB_WDIO_USER_DATA_PATH}`, `--app=${COMPASS_WEB_SANDBOX_RUNNER_PATH}`, ], diff --git a/packages/compass-e2e-tests/helpers/compass.ts b/packages/compass-e2e-tests/helpers/compass.ts index 42dc0f33e8d..c9de83a3984 100644 --- a/packages/compass-e2e-tests/helpers/compass.ts +++ b/packages/compass-e2e-tests/helpers/compass.ts @@ -20,7 +20,7 @@ import type { CompassBrowser } from './compass-browser'; import type { LogEntry } from './telemetry'; import Debug from 'debug'; import semver from 'semver'; -import { CHROME_STARTUP_FLAGS } from './chrome-startup-flags'; +import { CHROME_STARTUP_FLAGS, COMPASS_FLAGS } from './chrome-startup-flags'; import { DEFAULT_CONNECTION_STRINGS, DEFAULT_CONNECTION_NAMES, @@ -494,6 +494,7 @@ export async function runCompassOnce(args: string[], timeout = 30_000) { // When running binary without webdriver, we need to pass the same flags // as we pass when running with webdriverio to have similar behaviour. ...CHROME_STARTUP_FLAGS, + ...COMPASS_FLAGS, `--user-data-dir=${String(defaultUserDataDir)}`, ...args, ], @@ -598,6 +599,8 @@ async function startCompassElectron( const { needsCloseWelcomeModal, webdriverOptions, wdioOptions, chromeArgs } = await processCommonOpts(opts); + chromeArgs.push(...COMPASS_FLAGS); + if (!testPackagedApp) { // https://www.electronjs.org/docs/latest/tutorial/automated-testing#with-webdriverio chromeArgs.push(`--app=${COMPASS_DESKTOP_PATH}`); @@ -761,7 +764,8 @@ export async function startBrowser( assertTestingWeb(context); runCounter++; - const { webdriverOptions, wdioOptions } = await processCommonOpts(); + const { webdriverOptions, wdioOptions, chromeArgs } = + await processCommonOpts(); const browserCapabilities: Record> = { chrome: { @@ -769,6 +773,7 @@ export async function startBrowser( prefs: { 'download.default_directory': downloadPath, }, + args: chromeArgs, }, }, firefox: {