Skip to content

[ci] Windows test support#4885

Draft
gamesh411 wants to merge 13 commits into
Ericsson:masterfrom
gamesh411:windows-test-support
Draft

[ci] Windows test support#4885
gamesh411 wants to merge 13 commits into
Ericsson:masterfrom
gamesh411:windows-test-support

Conversation

@gamesh411

Copy link
Copy Markdown
Contributor

Add analyzer and web (sqlite) test jobs on windows-latest. Both use continue-on-error since Windows support is exploratory. Uses bash shell and choco for dependency installation.

@gamesh411 gamesh411 changed the title CI: add Windows test jobs (continue-on-error) [ci] Windows test support Jun 8, 2026
@gamesh411 gamesh411 force-pushed the windows-test-support branch 14 times, most recently from 8081c64 to 7219423 Compare June 9, 2026 10:53
The codechecker_common/compatibility/multiprocessing.py shim
provided platform-conditional imports (multiprocess on macOS/Win,
stdlib on Linux). Replace with direct multiprocess imports
everywhere since multiprocess is now a hard dependency on all
platforms.

multiprocess is a fork of stdlib multiprocessing that uses dill
instead of pickle, enabling serialization of closures and complex
objects needed for spawn-based workers.

No behavioral change: multiprocess uses fork by default on Linux
(same as stdlib multiprocessing). The start method is not changed
in this commit.
On non-Linux platforms, fork() is unsafe due to macOS Obj-C
runtime constraints (Security.framework loaded via SQLAlchemy ->
asyncio -> ssl -> libcrypto triggers fork-safety crashes). Windows
has no fork() at all. Python 3.14 will change the default start
method on all platforms.

Changes:
- Set multiprocess start method to 'spawn' on non-Linux (cli.py)
- Add _build_worker_server() to reconstruct HTTPServer in each
  spawn worker from serializable args (server.py)
- Pass listening socket via DupFd to spawn workers (server.py)
- Add logging initializers to Pool workers in analysis_manager,
  pre_analysis_manager, and log_parser (spawn workers do not
  inherit parent's logging configuration)

Linux behavior is unchanged: fork is still used, no import
overhead, no worker reconstruction needed.
- Normalize gcc/clang output quotes in log parser tests (macOS
  clang uses different quoting than Linux gcc)
- Skip ld-logger specific tests on non-Linux (LD_PRELOAD is
  Linux-only)
- Use os.sep for path assertions instead of hardcoded '/'
- Add platform guards for Linux-specific checker tests
The JSON compilation database can use either 'command' (string) or
'arguments' (list) format. tu_collector only handled 'command',
failing silently on the 'arguments' format. Parse both formats
correctly by joining the arguments list when 'command' is absent.
- Use subprocess.run() instead of Popen.communicate() for git
  commands (clearer error handling)
- Handle git template path differences across platforms
- Fix Makefile test targets for portable invocation
- Replace blind sleep(5) with port-readiness polling (socket
  connect loop to localhost:3000)
- Capture mock server stdout/stderr to log file for debugging
- Use sys.executable for subprocess to ensure correct Python
- Use 127.0.0.1 instead of localhost in OAuth test config
  (avoids DNS resolution delays on some platforms)
- Add flush=True to startup print for immediate visibility
- Add HTTP readiness check as fallback for file-based detection:
  if the server port responds to HTTP (even 404), consider it
  ready. This handles cases where the log file message is delayed
  due to output buffering or slow worker initialization.
- Add fatal error detection: fail fast if server output contains
  DB initialization failures instead of waiting for full timeout.
- Allow CI to override worker counts via CC_TEST_API_WORKERS and
  CC_TEST_TASK_WORKERS env vars for tuning on slow infrastructure.
- Pass port to wait_for_server_start for HTTP probe.

The HTTP readiness timeout is subject to tuning based on CI
infrastructure performance. Current observations: macOS GitHub
Actions runners have ~40ms per-file I/O (133x slower than local
NVMe), causing spawn worker imports to take ~36s each.
Task management tests previously used fixed sleep() calls to
synchronize with async task state transitions. This is inherently
racy: too short and the task has not been picked up, too long and
it has already completed.

Replace with poll-based approach:
- _poll_status() polls getTaskInfo every 1s until expected state
  or timeout (120s on macOS, 30s on Linux)
- For RUNNING checks: create long (600s) task, poll until RUNNING,
  cancel when done
- For COMPLETED/FAILED: create short (1s) task, poll until
  terminal state (worker is already warm from prior tests)
- Completion waits in filter tests use poll loops too

This makes tests deterministic regardless of worker startup time
while remaining fast on Linux (poll returns in 1-2s).
Add macOS runner (macos-latest) to CI:
- Analyzer job: matrix with ubuntu-24.04 and macos-latest
- Web (macOS) job: sqlite-only, 1+1 workers (CC_TEST_API_WORKERS=1
  CC_TEST_TASK_WORKERS=1) to reduce spawn startup overhead
- Tools job: matrix with macOS, skip Linux-only steps (build-logger
  needs LD_PRELOAD, bazel-compile-commands needs Bazel setup)

macOS jobs use continue-on-error to avoid blocking Linux CI.

Worker count rationale: on macOS CI runners (3 CPU, 7 GB RAM),
each spawn worker imports 887 .pyc files at ~40ms each (~36s per
worker). With 1+1 workers, server startup takes ~42s vs ~84s with
2+2. This is a CI infrastructure constraint (VM storage latency),
not a code issue — locally startup is 1.6s.

Adds install-deps-macos.sh for brew-based dependency installation.
@gamesh411 gamesh411 force-pushed the windows-test-support branch from 7219423 to be130dd Compare June 12, 2026 20:58
Add analyzer and web (sqlite) test jobs on windows-latest. Both
use continue-on-error since Windows support is exploratory.

Uses bash shell and choco for LLVM/cppcheck installation. Worker
count set to 1+1 (same rationale as macOS: spawn worker import
overhead on potentially slow CI storage).

Python 3.10 to match other CI jobs.

Depends on the spawn-based server from prior commits for the web
tests to have any chance of working (Windows has no fork()).
@gamesh411 gamesh411 force-pushed the windows-test-support branch from be130dd to f74ee25 Compare June 12, 2026 20:59
python-ldap has no binary wheels for Windows and requires
OpenLDAP C headers to build from source. Use pytest.importorskip
to skip the test module cleanly when ldap is not installed.
@gamesh411 gamesh411 force-pushed the windows-test-support branch from bec7169 to 8ee7cf5 Compare June 12, 2026 21:15
@gamesh411 gamesh411 force-pushed the windows-test-support branch from 8ee7cf5 to 688847b Compare June 12, 2026 21:15
python-ldap has no binary wheels for Windows and requires
OpenLDAP C headers to build from source. Use pytest.importorskip
to skip the test module cleanly when ldap is not installed.
Replace hardcoded '/' with os.path.abspath(os.sep) for the build
action directory in test fixtures. '/' is not a valid path on
Windows.
@gamesh411 gamesh411 force-pushed the windows-test-support branch from 688847b to d5c0e02 Compare June 12, 2026 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant