import os import subprocess from unittest import mock import pytest from test_fixtures.runner import ( _parse_args, build_pytest_args, discover_rie_endpoint, main, RIEDiscoveryError, ) def _build(argv, *, ddtrace): args, extra = _parse_args(argv) return build_pytest_args(args, extra, ddtrace=ddtrace) def test_default_is_parallel_with_report_and_ddtrace(): out = _build([], ddtrace=True) assert out[:3] == ['-v', '-W', 'ignore::pytest.PytestAssertRewriteWarning'] assert out[3:7] == ['-n', 'auto', '--dist', 'loadfile'] assert '--html=report/report.html' in out assert '--self-contained-html' in out assert '--ddtrace' in out def test_serial_disables_parallelism(): out = _build(['--serial'], ddtrace=True) assert '-n' not in out assert '--dist' not in out def test_no_report_omits_html(): out = _build(['--no-report'], ddtrace=False) assert not any(a.startswith('--html') for a in out) assert '--self-contained-html' not in out def test_custom_report_path(): out = _build(['--report', 'out/r.html'], ddtrace=False) assert '--html=out/r.html' in out def test_ddtrace_only_when_available(): assert '--ddtrace' not in _build([], ddtrace=False) def test_no_ddtrace_flag_overrides_availability(): assert '--ddtrace' not in _build(['--no-ddtrace'], ddtrace=True) def test_unknown_args_pass_through_to_pytest(): out = _build(['-k', 'test_x', 'tests/finalize-job'], ddtrace=False) assert '-k' in out and 'test_x' in out and 'tests/finalize-job' in out def test_main_sets_env_and_invokes_pytest(monkeypatch): monkeypatch.delenv('LAMBDA_FUNCTION_NAMES', raising=False) monkeypatch.delenv('LAMBDA_ENDPOINT_URL', raising=False) captured: dict[str, list[str]] = {} def fake_main(args): captured['args'] = args return 3 monkeypatch.setattr(pytest, 'main', fake_main) rc = main( [ '--lambda', 'finalize-job', '--endpoint-url', 'http://localhost:9002', '--serial', ] ) assert rc == 3 assert os.environ['LAMBDA_FUNCTION_NAMES'] == 'finalize-job' assert os.environ['LAMBDA_ENDPOINT_URL'] == 'http://localhost:9002' assert '-n' not in captured['args'] def test_main_creates_report_directory(monkeypatch, tmp_path): monkeypatch.setattr(pytest, 'main', lambda args: 0) report = tmp_path / 'report' / 'report.html' main(['--serial', '--no-ddtrace', '--report', str(report)]) assert report.parent.is_dir() def test_main_no_report_does_not_create_directory(monkeypatch, tmp_path): monkeypatch.setattr(pytest, 'main', lambda args: 0) report = tmp_path / 'report' / 'report.html' main(['--no-report', '--report', str(report)]) assert not report.parent.exists() def _fake_run(stdout='', returncode=0, stderr=''): return mock.Mock( spec=subprocess.CompletedProcess, stdout=stdout, stderr=stderr, returncode=returncode, ) def test_discover_rie_endpoint_parses_port(): run = mock.Mock(return_value=_fake_run(stdout='0.0.0.0:9002\n')) endpoint = discover_rie_endpoint('finalize-job', run=run) assert endpoint == 'http://localhost:9002' run.assert_called_once_with( [ 'docker', 'compose', '--project-name', 'rie-finalize-job', 'port', 'finalize-job', '8080', ], capture_output=True, text=True, ) def test_discover_rie_endpoint_uses_explicit_project_name(): run = mock.Mock(return_value=_fake_run(stdout='0.0.0.0:9002\n')) endpoint = discover_rie_endpoint( 'finalize-job', project_name='custom-project', run=run ) assert endpoint == 'http://localhost:9002' run.assert_called_once_with( [ 'docker', 'compose', '--project-name', 'custom-project', 'port', 'finalize-job', '8080', ], capture_output=True, text=True, ) def test_discover_rie_endpoint_raises_when_not_running(): run = mock.Mock(return_value=_fake_run(stdout='', returncode=1, stderr='oops')) with pytest.raises(RIEDiscoveryError, match='finalize-job'): discover_rie_endpoint('finalize-job', run=run) def test_discover_rie_endpoint_raises_on_empty_output(): run = mock.Mock(return_value=_fake_run(stdout=' \n', returncode=0)) with pytest.raises(RIEDiscoveryError): discover_rie_endpoint('finalize-job', run=run) def test_endpoint_url_and_rie_are_mutually_exclusive(): with pytest.raises(SystemExit): _parse_args(['--endpoint-url', 'http://x', '--rie', '--lambda', 'a']) def test_rie_requires_single_lambda(monkeypatch): monkeypatch.setattr(pytest, 'main', lambda args: 0) with pytest.raises(SystemExit, match='--rie requires --lambda'): main(['--rie']) with pytest.raises(SystemExit, match='--rie requires --lambda'): main(['--rie', '--lambda', 'a,b']) def test_main_rie_discovers_and_sets_endpoint(monkeypatch): monkeypatch.delenv('LAMBDA_ENDPOINT_URL', raising=False) monkeypatch.setattr(pytest, 'main', lambda args: 0) monkeypatch.setattr( 'test_fixtures.runner.discover_rie_endpoint', lambda lambda_name, project_name=None: f'http://localhost:9999-{lambda_name}', ) main(['--lambda', 'finalize-job', '--rie', '--serial']) assert os.environ['LAMBDA_ENDPOINT_URL'] == 'http://localhost:9999-finalize-job' def test_main_rie_passes_through_rie_project(monkeypatch): monkeypatch.delenv('LAMBDA_ENDPOINT_URL', raising=False) monkeypatch.setattr(pytest, 'main', lambda args: 0) captured = {} def fake_discover(lambda_name, project_name=None): captured['lambda_name'] = lambda_name captured['project_name'] = project_name return 'http://localhost:9999' monkeypatch.setattr('test_fixtures.runner.discover_rie_endpoint', fake_discover) main( [ '--lambda', 'finalize-job', '--rie', '--rie-project', 'custom-project', '--serial', ] ) assert captured == {'lambda_name': 'finalize-job', 'project_name': 'custom-project'}