SERVER-113130: Add tests for devcontainer setup (#43325)

GitOrigin-RevId: bf63d9ba6a3ac5cd3fed21497d849414349614ca
This commit is contained in:
Eric Lavigne 2025-11-05 09:46:06 -07:00 committed by MongoDB Bot
parent 9aa2cce88e
commit 8e8ce3cd4d
6 changed files with 254 additions and 1 deletions

View File

@ -15,9 +15,17 @@ sudo chown -R "$(whoami)": "${HOME}/.cache" || echo "Warning: Could not fix cach
sudo chown -R "$(whoami)": "${WORKSPACE_FOLDER}/python3-venv" || echo "Warning: Could not fix python3-venv permissions"
sudo chown "$(whoami)": "${WORKSPACE_FOLDER}/.." || echo "Warning: Could not fix parent directory permissions"
# Fix workspace root permissions (prevents bazelrc and other file permission issues)
echo "Fixing workspace root permissions..."
sudo chown -R "$(whoami)": "${WORKSPACE_FOLDER}" || echo "Warning: Could not fix workspace permissions"
# Fix Git repository permissions (prevents "insufficient permission" errors)
echo "Fixing Git repository permissions..."
sudo chown -R "$(whoami)": "${WORKSPACE_FOLDER}/.git" || echo "Warning: Could not fix .git permissions"
# Configure git safe.directory (prevents "dubious ownership" warnings)
echo "Configuring git safe.directory..."
git config --global --add safe.directory "${WORKSPACE_FOLDER}" || echo "Warning: Could not configure git safe.directory"
echo "[OK] Volume and Git permissions fixed"
# Step 2: Configure Bazel with Docker information (one-time container setup)
@ -121,7 +129,41 @@ fi
# Step 5: Build clang configuration
echo "Building clang configuration..."
if bazel build compiledb --config=local --config=no-remote-exec; then
# Backup existing .bazelrc.compiledb if it exists, then use our known-good config
COMPILEDB_RC="${WORKSPACE_FOLDER}/.bazelrc.compiledb"
COMPILEDB_RC_BACKUP="${WORKSPACE_FOLDER}/.bazelrc.compiledb.backup"
if [ -f "${COMPILEDB_RC}" ]; then
echo "Info: Backing up existing .bazelrc.compiledb"
mv "${COMPILEDB_RC}" "${COMPILEDB_RC_BACKUP}"
fi
# Create our temporary config for setup (allow remote execution if auth is configured)
echo "common --config=dbg" >"${COMPILEDB_RC}"
# Check for engflow credentials (supports three auth methods: workspace certs, volume certs, or browser token)
if [ -f "${WORKSPACE_FOLDER}/engflow.cert" ] && [ -f "${WORKSPACE_FOLDER}/engflow.key" ]; then
echo "Info: Engflow TLS credentials found in workspace (CI mode), using remote execution"
elif [ -d "${HOME}/.config/engflow_auth" ] && [ -n "$(ls -A ${HOME}/.config/engflow_auth 2>/dev/null)" ]; then
echo "Info: Engflow auth directory exists (likely browser token), using remote execution"
else
echo "Info: No engflow credentials found, using local execution"
echo "common --config=local" >>"${COMPILEDB_RC}"
fi
# Ensure restore happens even if build fails
restore_compiledb_rc() {
if [ -f "${COMPILEDB_RC_BACKUP}" ]; then
echo "Info: Restoring user's .bazelrc.compiledb"
mv "${COMPILEDB_RC_BACKUP}" "${COMPILEDB_RC}"
else
rm -f "${COMPILEDB_RC}"
fi
}
trap restore_compiledb_rc EXIT
if bazel build compiledb; then
echo "[OK] Clang configuration built successfully"
else
echo "Warning: Failed to build clang configuration"

View File

@ -63,6 +63,7 @@ include:
- filename: etc/evergreen_yml_components/tasks/compile_tasks_shared.yml
- filename: etc/evergreen_yml_components/tasks/misc_tasks.yml
- filename: etc/evergreen_yml_components/tasks/release_tasks.yml
- filename: etc/evergreen_yml_components/tasks/devcontainer_tasks.yml
- filename: etc/evergreen_yml_components/variants/misc/task_generation.yml
- filename: etc/evergreen_yml_components/variants/misc/misc.yml

View File

@ -0,0 +1,26 @@
# Devcontainer Testing Tasks
#
# These tasks validate that the devcontainer setup works correctly
################################################
# Task Definitions #
################################################
tasks:
# Comprehensive E2E test using devcontainer CLI
- name: devcontainer_test
tags:
["assigned_to_jira_team_devprod_correctness", "auxiliary", "devcontainer"]
commands:
- func: "git get project and add git tag"
- func: "f_expansions_write"
- func: "get engflow key"
- func: "get engflow cert"
- command: subprocess.exec
display_name: "Test devcontainer setup (E2E)"
type: test
timeout_secs: 3600 # 1 hour for full setup
params:
binary: bash
args:
- "./src/evergreen/devcontainer_test.sh"

View File

@ -78,3 +78,17 @@ buildvariants:
tasks:
- name: sync_repo_with_copybara
priority: 50
- name: devcontainer-ubuntu
display_name: "Devcontainer Test (ubuntu2204)"
tags:
["assigned_to_jira_team_devprod_correctness", "auxiliary", "devcontainer"]
activate: true
paths:
- ".devcontainer/**"
- "evergreen/devcontainer*.sh"
- "poetry_requirements.txt"
run_on:
- ubuntu2204-small
tasks:
- name: devcontainer_test

View File

@ -0,0 +1,46 @@
#!/bin/bash
# Install devcontainer CLI for testing
# This script sets up the devcontainer CLI tool used by VS Code
set -euo pipefail
echo "========================================"
echo "Installing Devcontainer CLI"
echo "========================================"
# Verify Node.js is available
if ! command -v node &>/dev/null; then
echo "ERROR: Node.js not found (should be pre-installed on distro)"
exit 1
fi
echo "Node.js version:"
node --version
# Verify npm is available
if ! command -v npm &>/dev/null; then
echo "ERROR: npm not found (should come with Node.js)"
exit 1
fi
echo "npm version:"
npm --version
# Install devcontainer CLI locally in task workdir
echo ""
echo "Installing @devcontainers/cli..."
INSTALL_DIR="$PWD/.devcontainer-cli"
mkdir -p "$INSTALL_DIR"
npm install -g --prefix "$INSTALL_DIR" @devcontainers/cli
# Add to PATH for this script and subsequent commands
export PATH="$INSTALL_DIR/bin:$PATH"
# Verify installation
echo ""
echo "Verifying devcontainer CLI installation..."
devcontainer --version
echo "Installed to: $INSTALL_DIR"
echo ""
echo "✅ Devcontainer CLI installed successfully"

124
evergreen/devcontainer_test.sh Executable file
View File

@ -0,0 +1,124 @@
#!/bin/bash
# Test full devcontainer setup using devcontainer CLI
# This simulates the complete user experience
set -euo pipefail
echo "========================================"
echo "Devcontainer Fresh Setup Test"
echo "========================================"
# Get the absolute path to the repo root (src directory)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
cd "$REPO_ROOT"
# Set a non-conflicting username for CI
# In CI, USER is often "ubuntu" which conflicts with system users
# Use a distinct name that won't conflict
if [ "${USER:-}" = "ubuntu" ] || [ "${USER:-}" = "root" ]; then
export USER="mongociuser"
echo "CI environment detected, using USER=$USER"
fi
# Configure engflow credentials if they were fetched by evergreen
echo ""
echo "=== Configuring engflow credentials ==="
if [ -f "${REPO_ROOT}/engflow.key" ] && [ -f "${REPO_ROOT}/engflow.cert" ]; then
echo "✓ Engflow credentials found, configuring for devcontainer"
echo "common --tls_client_certificate=./engflow.cert" >>.bazelrc.evergreen
echo "common --tls_client_key=./engflow.key" >>.bazelrc.evergreen
else
echo "Info: No engflow credentials found (local execution will be used)"
fi
# Ensure devcontainer CLI is available
if ! command -v devcontainer &>/dev/null; then
echo "Installing devcontainer CLI..."
bash "$SCRIPT_DIR/devcontainer_cli_setup.sh"
# Add CLI to PATH (installed locally by cli_setup.sh)
export PATH="$PWD/.devcontainer-cli/bin:$PATH"
fi
echo "Using devcontainer CLI version:"
devcontainer --version
echo ""
echo "=== Building and starting devcontainer ==="
# Use a unique test ID to reliably find the container later
TEST_ID="mongo-devcontainer-test-$$"
# Set CI environment variable to enable strict error handling in the container
export CI=true
# Use devcontainer CLI to build and start (same as VS Code does)
# Use --id-label to tag the container so we can find it reliably
# Pass CI=true to enable strict error handling in the container
devcontainer up --workspace-folder . --id-label "test-id=${TEST_ID}" --update-remote-user-uid-default "off" --remote-env CI=true
echo ""
echo "=== Finding container ==="
# Find the container using our custom label
CONTAINER_ID=$(docker ps -a --filter "label=test-id=${TEST_ID}" --format "{{.ID}}" | head -1)
if [ -z "$CONTAINER_ID" ]; then
echo "ERROR: Failed to find devcontainer with label test-id=${TEST_ID}"
echo "Running containers:"
docker ps -a
exit 1
fi
echo "Container ID: $CONTAINER_ID"
echo ""
echo "=== Testing inside devcontainer ==="
# Run commands inside the container using devcontainer exec
# Pass the same --id-label so it can find the container we created
echo "Checking GCC version..."
devcontainer exec --workspace-folder . --id-label "test-id=${TEST_ID}" gcc --version
echo ""
echo "Checking Python version..."
devcontainer exec --workspace-folder . --id-label "test-id=${TEST_ID}" python3 --version
echo ""
echo "Checking Python venv..."
devcontainer exec --workspace-folder . --id-label "test-id=${TEST_ID}" bash -c "source python3-venv/bin/activate && python --version"
echo ""
echo "Checking Bazel..."
devcontainer exec --workspace-folder . --id-label "test-id=${TEST_ID}" bazel --version
echo ""
echo "Checking Git..."
devcontainer exec --workspace-folder . --id-label "test-id=${TEST_ID}" git --version
echo ""
echo "Checking clangd configuration..."
if ! devcontainer exec --workspace-folder . --id-label "test-id=${TEST_ID}" test -f compile_commands.json; then
echo "ERROR: compile_commands.json not found - clangd setup failed"
exit 1
fi
echo "✓ compile_commands.json exists"
echo ""
echo "Checking .clang-tidy configuration..."
if ! devcontainer exec --workspace-folder . --id-label "test-id=${TEST_ID}" test -f .clang-tidy; then
echo "ERROR: .clang-tidy not found - clang-tidy setup failed"
exit 1
fi
echo "✓ .clang-tidy exists"
echo ""
echo "=== Stopping devcontainer ==="
# Stop and remove the container
docker stop "$CONTAINER_ID"
docker rm "$CONTAINER_ID"
echo ""
echo "✅ Fresh setup test PASSED"