from __future__ import annotations import json import tempfile import unittest from pathlib import Path from unittest.mock import patch from moli_benchmark.process import ProcessResult from moli_benchmark.public_web import POST_DCL_WAIT_SCRIPT from moli_benchmark.wild_web import ( _classify, _extract_page_snapshot, _failure_kind, _rotated_target_order, _wild_command_for_target, _wild_web_target_metadata, _wild_web_extraction_failures, run_wild_web_suite, ) class WildWebTests(unittest.TestCase): def test_target_order_rotates_per_seed(self) -> None: targets = ("moli", "lightpanda", "chrome") self.assertEqual(_rotated_target_order(targets, 0), targets) self.assertEqual( _rotated_target_order(targets, 1), ("lightpanda", "chrome", "moli"), ) def test_obscura_wild_web_command_uses_fetch_timeout_seconds(self) -> None: command = _wild_command_for_target("obscura", Path("/bin/obscura"), "https://example.test/", 7.9) self.assertEqual(command[:4], ["/bin/obscura", "fetch", "--dump", "html"]) self.assertIn("--wait-until", command) self.assertEqual(command[command.index("--wait") + 1], "0") self.assertIn("--timeout", command) self.assertEqual(command[command.index("--timeout") + 1], "7") self.assertEqual(command[-1], "https://example.test/") def test_lightpanda_wild_web_command_aligns_fetch_timeouts(self) -> None: command = _wild_command_for_target("lightpanda", Path("/bin/lightpanda"), "https://example.test/", 30.0) self.assertEqual(command[:4], ["/bin/lightpanda", "fetch", "--dump", "html"]) self.assertEqual( command[command.index("--wait-until") + 1], "domcontentloaded", ) self.assertEqual( command[command.index("--wait-script") + 1], POST_DCL_WAIT_SCRIPT, ) self.assertEqual(command[command.index("--wait-ms") + 1], "30000") self.assertEqual(command[command.index("--http-timeout") + 1], "30000") self.assertEqual(command[command.index("--terminate-ms") + 1], "30000") self.assertNotIn("--wait_until", command) self.assertNotIn("--wait_ms", command) self.assertNotIn("--http_timeout", command) self.assertEqual(command[-1], "https://example.test/") def test_moli_wild_web_command_uses_the_same_dcl_boundary(self) -> None: command = _wild_command_for_target( "moli", Path("/bin/moli"), "https://example.test/", 30.0, ) self.assertEqual( command[command.index("--wait-until") + 1], "domcontentloaded", ) self.assertEqual( command[command.index("--wait-script") + 1], POST_DCL_WAIT_SCRIPT, ) self.assertEqual(command[command.index("--timeout") + 1], "30000") self.assertEqual(command[command.index("--http-timeout") + 1], "30000") def test_wild_web_chrome_uses_cdp_dcl_metadata(self) -> None: self.assertEqual(_wild_web_target_metadata("chrome")["driver"], "cdp-dcl") self.assertEqual(_wild_web_target_metadata("chrome")["label"], "chrome / cdp-dcl") self.assertEqual(_wild_web_target_metadata("obscura-cdp")["driver"], "cdp-dcl") self.assertEqual(_wild_web_target_metadata("obscura-cdp")["label"], "obscura / cdp-dcl") with self.assertRaisesRegex(RuntimeError, "CDP DCL runner"): _wild_command_for_target("chrome", Path("/bin/chromium"), "https://example.test/", 7.9) def test_wild_web_accepts_obscura_cdp_dcl_target(self) -> None: def fake_cdp_dump(*args: object, **kwargs: object) -> ProcessResult: return ProcessResult( command=["/bin/obscura", "serve", "--port", "12345"], returncode=0, elapsed_ms=12.0, stdout="知乎知乎 首页 内容 推荐 回答 专栏 热榜 发现 等你来答".encode(), stderr=b"", timed_out=False, resources={"peak_pss_bytes": 123}, ) with tempfile.TemporaryDirectory() as temp_dir: with patch( "moli_benchmark.wild_web.run_served_cdp_dcl_dump", side_effect=fake_cdp_dump, ) as cdp_dump: summary = run_wild_web_suite( output_dir=Path(temp_dir), target_matrix={"obscura": {"available": True, "path": "/bin/obscura"}}, targets=("obscura-cdp",), seeds=("zhihu-home",), runs=1, timeout_seconds=1.0, gate_target="obscura-cdp", ) cdp_dump.assert_called_once() self.assertEqual(cdp_dump.call_args.args[:2], ("obscura-cdp", Path("/bin/obscura"))) self.assertEqual(summary["gate_failures"], 0) self.assertEqual(summary["targets"]["obscura-cdp"]["driver"], "cdp-dcl") def test_extraction_assertions_accept_expected_seed_keywords(self) -> None: snapshot = _extract_page_snapshot( """ 知乎 - 有问题,就会有答案
知乎 首页 内容 推荐 回答 专栏 热榜 发现 等你来答
""".encode() ) self.assertEqual(snapshot["title"], "知乎 - 有问题,就会有答案") self.assertIn("知乎 首页", snapshot["text_sample"]) self.assertEqual(_wild_web_extraction_failures("zhihu-home", snapshot), []) def test_seed_brand_is_required_in_title_but_not_repeated_in_body(self) -> None: snapshot = _extract_page_snapshot( b"Baidu" + b"useful navigation content " * 20 + b"" ) self.assertEqual(_wild_web_extraction_failures("baidu-home", snapshot), []) def test_extraction_assertions_report_missing_business_fields(self) -> None: snapshot = _extract_page_snapshot(b"Exampletiny") self.assertEqual( _wild_web_extraction_failures("toutiao-home", snapshot), ["title-keyword-mismatch", "short-body-text"], ) self.assertEqual(_failure_kind("success", ["title-keyword-mismatch"]), "extraction-failure") def test_snapshot_does_not_count_title_as_body_text(self) -> None: snapshot = _extract_page_snapshot( b"A long titleshort body" ) self.assertEqual(snapshot["title"], "A long title") self.assertEqual(snapshot["text_sample"], "short body") self.assertEqual(snapshot["text_length"], len("short body")) def test_classify_ignores_blocked_markers_inside_scripts_when_visible_content_exists( self, ) -> None: html = ( b"bilibili" b"
bilibili homepage video feed
" b"" b"" ) self.assertEqual(_classify(html, b"", 0, False), "success") def test_classify_detects_visible_blocked_pages(self) -> None: html = b"403 Forbiddenrequest blocked" self.assertEqual(_classify(html, b"", 0, False), "blocked") def test_classify_rejects_contentful_http_error_response(self) -> None: html = ( b"upstream response" + b"error details " * 100 + b"" ) self.assertEqual( _classify(html, b"", 0, False, response_status=500), "http-error", ) self.assertEqual(_failure_kind("http-error", []), "http-error") def test_classify_infers_cli_error_documents_and_network_failures(self) -> None: gateway = b"502 Bad Gatewayorigin unavailable" api_error = ( b"
"
            b'{"error":{"message":"invalid query"}}'
            b"
" ) tls_error = b"Navigation failed Reason: PeerFailedVerification" chinese_verification = "环境异常,完成验证后即可继续访问".encode() self.assertEqual(_classify(gateway, b"", 0, False), "http-error") self.assertEqual(_classify(api_error, b"", 0, False), "http-error") self.assertEqual(_classify(tls_error, b"", 0, False), "network-error") self.assertEqual(_failure_kind("network-error", []), "network-error") self.assertEqual( _classify(chinese_verification, b"", 0, False), "challenge", ) def test_classify_recognizes_lightpanda_transport_and_waf_documents(self) -> None: dns = ( b"

Navigation failed

" b"

Reason: CouldntResolveHost

" ) http2 = ( b"

Navigation failed

" b"

Reason: Http2Stream

" ) safeline = ( b"Security Detection Powered By SafeLine WAF" b"" ) privacy = ( b"Select the 2 matching tiles Submit " b"Powered and protected by Privacy" ) self.assertEqual(_classify(dns, b"", 0, False), "network-error") self.assertEqual(_classify(http2, b"", 0, False), "network-error") self.assertEqual(_classify(safeline, b"", 0, False), "blocked") self.assertEqual(_classify(privacy, b"", 0, False), "challenge") def test_classify_recognizes_lightpanda_fatal_fetch_timeout(self) -> None: stderr = ( b'$scope=app $level=fatal $msg="fetch error" err=Timeout ' b"url=https://example.test/" ) self.assertEqual(_classify(b"", stderr, 0, False), "timeout") def test_classify_preserves_cli_main_document_status_and_dns_reason(self) -> None: self.assertEqual( _classify( b"", b"Reason: lifecycle target document `https://example.test/` " b"returned 500 Internal Server Error", 1, False, ), "http-error", ) self.assertEqual( _classify( b"", b"Reason: lifecycle target document `https://example.test/` " b"returned 401 Unauthorized", 1, False, ), "blocked", ) self.assertEqual( _classify( b"", b"Reason: failed to resolve example.test:443: failed to lookup " b"address information", 1, False, ), "network-error", ) def test_run_wild_web_suite_writes_failure_snapshots(self) -> None: def run_process(*args: object, **kwargs: object) -> ProcessResult: return ProcessResult( command=["fake"], returncode=0, elapsed_ms=12.0, stdout=b"Exampletiny", stderr=b"", timed_out=False, resources={"peak_pss_bytes": 123}, ) with tempfile.TemporaryDirectory() as temp_dir: output_dir = Path(temp_dir) with patch("moli_benchmark.wild_web.run_process", run_process): summary = run_wild_web_suite( output_dir=output_dir, target_matrix={"moli": {"available": True, "path": "/bin/echo"}}, targets=("moli",), seeds=("toutiao-home",), runs=1, timeout_seconds=1.0, gate_target="moli", ) failures_dir = output_dir / "wild-web" / "failures" failure_files = sorted(path.name for path in failures_dir.iterdir()) rows = json.loads( (output_dir / "wild-web" / "runs.json").read_text( encoding="utf-8" ) ) self.assertEqual(summary["gate_failures"], 1) self.assertEqual(summary["targets"]["moli"]["failure_kinds"], {"extraction-failure": 1}) self.assertEqual(summary["targets"]["moli"]["extraction_failures"], 2) self.assertEqual(summary["schedule"], "site-paired-rotating-target-order") self.assertEqual(summary["scheduled_site_groups"], 1) self.assertEqual(rows[0]["schedule_index"], 0) self.assertEqual(rows[0]["target_order_index"], 1) self.assertTrue(rows[0]["started_at"].endswith("Z")) self.assertEqual(len(rows[0]["stdout_sha256"]), 64) self.assertEqual(len(rows[0]["stderr_sha256"]), 64) self.assertIn("moli-run-1-toutiao-home.json", failure_files) self.assertIn("moli-run-1-toutiao-home.stdout.html", failure_files) def test_acceptable_login_result_does_not_count_as_failure_kind(self) -> None: def run_process(*args: object, **kwargs: object) -> ProcessResult: return ProcessResult( command=["fake"], returncode=0, elapsed_ms=12.0, stdout="知乎知乎 首页 登录 内容 推荐 回答 专栏".encode(), stderr=b"", timed_out=False, resources={"peak_pss_bytes": 123}, ) with tempfile.TemporaryDirectory() as temp_dir: output_dir = Path(temp_dir) with patch("moli_benchmark.wild_web.run_process", run_process): summary = run_wild_web_suite( output_dir=output_dir, target_matrix={"moli": {"available": True, "path": "/bin/echo"}}, targets=("moli",), seeds=("zhihu-home",), runs=1, timeout_seconds=1.0, gate_target="moli", ) self.assertEqual(summary["gate_failures"], 0) self.assertEqual(summary["targets"]["moli"]["categories"], {"login": 1}) self.assertEqual(summary["targets"]["moli"]["failure_kinds"], {}) self.assertEqual(summary["targets"]["moli"]["elapsed_ms"]["count"], 1) self.assertEqual( summary["targets"]["moli"]["successful_elapsed_ms"]["count"], 1, ) self.assertEqual(summary["common_success"]["attempts"], 1) def test_capture_replay_writes_manifest_for_successful_rows(self) -> None: def run_process(*args: object, **kwargs: object) -> ProcessResult: return ProcessResult( command=["fake"], returncode=0, elapsed_ms=12.0, stdout="知乎知乎 首页 内容 推荐 回答 专栏 热榜 发现 等你来答".encode(), stderr=b"", timed_out=False, resources={"peak_pss_bytes": 123}, ) with tempfile.TemporaryDirectory() as temp_dir: output_dir = Path(temp_dir) with patch("moli_benchmark.wild_web.run_process", run_process): summary = run_wild_web_suite( output_dir=output_dir, target_matrix={"moli": {"available": True, "path": "/bin/echo"}}, targets=("moli",), seeds=("zhihu-home",), runs=1, timeout_seconds=1.0, gate_target="moli", capture_replay=True, ) replay_manifest = output_dir / "wild-web" / "replay" / "manifest.json" replay_html = output_dir / "wild-web" / "replay" / "moli-run-1-zhihu-home.html" replay_manifest_exists = replay_manifest.exists() replay_html_exists = replay_html.exists() self.assertEqual(summary["gate_failures"], 0) self.assertTrue(summary["replay_capture"]) self.assertEqual(summary["replay_artifacts"], 1) self.assertTrue(replay_manifest_exists) self.assertTrue(replay_html_exists) if __name__ == "__main__": unittest.main()