Reactorcide

← Back to Jobs

test-python

failed exit: 1

Triggered by eval job 019c7f02-9704-ed07-a35a-cfacce47d34a

Job ID
019c7f02-cd6e-f352-77d9-630a130ae102
Created
2026-02-21 07:03:36 UTC
Updated
2026-02-21 07:03:36 UTC
Duration
4m 6s
Source Ref
a697a2c51c98ad174f1afd0f06ee7363f998a380
Source URL
https://github.com/catalystcommunity/reactorcide.git
Runner Image
10.16.0.1:5000/public/reactorcide/runnerbase:dev
Priority
10
Queue
reactorcide-jobs

Logs

2026-02-21T07:03:54.952935649ZCloning into '/workspace'...
2026-02-21T07:05:08.781832693Z=== Running Python Tests ===
2026-02-21T07:05:09.114156165ZUsing CPython 3.13.12 interpreter at: /usr/local/bin/python3.13
2026-02-21T07:05:09.114165945ZCreating virtual environment at: .venv
2026-02-21T07:05:09.173460689Z Building runnerlib @ file:///workspace/runnerlib
2026-02-21T07:05:09.333604545ZDownloading pygments (1.2MiB)
2026-02-21T07:05:09.337164545ZDownloading cryptography (4.3MiB)
2026-02-21T07:05:10.060141179Z Downloaded cryptography
2026-02-21T07:05:10.198900478Z Downloaded pygments
2026-02-21T07:05:10.794883724Z Built runnerlib @ file:///workspace/runnerlib
2026-02-21T07:05:10.801027778Zwarning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.
2026-02-21T07:05:10.801044876Z If the cache and target directories are on different filesystems, hardlinking may not be supported.
2026-02-21T07:05:10.801051273Z If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.
2026-02-21T07:05:10.91091052ZInstalled 22 packages in 112ms
2026-02-21T07:05:14.400268912Z============================= test session starts ==============================
2026-02-21T07:05:14.400280619Zplatform linux -- Python 3.13.12, pytest-8.3.5, pluggy-1.6.0
2026-02-21T07:05:14.400284415Zrootdir: /workspace/runnerlib
2026-02-21T07:05:14.400288109Zconfigfile: pyproject.toml
2026-02-21T07:05:14.400293465Zplugins: cov-7.0.0
2026-02-21T07:05:14.400297995Zcollected 381 items
2026-02-21T07:05:14.400300325Z
2026-02-21T07:05:14.449823766Ztests/test_config.py .................... [ 5%]
2026-02-21T07:05:14.467470962Ztests/test_container_advanced.py ......... [ 7%]
2026-02-21T07:05:14.476720426Ztests/test_container_isolation.py .... [ 8%]
2026-02-21T07:05:14.513416263Ztests/test_container_validation.py ................... [ 13%]
2026-02-21T07:05:14.652429592Ztests/test_directory_operations.py ............ [ 16%]
2026-02-21T07:05:14.7482101Ztests/test_eval.py ..................................................... [ 30%]
2026-02-21T07:05:14.778803124Z............. [ 34%]
2026-02-21T07:06:59.888471572Ztests/test_eval_cli.py .........FFF....F.... [ 39%]
2026-02-21T07:07:01.493120854Ztests/test_git_operations.py .......... [ 42%]
2026-02-21T07:07:01.97704578Ztests/test_git_ops.py ....... [ 44%]
2026-02-21T07:07:02.543294575Ztests/test_integration.py ........... [ 46%]
2026-02-21T07:07:03.731867772Ztests/test_job_isolation.py ...F [ 48%]
2026-02-21T07:07:03.844253334Ztests/test_plugins.py ....................... [ 54%]
2026-02-21T07:07:03.898987734Ztests/test_register_secret.py ............ [ 57%]
2026-02-21T07:07:04.434907317Ztests/test_secrets.py ................... [ 62%]
2026-02-21T07:07:09.978655641Ztests/test_secrets_local.py ............................ [ 69%]
2026-02-21T07:07:10.017141955Ztests/test_secrets_resolver.py ............................. [ 77%]
2026-02-21T07:07:14.98663339Ztests/test_secrets_server.py ........ [ 79%]
2026-02-21T07:07:48.38339842Ztests/test_source_preparation.py .F...F.FF...... [ 83%]
2026-02-21T07:07:48.481843507Ztests/test_validation.py ........................... [ 90%]
2026-02-21T07:07:48.659328458Ztests/test_workflow.py ..................................... [100%]
2026-02-21T07:07:48.659337168Z
2026-02-21T07:07:48.659342991Z=================================== FAILURES ===================================
2026-02-21T07:07:48.659348751Z_____________ TestEvalCommand.test_eval_pr_uses_base_ref_for_diff ______________
2026-02-21T07:07:48.659351615Z
2026-02-21T07:07:48.659356731Zself = <runnerlib.tests.test_eval_cli.TestEvalCommand object at 0x7f1f46206a80>
2026-02-21T07:07:48.659367218Ztemp_dirs = (PosixPath('/tmp/tmphyunmizn/ci'), PosixPath('/tmp/tmphyunmizn/src'), PosixPath('/tmp/tmphyunmizn/ci/.reactorcide/jobs'), PosixPath('/tmp/tmphyunmizn/triggers.json'))
2026-02-21T07:07:48.6599751Z
2026-02-21T07:07:48.659996505Z def test_eval_pr_uses_base_ref_for_diff(self, temp_dirs):
2026-02-21T07:07:48.660037355Z """Test that PR events use pr_base_ref for changed files diff."""
2026-02-21T07:07:48.660043695Z ci_dir, src_dir, jobs_dir, triggers_file = temp_dirs
2026-02-21T07:07:48.66023734Z
2026-02-21T07:07:48.66024547Z _write_yaml(jobs_dir / "test.yaml", {
2026-02-21T07:07:48.660249844Z "name": "test",
2026-02-21T07:07:48.660570911Z "triggers": {"events": ["pull_request_opened"]},
2026-02-21T07:07:48.661069932Z "job": {"image": "alpine:latest", "command": "make test"},
2026-02-21T07:07:48.661082948Z })
2026-02-21T07:07:48.661085668Z
2026-02-21T07:07:48.661090095Z (src_dir / ".git").mkdir()
2026-02-21T07:07:48.661092478Z
2026-02-21T07:07:48.661098295Z with patch("src.workflow.changed_files", return_value=["file.py"]) as mock_changed:
2026-02-21T07:07:48.661102042Z result = runner.invoke(app, [
2026-02-21T07:07:48.661395832Z "eval",
2026-02-21T07:07:48.661401315Z "--ci-source-dir", str(ci_dir),
2026-02-21T07:07:48.661404835Z "--source-dir", str(src_dir),
2026-02-21T07:07:48.661408922Z "--event-type", "pull_request_opened",
2026-02-21T07:07:48.661413829Z "--branch", "feature/foo",
2026-02-21T07:07:48.662114109Z "--pr-base-ref", "[REDACTED]",
2026-02-21T07:07:48.662119309Z "--triggers-file", str(triggers_file),
2026-02-21T07:07:48.662123296Z ])
2026-02-21T07:07:48.662126349Z
2026-02-21T07:07:48.662132466Z # Verify it was called with origin/[REDACTED] as the from_ref
2026-02-21T07:07:48.662694484Z> mock_changed.assert_called_once_with(
2026-02-21T07:07:48.662701934Z "origin/[REDACTED]", "HEAD", str(src_dir)
2026-02-21T07:07:48.662708034Z )
2026-02-21T07:07:48.662710302Z
2026-02-21T07:07:48.662714485Ztests/test_eval_cli.py:344:
2026-02-21T07:07:48.662718402Z_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2026-02-21T07:07:48.662723565Z/usr/local/lib/python3.13/unittest/mock.py:991: in assert_called_once_with
2026-02-21T07:07:48.663101162Z return self.assert_called_with(*args, **kwargs)
2026-02-21T07:07:48.663107762Z_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2026-02-21T07:07:48.663110056Z
2026-02-21T07:07:48.663114259Zself = <MagicMock name='changed_files' id='139772302321584'>
2026-02-21T07:07:48.663716918Zargs = ('origin/[REDACTED]', 'HEAD', '/tmp/tmphyunmizn/src'), kwargs = {}
2026-02-21T07:07:48.663725348Zexpected = call('origin/[REDACTED]', 'HEAD', '/tmp/tmphyunmizn/src')
2026-02-21T07:07:48.663731762Zactual = call('[REDACTED]', 'HEAD', '/tmp/tmphyunmizn/src')
2026-02-21T07:07:48.663738052Z_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f1f453f5d00>
2026-02-21T07:07:48.663741749Zcause = None
2026-02-21T07:07:48.663754569Z
2026-02-21T07:07:48.663758582Z def assert_called_with(self, /, *args, **kwargs):
2026-02-21T07:07:48.664134626Z """assert that the last call was made with the specified arguments.
2026-02-21T07:07:48.664139262Z
2026-02-21T07:07:48.664144759Z Raises an AssertionError if the args and keyword args passed in are
2026-02-21T07:07:48.66656122Z different to the last call to the mock."""
2026-02-21T07:07:48.666567083Z if self.call_args is None:
2026-02-21T07:07:48.66657228Z expected = self._format_mock_call_signature(args, kwargs)
2026-02-21T07:07:48.666576006Z actual = 'not called.'
2026-02-21T07:07:48.666581676Z error_message = ('expected call not found.\nExpected: %s\n Actual: %s'
2026-02-21T07:07:48.6665855Z % (expected, actual))
2026-02-21T07:07:48.666594206Z raise AssertionError(error_message)
2026-02-21T07:07:48.666597074Z
2026-02-21T07:07:48.666604797Z def _error_message():
2026-02-21T07:07:48.666609417Z msg = self._format_mock_failure_message(args, kwargs)
2026-02-21T07:07:48.666612801Z return msg
2026-02-21T07:07:48.666617007Z expected = self._call_matcher(_Call((args, kwargs), two=True))
2026-02-21T07:07:48.666621267Z actual = self._call_matcher(self.call_args)
2026-02-21T07:07:48.666626904Z if actual != expected:
2026-02-21T07:07:48.666633344Z cause = expected if isinstance(expected, Exception) else None
2026-02-21T07:07:48.668152396Z> raise AssertionError(_error_message()) from cause
2026-02-21T07:07:48.668160102ZE AssertionError: expected call not found.
2026-02-21T07:07:48.668169089ZE Expected: changed_files('origin/[REDACTED]', 'HEAD', '/tmp/tmphyunmizn/src')
2026-02-21T07:07:48.668184596ZE Actual: changed_files('[REDACTED]', 'HEAD', '/tmp/tmphyunmizn/src')
2026-02-21T07:07:48.668186962Z
2026-02-21T07:07:48.668191006Z/usr/local/lib/python3.13/unittest/mock.py:979: AssertionError
2026-02-21T07:07:48.668208237Z___________ TestEvalCommand.test_eval_push_uses_head_parent_for_diff ___________
2026-02-21T07:07:48.66821041Z
2026-02-21T07:07:48.668215193Zself = <runnerlib.tests.test_eval_cli.TestEvalCommand object at 0x7f1f46206b70>
2026-02-21T07:07:48.66822459Ztemp_dirs = (PosixPath('/tmp/tmpb_yxub0u/ci'), PosixPath('/tmp/tmpb_yxub0u/src'), PosixPath('/tmp/tmpb_yxub0u/ci/.reactorcide/jobs'), PosixPath('/tmp/tmpb_yxub0u/triggers.json'))
2026-02-21T07:07:48.66822673Z
2026-02-21T07:07:48.66823105Z def test_eval_push_uses_head_parent_for_diff(self, temp_dirs):
2026-02-21T07:07:48.66823564Z """Test that push events use HEAD^ for changed files diff."""
2026-02-21T07:07:48.668239757Z ci_dir, src_dir, jobs_dir, triggers_file = temp_dirs
2026-02-21T07:07:48.66824208Z
2026-02-21T07:07:48.668245837Z _write_yaml(jobs_dir / "test.yaml", {
2026-02-21T07:07:48.668251313Z "name": "test",
2026-02-21T07:07:48.668256793Z "triggers": {"events": ["push"]},
2026-02-21T07:07:48.668266657Z "job": {"image": "alpine:latest", "command": "make test"},
2026-02-21T07:07:48.668271127Z })
2026-02-21T07:07:48.668274157Z
2026-02-21T07:07:48.668872819Z (src_dir / ".git").mkdir()
2026-02-21T07:07:48.668877075Z
2026-02-21T07:07:48.668882439Z with patch("src.workflow.changed_files", return_value=["file.py"]) as mock_changed:
2026-02-21T07:07:48.668886096Z result = runner.invoke(app, [
2026-02-21T07:07:48.66889055Z "eval",
2026-02-21T07:07:48.66889498Z "--ci-source-dir", str(ci_dir),
2026-02-21T07:07:48.668898716Z "--source-dir", str(src_dir),
2026-02-21T07:07:48.669439981Z "--event-type", "push",
2026-02-21T07:07:48.669451058Z "--branch", "[REDACTED]",
2026-02-21T07:07:48.669456292Z "--triggers-file", str(triggers_file),
2026-02-21T07:07:48.669461112Z ])
2026-02-21T07:07:48.669464582Z
2026-02-21T07:07:48.66994747Z> mock_changed.assert_called_once_with(
2026-02-21T07:07:48.669954214Z "HEAD^", "HEAD", str(src_dir)
2026-02-21T07:07:48.669958274Z )
2026-02-21T07:07:48.66996061Z
2026-02-21T07:07:48.669965Ztests/test_eval_cli.py:372:
2026-02-21T07:07:48.66997027Z_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2026-02-21T07:07:48.670475445Z/usr/local/lib/python3.13/unittest/mock.py:991: in assert_called_once_with
2026-02-21T07:07:48.670481709Z return self.assert_called_with(*args, **kwargs)
2026-02-21T07:07:48.670508432Z_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2026-02-21T07:07:48.670511822Z
2026-02-21T07:07:48.670516632Zself = <MagicMock name='changed_files' id='139772302323600'>
2026-02-21T07:07:48.670520835Zargs = ('HEAD^', 'HEAD', '/tmp/tmpb_yxub0u/src'), kwargs = {}
2026-02-21T07:07:48.673954609Zexpected = call('HEAD^', 'HEAD', '/tmp/tmpb_yxub0u/src')
2026-02-21T07:07:48.673966243Zactual = call('[REDACTED]', 'HEAD', '/tmp/tmpb_yxub0u/src')
2026-02-21T07:07:48.673973179Z_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f1f453f4860>
2026-02-21T07:07:48.673977079Zcause = None
2026-02-21T07:07:48.673980466Z
2026-02-21T07:07:48.673985173Z def assert_called_with(self, /, *args, **kwargs):
2026-02-21T07:07:48.673992767Z """assert that the last call was made with the specified arguments.
2026-02-21T07:07:48.673995544Z
2026-02-21T07:07:48.674000977Z Raises an AssertionError if the args and keyword args passed in are
2026-02-21T07:07:48.674005344Z different to the last call to the mock."""
2026-02-21T07:07:48.674009017Z if self.call_args is None:
2026-02-21T07:07:48.674013827Z expected = self._format_mock_call_signature(args, kwargs)
2026-02-21T07:07:48.67401792Z actual = 'not called.'
2026-02-21T07:07:48.67402253Z error_message = ('expected call not found.\nExpected: %s\n Actual: %s'
2026-02-21T07:07:48.674026327Z % (expected, actual))
2026-02-21T07:07:48.674030084Z raise AssertionError(error_message)
2026-02-21T07:07:48.67403241Z
2026-02-21T07:07:48.67403665Z def _error_message():
2026-02-21T07:07:48.674041424Z msg = self._format_mock_failure_message(args, kwargs)
2026-02-21T07:07:48.674045044Z return msg
2026-02-21T07:07:48.67405008Z expected = self._call_matcher(_Call((args, kwargs), two=True))
2026-02-21T07:07:48.67405418Z actual = self._call_matcher(self.call_args)
2026-02-21T07:07:48.67405771Z if actual != expected:
2026-02-21T07:07:48.674062044Z cause = expected if isinstance(expected, Exception) else None
2026-02-21T07:07:48.67406612Z> raise AssertionError(_error_message()) from cause
2026-02-21T07:07:48.674069934ZE AssertionError: expected call not found.
2026-02-21T07:07:48.674673051ZE Expected: changed_files('HEAD^', 'HEAD', '/tmp/tmpb_yxub0u/src')
2026-02-21T07:07:48.674682227ZE Actual: changed_files('[REDACTED]', 'HEAD', '/tmp/tmpb_yxub0u/src')
2026-02-21T07:07:48.674684687Z
2026-02-21T07:07:48.674689131Z/usr/local/lib/python3.13/unittest/mock.py:979: AssertionError
2026-02-21T07:07:48.674694721Z___________ TestEvalCommand.test_eval_no_git_dir_skips_changed_files ___________
2026-02-21T07:07:48.674711501Z
2026-02-21T07:07:48.674716677Zself = <runnerlib.tests.test_eval_cli.TestEvalCommand object at 0x7f1f466318d0>
2026-02-21T07:07:48.674725561Ztemp_dirs = (PosixPath('/tmp/tmp9szcunwp/ci'), PosixPath('/tmp/tmp9szcunwp/src'), PosixPath('/tmp/tmp9szcunwp/ci/.reactorcide/jobs'), PosixPath('/tmp/tmp9szcunwp/triggers.json'))
2026-02-21T07:07:48.674728597Z
2026-02-21T07:07:48.674733627Z def test_eval_no_git_dir_skips_changed_files(self, temp_dirs):
2026-02-21T07:07:48.674739034Z """Test that eval skips changed files detection when no .git dir exists."""
2026-02-21T07:07:48.674760254Z ci_dir, src_dir, jobs_dir, triggers_file = temp_dirs
2026-02-21T07:07:48.674762834Z
2026-02-21T07:07:48.674767087Z _write_yaml(jobs_dir / "test.yaml", {
2026-02-21T07:07:48.674771431Z "name": "test",
2026-02-21T07:07:48.674775214Z "triggers": {"events": ["push"]},
2026-02-21T07:07:48.674779234Z "paths": {"include": ["src/**"]},
2026-02-21T07:07:48.674789435Z "job": {"image": "alpine:latest", "command": "make test"},
2026-02-21T07:07:48.674793338Z })
2026-02-21T07:07:48.675301407Z
2026-02-21T07:07:48.67531029Z # No .git directory - should skip changed files and still match
2026-02-21T07:07:48.675314743Z # (path filtering is skipped when changed_files is None)
2026-02-21T07:07:48.675318877Z result = runner.invoke(app, [
2026-02-21T07:07:48.675323033Z "eval",
2026-02-21T07:07:48.67532762Z "--ci-source-dir", str(ci_dir),
2026-02-21T07:07:48.675332433Z "--source-dir", str(src_dir),
2026-02-21T07:07:48.67533653Z "--event-type", "push",
2026-02-21T07:07:48.675605276Z "--triggers-file", str(triggers_file),
2026-02-21T07:07:48.675610773Z ])
2026-02-21T07:07:48.67561346Z
2026-02-21T07:07:48.675617536Z assert result.exit_code == 0
2026-02-21T07:07:48.675621086Z> assert triggers_file.exists()
2026-02-21T07:07:48.675624566ZE AssertionError: assert False
2026-02-21T07:07:48.675628423ZE + where False = exists()
2026-02-21T07:07:48.676097998ZE + where exists = PosixPath('/tmp/tmp9szcunwp/triggers.json').exists
2026-02-21T07:07:48.676101868Z
2026-02-21T07:07:48.676106028Ztests/test_eval_cli.py:400: AssertionError
2026-02-21T07:07:48.676110591Z________ TestEvalSourcePreparation.test_eval_clones_source_when_missing ________
2026-02-21T07:07:48.676113001Z
2026-02-21T07:07:48.676118928Zself = <runnerlib.tests.test_eval_cli.TestEvalSourcePreparation object at 0x7f1f466ab4d0>
2026-02-21T07:07:48.676121518Z
2026-02-21T07:07:48.676125495Z def test_eval_clones_source_when_missing(self):
2026-02-21T07:07:48.676436714Z """Test that eval clones source repo when .git dir doesn't exist."""
2026-02-21T07:07:48.677148048Z with tempfile.TemporaryDirectory() as tmpdir:
2026-02-21T07:07:48.677153511Z base = Path(tmpdir)
2026-02-21T07:07:48.677157348Z ci_dir = base / "ci"
2026-02-21T07:07:48.677166376Z src_dir = base / "src"
2026-02-21T07:07:48.677174616Z src_dir.mkdir() # Exists but no .git (like worker creates)
2026-02-21T07:07:48.677179572Z jobs_dir = ci_dir / ".reactorcide" / "jobs"
2026-02-21T07:07:48.677183436Z jobs_dir.mkdir(parents=True)
2026-02-21T07:07:48.677188219Z triggers_file = base / "triggers.json"
2026-02-21T07:07:48.677190732Z
2026-02-21T07:07:48.677195396Z # Create a fake "remote" source repo
2026-02-21T07:07:48.677199169Z remote_dir = base / "remote_src"
2026-02-21T07:07:48.677642064Z remote_dir.mkdir()
2026-02-21T07:07:48.677651767Z from git import Repo
2026-02-21T07:07:48.677669041Z remote_repo = Repo.init(remote_dir)
2026-02-21T07:07:48.677680934Z (remote_dir / "[REDACTED].py").write_text("print('hello')")
2026-02-21T07:07:48.677687004Z remote_repo.index.add(["[REDACTED].py"])
2026-02-21T07:07:48.677692821Z remote_repo.index.commit("Initial commit")
2026-02-21T07:07:48.677697097Z
2026-02-21T07:07:48.677703067Z _write_yaml(jobs_dir / "test.yaml", {
2026-02-21T07:07:48.678181051Z "name": "test",
2026-02-21T07:07:48.678187249Z "triggers": {"events": ["push"]},
2026-02-21T07:07:48.678192679Z "job": {"image": "alpine:latest", "command": "make test"},
2026-02-21T07:07:48.678196719Z })
2026-02-21T07:07:48.678199502Z
2026-02-21T07:07:48.678203692Z result = runner.invoke(app, [
2026-02-21T07:07:48.678207579Z "eval",
2026-02-21T07:07:48.678215436Z "--ci-source-dir", str(ci_dir),
2026-02-21T07:07:48.678219146Z "--source-dir", str(src_dir),
2026-02-21T07:07:48.678222639Z "--event-type", "push",
2026-02-21T07:07:48.678227592Z "--branch", "[REDACTED]",
2026-02-21T07:07:48.678716344Z "--source-url", str(remote_dir),
2026-02-21T07:07:48.678725177Z "--triggers-file", str(triggers_file),
2026-02-21T07:07:48.678731344Z ])
2026-02-21T07:07:48.678735761Z
2026-02-21T07:07:48.678741511Z> assert result.exit_code == 0
2026-02-21T07:07:48.678746751ZE AssertionError: assert 1 == 0
2026-02-21T07:07:48.678762775ZE + where 1 = <Result GitCommandError('git checkout [REDACTED]', 128)>.exit_code
2026-02-21T07:07:48.678907869Z
2026-02-21T07:07:48.678918229Ztests/test_eval_cli.py:567: AssertionError
2026-02-21T07:07:48.678926966Z_______________ TestJobIsolation.test_container_mount_isolation ________________
2026-02-21T07:07:48.679092778Z
2026-02-21T07:07:48.679102811Zself = <runnerlib.tests.test_job_isolation.TestJobIsolation object at 0x7f1f4620b820>
2026-02-21T07:07:48.679400001Zmock_popen = <MagicMock name='Popen' id='139772282208672'>
2026-02-21T07:07:48.679409488Z
2026-02-21T07:07:48.679413938Z @patch('subprocess.Popen')
2026-02-21T07:07:48.679422188Z def test_container_mount_isolation(self, mock_popen):
2026-02-21T07:07:48.679893606Z """Test that containers mount only their job's directory."""
2026-02-21T07:07:48.679901676Z # Mock the Popen object with proper behavior
2026-02-21T07:07:48.679905813Z mock_process = MagicMock()
2026-02-21T07:07:48.679911186Z mock_process.poll.side_effect = [None, None, 0] # Running, running, then finished
2026-02-21T07:07:48.680148282Z mock_process.returncode = 0
2026-02-21T07:07:48.680154902Z mock_process.stdout.readline.return_value = '' # No output (text mode)
2026-02-21T07:07:48.680159322Z mock_process.stderr.readline.return_value = '' # No errors
2026-02-21T07:07:48.680166345Z mock_process.communicate.return_value = ('', '') # Empty re[REDACTED]ing output
2026-02-21T07:07:48.680175152Z mock_popen.return_value = mock_process
2026-02-21T07:07:48.680177932Z
2026-02-21T07:07:48.680554759Z with tempfile.TemporaryDirectory() as temp_dir:
2026-02-21T07:07:48.680947163Z # Save original cwd if possible
2026-02-21T07:07:48.680955029Z try:
2026-02-21T07:07:48.680960989Z original_cwd = os.getcwd()
2026-02-21T07:07:48.680974746Z except FileNotFoundError:
2026-02-21T07:07:48.680979653Z # If current dir doesn't exist, use temp dir as fallback
2026-02-21T07:07:48.680983296Z original_cwd = temp_dir
2026-02-21T07:07:48.680986126Z
2026-02-21T07:07:48.680989536Z try:
2026-02-21T07:07:48.681381708Z os.chdir(temp_dir)
2026-02-21T07:07:48.681387994Z
2026-02-21T07:07:48.681394614Z config = RunnerConfig(
2026-02-21T07:07:48.681398594Z code_dir="/job/src",
2026-02-21T07:07:48.681401914Z job_dir="/job/src",
2026-02-21T07:07:48.684561848Z job_command="echo test",
2026-02-21T07:07:48.684569662Z runner_image="alpine:latest"
2026-02-21T07:07:48.684576905Z )
2026-02-21T07:07:48.684579995Z
2026-02-21T07:07:48.684584299Z # Prepare job directory
2026-02-21T07:07:48.684588739Z job_path = prepare_job_directory(config)
2026-02-21T07:07:48.684591279Z
2026-02-21T07:07:48.684594786Z # Create a test file
2026-02-21T07:07:48.684598976Z test_file = job_path / "test.txt"
2026-02-21T07:07:48.68460245Z test_file.write_text("test data")
2026-02-21T07:07:48.684606093Z
2026-02-21T07:07:48.68461174Z # Run container
2026-02-21T07:07:48.684616276Z> run_container(config)
2026-02-21T07:07:48.6846198Z
2026-02-21T07:07:48.68462536Z/workspace/runnerlib/tests/test_job_isolation.py:257:
2026-02-21T07:07:48.684631813Z_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2026-02-21T07:07:48.68463555Z
2026-02-21T07:07:48.68464674Zconfig = RunnerConfig(code_dir='/job/src', job_dir='/job/src', job_command='echo test', runner_image='alpine:latest', job_env=N...=None, source_type=None, source_url=None, source_ref=None, ci_source_type=None, ci_source_url=None, ci_source_ref=None)
2026-02-21T07:07:48.684653326Zadditional_args = None
2026-02-21T07:07:48.68465698Z
2026-02-21T07:07:48.684662153Z def run_container(
2026-02-21T07:07:48.684668153Z config: RunnerConfig,
2026-02-21T07:07:48.684674153Z additional_args: Optional[List[str]] = None
2026-02-21T07:07:48.684680076Z ) -> int:
2026-02-21T07:07:48.684688216Z """Run the job container using docker with full configuration support.
2026-02-21T07:07:48.684692403Z
2026-02-21T07:07:48.684698271Z Args:
2026-02-21T07:07:48.684704474Z config: Runner configuration
2026-02-21T07:07:48.684709474Z additional_args: Additional arguments to pass to the job command
2026-02-21T07:07:48.684711881Z
2026-02-21T07:07:48.684715094Z Returns:
2026-02-21T07:07:48.684718871Z Exit code of the container process
2026-02-21T07:07:48.684721451Z
2026-02-21T07:07:48.684725081Z Raises:
2026-02-21T07:07:48.684730967Z ValueError: If configuration is invalid
2026-02-21T07:07:48.684742194Z FileNotFoundError: If docker is not available
2026-02-21T07:07:48.684747144Z """
2026-02-21T07:07:48.684750781Z # Create plugin context for the execution
2026-02-21T07:07:48.684994389Z plugin_context = PluginContext(
2026-02-21T07:07:48.685001449Z config=config,
2026-02-21T07:07:48.685011213Z phase=PluginPhase.PRE_SOURCE_PREP,
2026-02-21T07:07:48.685015169Z metadata={}
2026-02-21T07:07:48.68571323Z )
2026-02-21T07:07:48.685718327Z
2026-02-21T07:07:48.685722597Z try:
2026-02-21T07:07:48.685727631Z # Execute pre-source-prep plugins
2026-02-21T07:07:48.685734114Z plugin_manager.execute_phase(PluginPhase.PRE_SOURCE_PREP, plugin_context)
2026-02-21T07:07:48.685736604Z
2026-02-21T07:07:48.685740927Z # Basic validation is handled by CLI layer
2026-02-21T07:07:48.685743141Z
2026-02-21T07:07:48.685746951Z # Check if docker is available
2026-02-21T07:07:48.685757004Z if not shutil.which("docker"):
2026-02-21T07:07:48.685761531Z logger.error("Docker is not available in PATH")
2026-02-21T07:07:48.685766721Z> raise FileNotFoundError("docker is not available in PATH")
2026-02-21T07:07:48.685905722ZE FileNotFoundError: docker is not available in PATH
2026-02-21T07:07:48.686095867Z
2026-02-21T07:07:48.68610398Z/workspace/runnerlib/src/container.py:114: FileNotFoundError
2026-02-21T07:07:48.68610933Z----------------------------- Captured stderr call -----------------------------
2026-02-21T07:07:48.686115087Z2026-02-21T07:07:03.701227+00:00 [ERROR] [runnerlib] Docker is not available in PATH
2026-02-21T07:07:48.686119564Z___________ TestSourcePreparation.test_no_source_preparation_default ___________
2026-02-21T07:07:48.686657803Z
2026-02-21T07:07:48.686671273Zself = <runnerlib.tests.test_source_preparation.TestSourcePreparation object at 0x7f1f466491d0>
2026-02-21T07:07:48.68667436Z
2026-02-21T07:07:48.686682776Z def test_no_source_preparation_default(self):
2026-02-21T07:07:48.68668823Z """Test job with no source preparation (default - source_type not set)."""
2026-02-21T07:07:48.686868775Z # Configure without specifying source_type
2026-02-21T07:07:48.686976343Z config = get_config(job_command="echo 'hello'")
2026-02-21T07:07:48.686980459Z
2026-02-21T07:07:48.686984469Z # Prepare source should return None
2026-02-21T07:07:48.686995273Z result = prepare_source(config)
2026-02-21T07:07:48.687349017Z> assert result is None
2026-02-21T07:07:48.687356077ZE AssertionError: assert PosixPath('/tmp/tmpy2338_yc/job/src') is None
2026-02-21T07:07:48.687591629Z
2026-02-21T07:07:48.687600015Z/workspace/runnerlib/tests/test_source_preparation.py:89: AssertionError
2026-02-21T07:07:48.687605005Z----------------------------- Captured stdout call -----------------------------
2026-02-21T07:07:48.688104195Z2026-02-21T07:07:15.012704+00:00 Cloning git repository: https://[REDACTED].com/[REDACTED].git
2026-02-21T07:07:48.688111508Z2026-02-21T07:07:25.910878+00:00 Checking out ref: [REDACTED]
2026-02-21T07:07:48.688222262Z2026-02-21T07:07:26.370166+00:00 Repository checked out to: /tmp/tmpy2338_yc/job/src
2026-02-21T07:07:48.688231796Z----------------------------- Captured stderr call -----------------------------
2026-02-21T07:07:48.688250022Z2026-02-21T07:07:15.012329+00:00 [INFO] [runnerlib] Preparing source type=git url=https://[REDACTED].com/[REDACTED].git ref=[REDACTED]
2026-02-21T07:07:48.688847148Z2026-02-21T07:07:15.012552+00:00 [INFO] [runnerlib] Preparing git source url=[REDACTED] ref=[REDACTED] target=/tmp/tmpy2338_yc/job/src
2026-02-21T07:07:48.688854958Z2026-02-21T07:07:26.369999+00:00 [INFO] [runnerlib] Git source prepared successfully path=/tmp/tmpy2338_yc/job/src
2026-02-21T07:07:48.688860071Z__________________ TestSourcePreparation.test_ci_source_only ___________________
2026-02-21T07:07:48.688862444Z
2026-02-21T07:07:48.689097564Zself = <runnerlib.tests.test_source_preparation.TestSourcePreparation object at 0x7f1f4662d8c0>
2026-02-21T07:07:48.689102977Z
2026-02-21T07:07:48.689108977Z def test_ci_source_only(self):
2026-02-21T07:07:48.68911674Z """Test preparation of CI source without regular source."""
2026-02-21T07:07:48.689616439Z # Create CI repo
2026-02-21T07:07:48.690195085Z ci_repo_dir = Path(self.temp_dir) / "ci_repo"
2026-02-21T07:07:48.690201858Z ci_repo_dir.mkdir()
2026-02-21T07:07:48.690208701Z ci_repo = Repo.init(ci_repo_dir)
2026-02-21T07:07:48.690215941Z (ci_repo_dir / "deploy.sh").write_text("#!/bin/bash\necho deploying")
2026-02-21T07:07:48.690219418Z ci_repo.index.add(["deploy.sh"])
2026-02-21T07:07:48.690770177Z ci_repo.index.commit("CI commit")
2026-02-21T07:07:48.690774441Z
2026-02-21T07:07:48.690778147Z # Configure with only CI source
2026-02-21T07:07:48.690781694Z config = get_config(
2026-02-21T07:07:48.690785801Z job_command="bash /job/ci/deploy.sh",
2026-02-21T07:07:48.690864952Z ci_source_type="git",
2026-02-21T07:07:48.690871832Z ci_source_url=str(ci_repo_dir),
2026-02-21T07:07:48.691191681Z ci_source_ref="[REDACTED]"
2026-02-21T07:07:48.691198575Z )
2026-02-21T07:07:48.691201758Z
2026-02-21T07:07:48.691285272Z # Prepare CI source
2026-02-21T07:07:48.691292669Z ci_result = prepare_ci_source(config)
2026-02-21T07:07:48.692082244Z assert ci_result is not None
2026-02-21T07:07:48.692090207Z assert (ci_result / "deploy.sh").exists()
2026-02-21T07:07:48.692094487Z
2026-02-21T07:07:48.692099867Z # Prepare regular source (should return None)
2026-02-21T07:07:48.692105454Z source_result = prepare_source(config)
2026-02-21T07:07:48.692726956Z> assert source_result is None
2026-02-21T07:07:48.69273756ZE AssertionError: assert PosixPath('/tmp/tmpvakaz0h4/job/src') is None
2026-02-21T07:07:48.69274144Z
2026-02-21T07:07:48.69274848Z/workspace/runnerlib/tests/test_source_preparation.py:212: AssertionError
2026-02-21T07:07:48.692754894Z----------------------------- Captured stdout call -----------------------------
2026-02-21T07:07:48.692762237Z2026-02-21T07:07:26.952394+00:00 🔐 Preparing trusted CI source (type: git)
2026-02-21T07:07:48.692770114Z2026-02-21T07:07:26.952597+00:00 Cloning git repository: /tmp/tmpvakaz0h4/ci_repo
2026-02-21T07:07:48.692778171Z2026-02-21T07:07:26.998284+00:00 Checking out ref: [REDACTED]
2026-02-21T07:07:48.692927142Z2026-02-21T07:07:27.014551+00:00 Repository checked out to: /tmp/tmpvakaz0h4/job/ci
2026-02-21T07:07:48.692934502Z2026-02-21T07:07:27.015318+00:00 Cloning git repository: [REDACTED]
2026-02-21T07:07:48.693529444Z2026-02-21T07:07:36.868778+00:00 Checking out ref: [REDACTED]
2026-02-21T07:07:48.693541454Z2026-02-21T07:07:37.337982+00:00 Repository checked out to: /tmp/tmpvakaz0h4/job/src
2026-02-21T07:07:48.693549108Z----------------------------- Captured stderr call -----------------------------
2026-02-21T07:07:48.694041163Z2026-02-21T07:07:26.952245+00:00 [INFO] [runnerlib] Preparing CI source type=git url=/tmp/tmpvakaz0h4/ci_repo ref=[REDACTED]
2026-02-21T07:07:48.694055533Z2026-02-21T07:07:26.952525+00:00 [INFO] [runnerlib] Preparing git source url=/tmp/tmpvakaz0h4/ci_repo ref=[REDACTED] target=/tmp/tmpvakaz0h4/job/ci
2026-02-21T07:07:48.69406489Z2026-02-21T07:07:27.014416+00:00 [INFO] [runnerlib] Git source prepared successfully path=/tmp/tmpvakaz0h4/job/ci
2026-02-21T07:07:48.694079517Z2026-02-21T07:07:27.015126+00:00 [INFO] [runnerlib] Preparing source type=git url=https://[REDACTED].com/[REDACTED].git ref=[REDACTED]
2026-02-21T07:07:48.694190221Z2026-02-21T07:07:27.015248+00:00 [INFO] [runnerlib] Preparing git source url=[REDACTED] ref=[REDACTED] target=/tmp/tmpvakaz0h4/job/src
2026-02-21T07:07:48.694201288Z2026-02-21T07:07:37.337838+00:00 [INFO] [runnerlib] Git source prepared successfully path=/tmp/tmpvakaz0h4/job/src
2026-02-21T07:07:48.694209578Z______________ TestSourcePreparation.test_git_source_missing_url _______________
2026-02-21T07:07:48.694213905Z
2026-02-21T07:07:48.694221808Zself = <runnerlib.tests.test_source_preparation.TestSourcePreparation object at 0x7f1f4675c150>
2026-02-21T07:07:48.69479108Z
2026-02-21T07:07:48.694806206Z def test_git_source_missing_url(self):
2026-02-21T07:07:48.694816306Z """Test that git source without URL raises ValueError."""
2026-02-21T07:07:48.694822864Z config = get_config(
2026-02-21T07:07:48.694928561Z job_command="echo 'test'",
2026-02-21T07:07:48.694936749Z source_type="git"
2026-02-21T07:07:48.694943369Z # source_url not provided
2026-02-21T07:07:48.69550749Z )
2026-02-21T07:07:48.695515711Z
2026-02-21T07:07:48.695523211Z> with pytest.raises(ValueError, match="source_url is required"):
2026-02-21T07:07:48.695528904ZE Failed: DID NOT RAISE <class 'ValueError'>
2026-02-21T07:07:48.695889698Z
2026-02-21T07:07:48.695904802Z/workspace/runnerlib/tests/test_source_preparation.py:233: Failed
2026-02-21T07:07:48.695913725Z----------------------------- Captured stdout call -----------------------------
2026-02-21T07:07:48.695926745Z2026-02-21T07:07:37.490767+00:00 Cloning git repository: [REDACTED]
2026-02-21T07:07:48.695934968Z2026-02-21T07:07:46.758055+00:00 Checking out ref: [REDACTED]
2026-02-21T07:07:48.696541424Z2026-02-21T07:07:47.634591+00:00 Repository checked out to: /tmp/tmp7p79op4a/job/src
2026-02-21T07:07:48.696551524Z----------------------------- Captured stderr call -----------------------------
2026-02-21T07:07:48.696563728Z2026-02-21T07:07:37.490495+00:00 [INFO] [runnerlib] Preparing source type=git url=[REDACTED] ref=[REDACTED]
2026-02-21T07:07:48.696584614Z2026-02-21T07:07:37.490686+00:00 [INFO] [runnerlib] Preparing git source url=https://[REDACTED].com/[REDACTED].git ref=[REDACTED] target=/tmp/tmp7p79op4a/job/src
2026-02-21T07:07:48.697393759Z2026-02-21T07:07:47.634424+00:00 [INFO] [runnerlib] Git source prepared successfully path=/tmp/tmp7p79op4a/job/src
2026-02-21T07:07:48.697404872Z______________ TestSourcePreparation.test_copy_source_missing_url ______________
2026-02-21T07:07:48.697409086Z
2026-02-21T07:07:48.697417172Zself = <runnerlib.tests.test_source_preparation.TestSourcePreparation object at 0x7f1f4675c250>
2026-02-21T07:07:48.697421019Z
2026-02-21T07:07:48.697427366Z def test_copy_source_missing_url(self):
2026-02-21T07:07:48.697435142Z """Test that copy source without URL raises ValueError."""
2026-02-21T07:07:48.697442029Z config = get_config(
2026-02-21T07:07:48.697447777Z job_command="echo 'test'",
2026-02-21T07:07:48.697453323Z source_type="copy"
2026-02-21T07:07:48.697458663Z # source_url not provided
2026-02-21T07:07:48.697994532Z )
2026-02-21T07:07:48.698007712Z
2026-02-21T07:07:48.698016713Z with pytest.raises(ValueError, match="source_url is required"):
2026-02-21T07:07:48.698022786Z> prepare_source(config)
2026-02-21T07:07:48.698026553Z
2026-02-21T07:07:48.698033603Z/workspace/runnerlib/tests/test_source_preparation.py:245:
2026-02-21T07:07:48.698402083Z_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2026-02-21T07:07:48.69841101Z/workspace/runnerlib/src/source_prep.py:571: in prepare_source
2026-02-21T07:07:48.698417726Z return _prepare_copy_source(config.source_url, target_path)
2026-02-21T07:07:48.69842452Z_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2026-02-21T07:07:48.69842949Z
2026-02-21T07:07:48.698736763Zsource_url = 'https://[REDACTED].com/[REDACTED].git'
2026-02-21T07:07:48.698748176Ztarget_path = PosixPath('/tmp/tmpkko9dy8x/job/src')
2026-02-21T07:07:48.698768706Z
2026-02-21T07:07:48.69877746Z def _prepare_copy_source(source_url: str, target_path: Path) -> Path:
2026-02-21T07:07:48.699107249Z """Prepare source code by copying from a local directory.
2026-02-21T07:07:48.699114686Z
2026-02-21T07:07:48.699123936Z Args:
2026-02-21T07:07:48.699630349Z source_url: Path to source directory
2026-02-21T07:07:48.699640275Z target_path: Where to copy the directory
2026-02-21T07:07:48.699645635Z
2026-02-21T07:07:48.699659089Z Returns:
2026-02-21T07:07:48.699665879Z Path to the copied directory
2026-02-21T07:07:48.699671775Z """
2026-02-21T07:07:48.699933071Z source_path = Path(source_url).resolve()
2026-02-21T07:07:48.699940977Z
2026-02-21T07:07:48.700213008Z if not source_path.exists():
2026-02-21T07:07:48.700223235Z> raise FileNotFoundError(f"Source directory does not exist: {source_path}")
2026-02-21T07:07:48.700714748ZE FileNotFoundError: Source directory does not exist: /tmp/tmpkko9dy8x/https:/[REDACTED].com/[REDACTED].git
2026-02-21T07:07:48.700721794Z
2026-02-21T07:07:48.700728963Z/workspace/runnerlib/src/source_prep.py:436: FileNotFoundError
2026-02-21T07:07:48.700747493Z----------------------------- Captured stderr call -----------------------------
2026-02-21T07:07:48.700759312Z2026-02-21T07:07:47.766525+00:00 [INFO] [runnerlib] Preparing source type=copy url=[REDACTED] ref=[REDACTED]
2026-02-21T07:07:48.700765942Z=========================== short test summary info ============================
2026-02-21T07:07:48.701297465ZFAILED tests/test_eval_cli.py::TestEvalCommand::test_eval_pr_uses_base_ref_for_diff
2026-02-21T07:07:48.701305689ZFAILED tests/test_eval_cli.py::TestEvalCommand::test_eval_push_uses_head_parent_for_diff
2026-02-21T07:07:48.701311236ZFAILED tests/test_eval_cli.py::TestEvalCommand::test_eval_no_git_dir_skips_changed_files
2026-02-21T07:07:48.701322729ZFAILED tests/test_eval_cli.py::TestEvalSourcePreparation::test_eval_clones_source_when_missing
2026-02-21T07:07:48.701415066ZFAILED tests/test_job_isolation.py::TestJobIsolation::test_container_mount_isolation
2026-02-21T07:07:48.701425454ZFAILED tests/test_source_preparation.py::TestSourcePreparation::test_no_source_preparation_default
2026-02-21T07:07:48.701433103ZFAILED tests/test_source_preparation.py::TestSourcePreparation::test_ci_source_only
2026-02-21T07:07:48.7018461ZFAILED tests/test_source_preparation.py::TestSourcePreparation::test_git_source_missing_url
2026-02-21T07:07:48.701856643ZFAILED tests/test_source_preparation.py::TestSourcePreparation::test_copy_source_missing_url
2026-02-21T07:07:48.701945258Z================== 9 failed, 372 passed in 156.80s (0:02:36) ===================