Files
vscode/scripts/test-integration.bat
Alexandru DimaandCopilot 4d57ed62e1 ci: run only the integration tests a change can affect on macOS and Windows (#344146)
* ci: rename the unit-test-plan artifact to test-plan

The plan is about to cover the integration tests too. Renames the artifact and its folder
(.build/unit-test-plan to .build/test-plan) and the input of the macOS and Windows test workflows
(unit_test_selection to test_selection). No behavior change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ripple: plan the integration tests

`ripple plan` now also selects the integration test files a change can affect: plan.json has an
`integration` object (`select`, `reason`, `files`), and `--out-dir` writes the selected files to
integration.txt, like unit.txt. The job summary gets an "Integration test plan" section.

A new configuration group, `runEveryIntegrationTest`, lists the files outside the module graph that
only the integration tests depend on: changing one runs every integration test, but no unit test.
As for `runEverything`, the scripts its scripts load through relative imports and the npm packages
they load count too (`runEverything` scripts first, so a script both groups load runs everything).
vscode.jsonc lists the integration test scripts and the Agent Host E2E runner. `runEverything` keeps
running every test, unit and integration.

`affected` and `blame` honor the new group, and `replay` reports `runAllIntegration` and
`declIntegrationTestFiles` per commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test: run only listed integration tests with --runList

The Agent Host E2E runner takes `--runList <file>`, like the unit test runners: it runs only the
suites whose files the list names, one per line, and exits before preparing the test runtime when
it names none. It passes the list on to its storage passes and does not forward it to the suites,
which it runs with `--run`.

scripts/test-integration.sh and .bat document `--runList`, which they already forwarded to the
node.js test runner, and treat it as a filter like `--run` and `--runGlob`: the extension host
suites, which no list names, do not run.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ci: run only the affected integration tests on macOS and Windows

The macOS and Windows Electron jobs, and the Windows Agent Host E2E job, now download the test plan
and pass its integration.txt with `--runList` to scripts/test-integration.sh (the node.js
integration tests) and to the Agent Host E2E runner. Linux keeps running every integration test.

`Check ripple` tells the Agent Host E2E suites (AGENT_HOST_E2E, kept in sync with the runner by
agentHostTestSelection.test.ts) from the other integration tests that the plan selects, and Detect
Changes outputs `selected-node-integration-tests` and `selected-agent-host-e2e`. The node.js
integration test step is skipped when the plan selects none of its files (new input
`node_integration_tests`), and Agent Host E2E (the macOS step, the Windows job) when it selects no
suite and as before when the affected-file check does not select it. A failed, missing or
run-everything plan runs every integration test, and so does a change to the integration test
scripts (`runEveryIntegrationTest`). When planning fails, the job summary also says that every
integration test runs.

On the last 300 first-parent commits of main (Oct 21 to 25), the plan selects no integration test
for 72% of them, some (29 of 68 files on average) for 20%, and every test for 8%. With the
path-based checks alone, the macOS and Windows node.js integration tests ran for 99.7% of them and
Agent Host E2E for 42%; with the plan, for 28% and 25%, and never where they did not run before.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* ci: address review of the integration test selection

- Changes to src/bootstrap-*.ts run every integration test (a new `runEveryIntegrationTest` group).
  Integration tests fork src/bootstrap-fork.ts through `FileAccess.asFileUri('bootstrap-fork')`,
  which ripple cannot resolve, so these changes selected no integration test, and macOS and
  Windows skipped them, including Agent Host E2E, which the affected-file check runs for any
  src/bootstrap* change. They touched 20 of 17,789 first-parent commits of main in 12 months.
- Restore the ripple README's description of the Browser unit test skip of #344108, which the
  rebase onto it dropped.
- Test that the Agent Host E2E runner runs only the suites that a `--runList` file lists, also with
  Windows line endings and separators, and that it prepares nothing when the list names none.
- The Ripple job says that ripple plans the tests, not the unit tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-10-25 17:55:01 +00:00

379 lines
15 KiB
Batchfile

@echo off
setlocal
:: Capture script directory before any call :label changes %~dp0
set "SCRIPT_DIR=%~dp0"
pushd %SCRIPT_DIR%\..
:: Parse arguments for help and filters
set "BUILD_ARG="
set "HAS_FILTER="
set "RUN_FILE="
set "RUN_GLOB="
set "GREP_PATTERN="
set "SUITE_FILTER="
set "ONLY_NODE_TESTS="
set "ONLY_EXTENSION_HOST_TESTS="
set "SHOW_HELP="
:parse_args
if "%~1"=="" goto done_parsing
if /i "%~1"=="--help" (set SHOW_HELP=1& shift & goto parse_args)
if /i "%~1"=="-h" (set SHOW_HELP=1& shift & goto parse_args)
if /i "%~1"=="--build" (set "BUILD_ARG=--build"& shift & goto parse_args)
if /i "%~1"=="--run" (set "RUN_FILE=%~2"& set HAS_FILTER=1& shift & shift & goto parse_args)
if /i "%~1"=="--grep" (set "GREP_PATTERN=%~2"& shift & shift & goto parse_args)
if /i "%~1"=="-g" (set "GREP_PATTERN=%~2"& shift & shift & goto parse_args)
if /i "%~1"=="-f" (set "GREP_PATTERN=%~2"& shift & shift & goto parse_args)
if /i "%~1"=="--runGlob" (set "RUN_GLOB=%~2"& set HAS_FILTER=1& shift & shift & goto parse_args)
if /i "%~1"=="--glob" (set "RUN_GLOB=%~2"& set HAS_FILTER=1& shift & shift & goto parse_args)
if /i "%~1"=="--runGrep" (set "RUN_GLOB=%~2"& set HAS_FILTER=1& shift & shift & goto parse_args)
if /i "%~1"=="--runList" (set HAS_FILTER=1& shift & shift & goto parse_args)
if /i "%~1"=="--suite" (set "SUITE_FILTER=%~2"& shift & shift & goto parse_args)
if /i "%~1"=="--only-node-tests" (set ONLY_NODE_TESTS=1& shift & goto parse_args)
if /i "%~1"=="--only-extension-host-tests" (set ONLY_EXTENSION_HOST_TESTS=1& shift & goto parse_args)
shift
goto parse_args
:done_parsing
if defined SHOW_HELP (
echo Usage: %~nx0 [options]
echo.
echo Runs integration tests. When no filters are given, all integration tests
echo ^(node.js integration tests + extension host tests^) are run.
echo Agent Host E2E suites are not included; run them with scripts\test-agent-host-e2e.bat.
echo.
echo --run and --runGlob select which node.js integration test files to load, and
echo --runList runs only the files that a list names. Extension host tests are
echo skipped when these options are used.
echo.
echo --grep filters test cases by name across all test runners. When used alone,
echo the pattern is applied to both node.js integration tests and all extension
echo host suites. When combined with --suite, only the selected suites are run.
echo.
echo --suite selects which extension host test suites to run.
echo Node.js integration tests are skipped when this option is used.
echo.
echo --only-node-tests and --only-extension-host-tests run one of the two parts,
echo for example in separate CI steps.
echo.
echo Options:
echo --build use the out-build directory for node.js and JSON tests
echo --run ^<file^> run tests from a specific file ^(src/ path^)
echo --runGlob, --glob ^<pattern^> select test files by path glob ^(e.g. '**\*.integrationTest.js'^)
echo --runList ^<file^> run only the test files listed in ^<file^>, one per line ^(src/ paths^)
echo --grep, -g, -f ^<pattern^> filter test cases by name ^(matched against test titles^)
echo --suite ^<pattern^> run only matching extension host test suites
echo supports comma-separated list
echo --only-node-tests run only the node.js integration tests
echo --only-extension-host-tests run only the extension host tests
echo --help, -h show this help
echo.
echo Available suites:
echo api-folder, api-workspace, colorize, terminal-suggest, typescript,
echo markdown, emmet, git, git-base, ipynb, notebook-renderers,
echo configuration-editing, github-authentication, copilot, css, html, json
echo.
echo All other options are forwarded to the node.js test runner ^(see scripts\test.bat --help^).
echo Note: extra options are not forwarded to extension host suites ^(--suite mode^).
echo.
echo Examples:
echo %~nx0
echo %~nx0 --run src\vs\editor\test\browser\controller.integrationTest.ts
echo %~nx0 --grep "some test name"
echo %~nx0 --runGlob "**\*.integrationTest.js"
echo %~nx0 --suite git # run only Git tests
echo %~nx0 --suite "api-folder,api-workspace" # run multiple suites
echo %~nx0 --suite api-folder --grep "some test" # grep within a suite
exit /b 0
)
if defined ONLY_NODE_TESTS if defined ONLY_EXTENSION_HOST_TESTS (
echo Error: --only-node-tests cannot be combined with --only-extension-host-tests or --suite
exit /b 1
)
if defined ONLY_NODE_TESTS if defined SUITE_FILTER (
echo Error: --only-node-tests cannot be combined with --only-extension-host-tests or --suite
exit /b 1
)
if defined ONLY_EXTENSION_HOST_TESTS if defined HAS_FILTER (
echo Error: --only-extension-host-tests cannot be combined with --run, --runGlob or --runList
exit /b 1
)
set VSCODEUSERDATADIR=%TEMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,2%
set VSCODECRASHDIR=%SCRIPT_DIR%\..\.build\crashes
set VSCODELOGSDIR=%SCRIPT_DIR%\..\.build\logs\integration-tests
:: Seed user settings to disable OS notifications (dock bounce, toast, etc.)
if not exist "%VSCODEUSERDATADIR%\User" mkdir "%VSCODEUSERDATADIR%\User"
(
echo {
echo "chat.notifyWindowOnConfirmation": "off",
echo "chat.notifyWindowOnResponseReceived": "off"
echo }
) > "%VSCODEUSERDATADIR%\User\settings.json"
:: Figure out which Electron to use for running tests
if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" (
chcp 65001
set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat
set VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE=1
echo Running integration tests out of sources.
) else (
set VSCODE_CLI=1
set ELECTRON_ENABLE_LOGGING=1
echo Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build.
)
echo Storing crash reports into '%VSCODECRASHDIR%'.
echo Storing log files into '%VSCODELOGSDIR%'.
:: Validate --suite filter matches at least one known suite
if defined SUITE_FILTER (
set "_any_match="
for %%s in (api-folder api-workspace colorize terminal-suggest typescript markdown emmet git git-base ipynb notebook-renderers configuration-editing github-authentication copilot css html json) do (
call :should_run_suite %%s && set "_any_match=1"
)
if not defined _any_match (
echo Error: no suites match filter '%SUITE_FILTER%'
echo Available suites: api-folder api-workspace colorize terminal-suggest typescript markdown emmet git git-base ipynb notebook-renderers configuration-editing github-authentication copilot css html json
goto :failed
)
)
:: Node.js integration tests
if defined SUITE_FILTER goto skip_nodejs_tests
if defined ONLY_EXTENSION_HOST_TESTS goto skip_nodejs_tests
echo.
echo ### node.js integration tests
call node --input-type=module -e "import { getAgentHostTestProfile } from './src/vs/platform/agentHost/test/node/agentHostTestProfile.ts'; console.log('Agent Host test profile:', getAgentHostTestProfile(), '(' + (process.env.AGENT_HOST_TEST_PROFILE_REASON ?? 'default') + ')');"
if errorlevel 1 goto :failed
if defined RUN_GLOB (
call .\scripts\test.bat %*
) else if defined RUN_FILE (
call .\scripts\test.bat %*
) else (
rem Agent Host E2E runs separately, in parallel isolated processes: scripts\test-agent-host-e2e.bat
call .\scripts\test.bat --runGlob **\*.integrationTest.js --excludeRunGlob "**/agentHost/test/node/e2e/{providers/*AgentHostE2E,conformance/*}.integrationTest.js" %*
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_nodejs_tests
:: Skip extension host tests when a non-suite filter is active
if not defined SUITE_FILTER if defined HAS_FILTER (
echo.
echo Filter active, skipping extension host tests.
rmdir /s /q "%VSCODEUSERDATADIR%" 2>nul
exit /b 0
)
if defined ONLY_NODE_TESTS (
rmdir /s /q "%VSCODEUSERDATADIR%" 2>nul
exit /b 0
)
:: Tests in the extension host
:: Forward grep pattern to extension test runners
if defined GREP_PATTERN set "MOCHA_GREP=%GREP_PATTERN%"
set API_TESTS_EXTRA_ARGS=--disable-telemetry --disable-experiments --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR%
call :should_run_suite api-folder || goto skip_api_folder
echo.
echo ### API tests (folder)
call "%INTEGRATION_TEST_ELECTRON_PATH%" %SCRIPT_DIR%\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%SCRIPT_DIR%\..\extensions\vscode-api-tests --extensionTestsPath=%SCRIPT_DIR%\..\extensions\vscode-api-tests\out\singlefolder-tests %API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_api_folder
call :should_run_suite api-workspace || goto skip_api_workspace
echo.
echo ### API tests (workspace)
call "%INTEGRATION_TEST_ELECTRON_PATH%" %SCRIPT_DIR%\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%SCRIPT_DIR%\..\extensions\vscode-api-tests --extensionTestsPath=%SCRIPT_DIR%\..\extensions\vscode-api-tests\out\workspace-tests %API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_api_workspace
call :should_run_suite colorize || goto skip_colorize
echo.
echo ### Colorize tests
if defined GREP_PATTERN (
call npm run test-extension -- -l vscode-colorize-tests --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l vscode-colorize-tests
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_colorize
call :should_run_suite terminal-suggest || goto skip_terminal_suggest
echo.
echo ### Terminal Suggest tests
if defined GREP_PATTERN (
call npm run test-extension -- -l terminal-suggest --enable-proposed-api=vscode.vscode-api-tests --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l terminal-suggest --enable-proposed-api=vscode.vscode-api-tests
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_terminal_suggest
call :should_run_suite typescript || goto skip_typescript
echo.
echo ### TypeScript tests
call "%INTEGRATION_TEST_ELECTRON_PATH%" %SCRIPT_DIR%\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%SCRIPT_DIR%\..\extensions\typescript-language-features --extensionTestsPath=%SCRIPT_DIR%\..\extensions\typescript-language-features\out\test\unit %API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_typescript
call :should_run_suite markdown || goto skip_markdown
echo.
echo ### Markdown tests
if defined GREP_PATTERN (
call npm run test-extension -- -l markdown-language-features --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l markdown-language-features
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_markdown
call :should_run_suite emmet || goto skip_emmet
echo.
echo ### Emmet tests
call "%INTEGRATION_TEST_ELECTRON_PATH%" %SCRIPT_DIR%\..\extensions\emmet\test-workspace --extensionDevelopmentPath=%SCRIPT_DIR%\..\extensions\emmet --extensionTestsPath=%SCRIPT_DIR%\..\extensions\emmet\out\test %API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_emmet
call :should_run_suite git || goto skip_git
echo.
echo ### Git tests
for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i
set GITWORKSPACE=%TEMPDIR%\git-%RANDOM%
mkdir %GITWORKSPACE%
call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%SCRIPT_DIR%\..\extensions\git --extensionTestsPath=%SCRIPT_DIR%\..\extensions\git\out\test %API_TESTS_EXTRA_ARGS%
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_git
call :should_run_suite git-base || goto skip_git_base
echo.
echo ### Git Base tests
if defined GREP_PATTERN (
call npm run test-extension -- -l git-base --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l git-base
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_git_base
call :should_run_suite ipynb || goto skip_ipynb
echo.
echo ### Ipynb tests
if defined GREP_PATTERN (
call npm run test-extension -- -l ipynb --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l ipynb
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_ipynb
call :should_run_suite notebook-renderers || goto skip_notebook_renderers
echo.
echo ### Notebook Output tests
if defined GREP_PATTERN (
call npm run test-extension -- -l notebook-renderers --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l notebook-renderers
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_notebook_renderers
call :should_run_suite configuration-editing || goto skip_configuration_editing
echo.
echo ### Configuration editing tests
if defined GREP_PATTERN (
call npm run test-extension -- -l configuration-editing --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l configuration-editing
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_configuration_editing
call :should_run_suite github-authentication || goto skip_github_authentication
echo.
echo ### GitHub Authentication tests
if defined GREP_PATTERN (
call npm run test-extension -- -l github-authentication --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l github-authentication
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_github_authentication
call :should_run_suite copilot || goto skip_copilot
echo.
echo ### Copilot tests
if defined GREP_PATTERN (
call npm run test-extension -- -l copilot --grep "%GREP_PATTERN%"
) else (
call npm run test-extension -- -l copilot
)
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_copilot
:: Tests standalone (CommonJS)
call :should_run_suite css || goto skip_css
echo.
echo ### CSS tests
call %SCRIPT_DIR%\node-electron.bat %SCRIPT_DIR%\..\extensions\css-language-features/server/test/index.js
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_css
call :should_run_suite html || goto skip_html
echo.
echo ### HTML tests
call %SCRIPT_DIR%\node-electron.bat %SCRIPT_DIR%\..\extensions\html-language-features/server/test/index.js
if %errorlevel% neq 0 exit /b %errorlevel%
:skip_html
call :should_run_suite json || goto skip_json
echo.
echo ### JSON tests
call "%SCRIPT_DIR%\node-electron.bat" "%SCRIPT_DIR%\..\extensions\json-language-features\client\out\test\index.js" %BUILD_ARG%
if %errorlevel% neq 0 goto :failed
:skip_json
:: Cleanup
rmdir /s /q "%VSCODEUSERDATADIR%"
popd
goto :end
:: Subroutine: check whether a suite should run based on SUITE_FILTER.
:: Returns errorlevel 0 if the suite should run, 1 if it should be skipped.
:should_run_suite
if not defined SUITE_FILTER exit /b 0
set "_suite_name=%~1"
:: Replace commas with spaces so for-loop tokenizes correctly
set "_filter=%SUITE_FILTER:,= %"
for %%p in (%_filter%) do (
if /i "%%p"=="%_suite_name%" exit /b 0
)
exit /b 1
:failed
if defined VSCODEUSERDATADIR rmdir /s /q "%VSCODEUSERDATADIR%" 2>nul
popd
endlocal
exit /b 1
:end
endlocal