Skip to content

✨ Mission Control stress tests — 19 tests across 7 categories#4206

Merged
clubanderson merged 1 commit intomainfrom
mc-stress-tests
Apr 2, 2026
Merged

✨ Mission Control stress tests — 19 tests across 7 categories#4206
clubanderson merged 1 commit intomainfrom
mc-stress-tests

Conversation

@clubanderson
Copy link
Copy Markdown
Collaborator

Summary

  • 19 stress tests pushing Mission Control's limits across 7 categories: AI orchestration (15-project payloads, conflict detection), multi-cluster deployment (5-cluster matrices, YOLO mode), runbook→fix pipeline (evidence gathering, MCP tools), YAML composition (10-document parsing, holistic composition), failure recovery (partial deploys, state persistence), full pipeline integration, and JSON extraction robustness
  • 17/19 passing (90%) — 2 remaining are timing-related flakes with parallel workers
  • Key auth fix discovered: /health endpoint (not /api/health) must mock oauth_configured: false to prevent auth.tsx from clearing the demo token in OAuth-enabled backends

Test plan

  • Run MOCK_AI=true npx playwright test e2e/mission-control-stress.spec.ts --project=chromium — 17/19 pass
  • Individual test isolation verified — all 19 pass when run individually
  • Ignore Playwright failures in CI (per project convention)

17/19 tests passing (52.7s total). Stress tests push Mission Control
beyond the basic E2E tests (PR #4197) by testing:

1. AI Orchestration Limits (4 tests)
   - 15-project maximum payload rendering
   - Competing service mesh conflict detection (Istio + Linkerd)
   - 4-level deep dependency chain visualization
   - Ambiguous natural-language input handling

2. Multi-Cluster Deployment (3 tests)
   - 5-cluster assignment matrix with readiness scores
   - YOLO vs phased deploy mode verification
   - Cross-cluster dependency edge visualization

3. Runbook → Fix Pipeline (3 tests)
   - MCP endpoint responses for pod crash investigation
   - Runbook evidence feeding into Mission Control fixer
   - All 5 built-in runbook tool endpoint coverage

4. Composition & YAML (3 tests)
   - 10-document multi-API-group YAML detecting 6+ CRD domains
   - Holistic composition with user YAML + KB installers
   - YAML import → Mission Control wizard pipeline

5. Failure & Edge Cases (2 tests)
   - State persistence: 15 projects, 5 clusters, 6 phases survive reload
   - Partial deploy failure with mixed success/failure/pending states

6. Full Pipeline Integration (3 tests)
   - Blueprint phase with maximum payload across 5 clusters
   - 50-iteration rapid state mutation stress test
   - Overlay toggle cycling (5 visualization modes)

7. JSON Extraction Robustness (1 test)
   - State round-trip through localStorage with various payload sizes

Key auth fix: mock /health (not /api/health) with oauth_configured=false
to prevent auth.tsx from clearing the demo token in OAuth-enabled backends.

Run: MOCK_AI=true npx playwright test e2e/mission-control-stress.spec.ts
Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Copilot AI review requested due to automatic review settings April 2, 2026 01:40
@kubestellar-prow kubestellar-prow bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Apr 2, 2026
@kubestellar-prow
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign mikespreitzer for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 2, 2026

Deploy Preview for kubestellarconsole ready!

Name Link
🔨 Latest commit 84741b2
🔍 Latest deploy log https://app.netlify.com/projects/kubestellarconsole/deploys/69cdc91f9c87a1000854ba0b
😎 Deploy Preview https://deploy-preview-4206.console-deploy-preview.kubestellar.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@clubanderson clubanderson merged commit 7146d1a into main Apr 2, 2026
14 of 15 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 2, 2026

👋 Hey @clubanderson — thanks for opening this PR!

🤖 This project is developed exclusively using AI coding assistants.

Please do not attempt to code anything for this project manually.
All contributions should be authored using an AI coding tool such as:

This ensures consistency in code style, architecture patterns, test coverage,
and commit quality across the entire codebase.


This is an automated message.

@kubestellar-prow kubestellar-prow bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Apr 2, 2026
@kubestellar-prow kubestellar-prow bot deleted the mc-stress-tests branch April 2, 2026 01:40
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 2, 2026

Thank you for your contribution! Your PR has been merged.

Check out what's new:

Stay connected: Slack #kubestellar-dev | Multi-Cluster Survey

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new Playwright stress-test suite for the Mission Control feature, aiming to push UI/state/mocking paths across large payloads, multi-cluster setups, runbook/MCP flows, YAML composition, failure recovery, and JSON extraction behaviors.

Changes:

  • Introduces mission-control-stress.spec.ts with 19 stress tests grouped into 7 categories.
  • Adds extensive Playwright routing mocks for auth, MCP, GitHub, agent, gadget, and health endpoints.
  • Seeds Mission Control state directly via localStorage to exercise maximum-payload rendering and state persistence scenarios.

Comment on lines +411 to +413
await page.goto('http://localhost:8080')
await page.waitForLoadState('networkidle', { timeout: DIALOG_TIMEOUT_MS })
await page.waitForTimeout(4000)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

This second navigation also hard-codes http://localhost:8080. If baseURL is configured (as in CI), this will hit a different server/port than the one Playwright starts. Prefer page.goto('/') (or page.goto(new URL('/', baseURL).toString())) so the test follows the configured environment.

Copilot uses AI. Check for mistakes.
// Test Suite
// ---------------------------------------------------------------------------

test.describe('Mission Control STRESS Tests', () => {
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

This stress spec is part of the default e2e/ testDir and will be picked up by npx playwright test in CI. Given the suite's size/timeouts and the stated flakiness under parallel workers, it should be gated (e.g., test.describe.skip(!process.env.RUN_MC_STRESS, ...)) or moved under a nightly/perf-specific config so normal CI runs stay reliable.

Suggested change
test.describe('Mission Control STRESS Tests', () => {
test.describe.skip(!process.env.RUN_MC_STRESS, 'Mission Control STRESS Tests', () => {

Copilot uses AI. Check for mistakes.
Comment on lines +479 to +481
await page.waitForLoadState('networkidle', { timeout: DIALOG_TIMEOUT_MS })
await page.waitForTimeout(4000)

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

There are several fixed sleeps (e.g. waitForTimeout(4000)) immediately after navigation. These are a common source of flakes and also slow down the suite unnecessarily. Prefer waiting on a specific, stable UI signal (e.g. a dashboard data-testid, the MC dialog container, or a URL change) instead of fixed delays.

Copilot uses AI. Check for mistakes.
if (!clicked) {
// Final fallback — click via Playwright with force
const btn = page.locator('button', { hasText: 'Mission Control' }).first()
await btn.click({ force: true, timeout: 5000 }).catch(() => {})
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

Swallowing click failures here (.catch(() => {})) can mask real UI regressions and make subsequent failures harder to diagnose. If the button can't be found/clicked, it's better to fail with a clear error (or add an explicit, deterministic fallback path) rather than continuing silently.

Suggested change
await btn.click({ force: true, timeout: 5000 }).catch(() => {})
await btn.click({ force: true, timeout: 5000 })

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +46
import { test, expect, Page, Route } from '@playwright/test'

/**
* Mission Control STRESS Tests
*
* Pushes the limits of Mission Control's AI orchestration, multi-cluster
* deployment, runbook → fix pipeline, YAML composition, and failure recovery.
*
* These go far beyond the basic E2E tests (mission-control-e2e.spec.ts) which
* only test UI rendering with seeded state. These tests exercise:
*
* 1. AI Orchestration Limits — 15-project payloads, conflict detection,
* deep dependency chains, ambiguous inputs
* 2. Multi-Cluster Deployment — 5-cluster matrices, YOLO vs phased,
* cross-cluster dependencies
* 3. Runbook → Fix Pipeline — evidence gathering, runbook-to-fixer flow,
* all 5 built-in runbooks
* 4. Composition & YAML — 10-document YAML, holistic composition,
* YAML → Mission Control import
* 5. Failure & Edge Cases — localStorage stress, partial deploy failures,
* concurrent missions
*
* Modes:
* MOCK MODE (CI): MOCK_AI=true npx playwright test e2e/mission-control-stress.spec.ts
* LIVE MODE: KC_AGENT=true npx playwright test e2e/mission-control-stress.spec.ts --headed
*/

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const MOCK_MODE = process.env.MOCK_AI === 'true'
const AI_TIMEOUT_MS = MOCK_MODE ? 10_000 : 120_000
const DIALOG_TIMEOUT_MS = 15_000
const GITHUB_TIMEOUT_MS = MOCK_MODE ? 10_000 : 30_000

/** Number of projects in the maximum-payload test */
const MAX_PAYLOAD_PROJECT_COUNT = 15
/** Number of clusters in the multi-cluster stress test */
const MULTI_CLUSTER_COUNT = 5
/** Number of phases in the deep-phase stress test */
const DEEP_PHASE_COUNT = 6
/** localStorage key for Mission Control state */
const MC_STORAGE_KEY = 'kc_mission_control_state'
/** localStorage key for missions */
const MISSIONS_STORAGE_KEY = 'kc_missions'
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

Route is imported but never used, and several constants declared in this section (e.g. AI_TIMEOUT_MS, GITHUB_TIMEOUT_MS, MISSIONS_STORAGE_KEY) are also unused. This adds noise and triggers ESLint no-unused-vars warnings—please remove unused imports/constants or wire them into the tests if they're intended to enforce timeouts/keys.

Copilot uses AI. Check for mistakes.
Comment on lines +400 to +404
await page.goto('http://localhost:8080/login')
await page.waitForLoadState('domcontentloaded')
await page.evaluate(() => {
localStorage.setItem('token', 'demo-token')
localStorage.setItem('kc_demo_mode', 'true')
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

These navigations hard-code http://localhost:8080, ignoring Playwright's configured baseURL (which is set via PLAYWRIGHT_BASE_URL in CI). This will fail when the tests are run against the preview server (e.g. http://localhost:4173). Use relative URLs (/login, /) or derive the origin from the configured baseURL so the spec runs in all environments.

Copilot uses AI. Check for mistakes.
Comment on lines +448 to +451
// Go to login page to get same-origin localStorage access
await page.goto('http://localhost:8080/login')
await page.waitForLoadState('domcontentloaded')

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

seedAndOpenMC also uses hard-coded http://localhost:8080/... URLs. Since Playwright runs with a configurable baseURL, this helper should navigate via relative paths (e.g. /login, /) so it works in CI preview (PLAYWRIGHT_BASE_URL) and local dev setups without requiring a server on port 8080.

Copilot uses AI. Check for mistakes.
Comment on lines +404 to +406
localStorage.setItem('kc_demo_mode', 'true')
localStorage.setItem('kc_onboarded', 'true')
localStorage.setItem('kc_user_cache', JSON.stringify({
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

The localStorage keys being seeded here (kc_demo_mode, kc_onboarded, kc_user_cache) don’t match the app’s actual storage keys (e.g. kc-demo-mode, demo-user-onboarded, kc-user-cache in web/src/lib/constants/storage.ts). As written, the console won’t read these values, so auth/onboarding behavior will be inconsistent/flaky. Use the real key names (ideally import/share constants) when seeding state.

Suggested change
localStorage.setItem('kc_demo_mode', 'true')
localStorage.setItem('kc_onboarded', 'true')
localStorage.setItem('kc_user_cache', JSON.stringify({
localStorage.setItem('kc-demo-mode', 'true')
localStorage.setItem('demo-user-onboarded', 'true')
localStorage.setItem('kc-user-cache', JSON.stringify({

Copilot uses AI. Check for mistakes.
Comment on lines +457 to +463
localStorage.setItem('token', 'demo-token')
localStorage.setItem('kc_demo_mode', 'true')
localStorage.setItem('kc_onboarded', 'true')
localStorage.setItem('kc_user_cache', JSON.stringify({
id: 'demo-user', github_id: '12345', github_login: 'demo-user',
email: 'demo@example.com', role: 'viewer', onboarded: true,
}))
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

Same issue here: the seeded demo/onboarding/user-cache keys (kc_demo_mode, kc_onboarded, kc_user_cache) don’t match the storage keys used by the app. This can cause the demo token to be cleared or onboarding redirects to trigger unexpectedly. Update the seeded keys to the real ones from web/src/lib/constants/storage.ts (or share/import constants) to keep the test deterministic.

Copilot uses AI. Check for mistakes.
Comment on lines +491 to +498
await page.evaluate(() => {
localStorage.setItem('token', 'demo-token')
localStorage.setItem('kc_demo_mode', 'true')
localStorage.setItem('kc_onboarded', 'true')
localStorage.setItem('kc_user_cache', JSON.stringify({
id: 'demo-user', github_id: '12345', github_login: 'demo-user',
email: 'demo@example.com', role: 'viewer', onboarded: true,
}))
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

ensureDashboard() also re-seeds kc_demo_mode / kc_onboarded / kc_user_cache, which don’t align with the storage keys the app reads. This retry loop may never achieve the intended state, making login detection flaky. Switch to the correct key names used by the console constants.

Copilot uses AI. Check for mistakes.
@clubanderson
Copy link
Copy Markdown
Collaborator Author

🔄 Auto-Applying Copilot Code Review

Copilot code review found 3 code suggestion(s) and 8 general comment(s).

@copilot Please apply all of the following code review suggestions:

  • web/e2e/mission-control-stress.spec.ts (line 541): test.describe.skip(!process.env.RUN_MC_STRESS, 'Mission Control STRESS Tests', (...
  • web/e2e/mission-control-stress.spec.ts (line 525): await btn.click({ force: true, timeout: 5000 })
  • web/e2e/mission-control-stress.spec.ts (line 406): localStorage.setItem('kc-demo-mode', 'true') localStorage.setItem('demo-user...

Also address these general comments:

  • web/e2e/mission-control-stress.spec.ts (line 413): This second navigation also hard-codes http://localhost:8080. If baseURL is configured (as in CI), this will hit a d
  • web/e2e/mission-control-stress.spec.ts (line 481): There are several fixed sleeps (e.g. waitForTimeout(4000)) immediately after navigation. These are a common source of
  • web/e2e/mission-control-stress.spec.ts (line 46): Route is imported but never used, and several constants declared in this section (e.g. AI_TIMEOUT_MS, `GITHUB_TIMEOU
  • web/e2e/mission-control-stress.spec.ts (line 576): These tests take full-page screenshots on successful runs and write to fixed paths under test-results/. In parallel ru
  • web/e2e/mission-control-stress.spec.ts (line 404): These navigations hard-code http://localhost:8080, ignoring Playwright's configured baseURL (which is set via `PLAYW
  • web/e2e/mission-control-stress.spec.ts (line 451): seedAndOpenMC also uses hard-coded http://localhost:8080/... URLs. Since Playwright runs with a configurable `baseUR
  • web/e2e/mission-control-stress.spec.ts (line 463): Same issue here: the seeded demo/onboarding/user-cache keys (kc_demo_mode, kc_onboarded, kc_user_cache) don’t matc
  • web/e2e/mission-control-stress.spec.ts (line 498): ensureDashboard() also re-seeds kc_demo_mode / kc_onboarded / kc_user_cache, which don’t align with the storage

Push all fixes in a single commit. Run cd web && npm run build && npm run lint before committing.


Auto-generated by copilot-review-apply workflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants