Skip to content

test(windows): make path assertions and chmod tests OS-aware#1378

Merged
danielmeppiel merged 1 commit into
mainfrom
danielmeppiel/fix-windows-ci
May 18, 2026
Merged

test(windows): make path assertions and chmod tests OS-aware#1378
danielmeppiel merged 1 commit into
mainfrom
danielmeppiel/fix-windows-ci

Conversation

@danielmeppiel
Copy link
Copy Markdown
Collaborator

Problem

Windows CI on main is red (run 26061585552). Linux and macOS pass — only the Windows job fails, with six unit-test failures that all encode POSIX-only assumptions:

FAILED tests/unit/runtime/test_runtime_utils.py::TestFindRuntimeBinary::test_skips_non_executable_apm_binary
FAILED tests/unit/runtime/test_runtime_utils.py::TestFindRuntimeBinary::test_apm_binary_without_execute_permission_falls_back
FAILED tests/unit/integration/test_hook_integrator.py::TestClaudeIntegration::test_integrate_hookify_claude
FAILED tests/unit/integration/test_hook_integrator.py::TestClaudeIntegration::test_integrate_hooks_with_scripts_in_hooks_subdir_claude
FAILED tests/unit/integration/test_hook_integrator.py::TestCursorIntegration::test_integrate_hookify_cursor
FAILED tests/unit/integration/test_hook_integrator.py::TestIssue1007Fixes::test_rewrite_command_deploy_root_produces_absolute_path

Both groups are test-only defects; production code behaves correctly on Windows.

Root cause

Runtime tests (2) — both call chmod(0o644) / chmod(0o600) on the APM-managed binary expecting find_runtime_binary() to fall back to shutil.which() because the file is "not executable". Windows ignores POSIX execute bits: os.access(path, os.X_OK) returns True for any readable file, so the fallback branch is unreachable and the test asserts the wrong path.

Hook integrator tests (4) — all assert forward-slash substrings such as ".claude/hooks/hookify/hooks/pretooluse.py" in cmd. When deploy_root is set, _rewrite_command_for_target() emits absolute paths via Path.resolve(), which uses native separators (backslash on Windows). This is the correct production behaviour — Claude Code / Cursor on Windows expect Windows paths — so the fix is on the assertion side.

Fix

  • Skip the two chmod-based runtime tests on win32 with a reason documenting the platform limitation. Other tests in the same class already use @pytest.mark.skipif(sys.platform != "win32", ...) for the inverse case, so the pattern is established.
  • Normalise backslashes to forward slashes (cmd.replace("\\", "/")) before the substring / endswith check in the four hook-integrator tests. The production rewriter is untouched.

No src/ changes — six test-only edits, 17 lines added / 7 removed.

Validation

Locally:

$ uv run --extra dev pytest tests/unit/runtime/test_runtime_utils.py tests/unit/integration/test_hook_integrator.py -q
154 passed, 1 skipped in 2.17s
$ uv run --extra dev ruff check src/ tests/ && uv run --extra dev ruff format --check src/ tests/
All checks passed!
786 files already formatted

Both CI-mirror lint commands are silent per .apm/instructions/linting.instructions.md. Windows CI on this branch will confirm the six previously-failing tests now pass / skip cleanly.

Six unit tests fail on Windows CI because they encode POSIX-only
assumptions:

- tests/unit/runtime/test_runtime_utils.py
  * test_skips_non_executable_apm_binary
  * test_apm_binary_without_execute_permission_falls_back
  Both rely on chmod(0o644)/chmod(0o600) making the APM-managed binary
  non-executable so find_runtime_binary() falls back to PATH.  Windows
  ignores POSIX execute bits; os.access(path, os.X_OK) returns True for
  any readable file, so the fallback branch is unreachable.  Skip both
  on win32 with a reason that documents the platform limitation.

- tests/unit/integration/test_hook_integrator.py
  Four tests assert that rewritten hook commands contain forward-slash
  paths like '.claude/hooks/hookify/hooks/pretooluse.py'.  When
  deploy_root is set, _rewrite_command_for_target() emits absolute paths
  via Path.resolve(), which uses native separators (backslash on
  Windows).  This is the correct production behaviour -- Claude Code on
  Windows expects Windows paths -- so normalise the assertion side
  instead of the code under test by replacing backslashes before the
  substring/endswith check.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 18, 2026 21:38
@danielmeppiel danielmeppiel merged commit 0b90151 into main May 18, 2026
19 checks passed
@danielmeppiel danielmeppiel deleted the danielmeppiel/fix-windows-ci branch May 18, 2026 21:41
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

This PR fixes Windows-only unit test failures by making test assertions OS-aware, without changing production code. It aligns runtime permission tests with Windows semantics and makes hook-integrator path assertions resilient to native path separators.

Changes:

  • Skip two chmod/execute-bit-based runtime tests on win32, documenting why the branch is unreachable on Windows.
  • Normalize command-path separators in four hook-integrator tests by replacing backslashes before substring/endswith assertions.
Show a summary per file
File Description
tests/unit/runtime/test_runtime_utils.py Skips POSIX execute-bit dependent tests on Windows to match os.access(X_OK) behavior.
tests/unit/integration/test_hook_integrator.py Normalizes path separators in assertions so rewritten hook commands pass on Windows and POSIX.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 0

sergio-sisternes-epam pushed a commit that referenced this pull request May 19, 2026
Six unit tests fail on Windows CI because they encode POSIX-only
assumptions:

- tests/unit/runtime/test_runtime_utils.py
  * test_skips_non_executable_apm_binary
  * test_apm_binary_without_execute_permission_falls_back
  Both rely on chmod(0o644)/chmod(0o600) making the APM-managed binary
  non-executable so find_runtime_binary() falls back to PATH.  Windows
  ignores POSIX execute bits; os.access(path, os.X_OK) returns True for
  any readable file, so the fallback branch is unreachable.  Skip both
  on win32 with a reason that documents the platform limitation.

- tests/unit/integration/test_hook_integrator.py
  Four tests assert that rewritten hook commands contain forward-slash
  paths like '.claude/hooks/hookify/hooks/pretooluse.py'.  When
  deploy_root is set, _rewrite_command_for_target() emits absolute paths
  via Path.resolve(), which uses native separators (backslash on
  Windows).  This is the correct production behaviour -- Claude Code on
  Windows expects Windows paths -- so normalise the assertion side
  instead of the code under test by replacing backslashes before the
  substring/endswith check.

Co-authored-by: Daniel Meppiel <copilot-rework@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

2 participants