# -*- coding: utf-8 -*- """拆分后 rrpp_core 的独立回归测试(不依赖 Qt 或真实代理连接)。""" import sys import tempfile import unittest from pathlib import Path LITE_DIR = Path(__file__).resolve().parent.parent sys.path.insert(0, str(LITE_DIR)) from rrpp_core.forwarder_primitives import ( force_http_close, inject_proxy_auth, parse_connect_authority, parse_http_absolute, ) from rrpp_core.node_api import NodeAuthError, b64url from rrpp_core.node_secrets import NodeSecretsStore from rrpp_core.network_primitives import is_private_host, is_private_ipv4_int, ttl_cache from rrpp_core.pac_data import atomic_write, read_version, validate_document from rrpp_core.routing_primitives import ( build_suffix_trie, merge_ip_ranges, parse_domain_rules, suffix_trie_matches, ) from rrpp_core.settings_store import JsonSettingsStore from rrpp_core.traffic import TrafficStats, format_bytes class CoreModuleTests(unittest.TestCase): def test_domain_rules_and_trie(self): suffixes, exact, regexes, invalid = parse_domain_rules( ["example.com", "full:only.example", "regexp:^edge-[0-9]+\\.example$", "regexp:["] ) self.assertEqual(invalid, 1) self.assertIn("example.com", suffixes) self.assertIn("only.example", exact) self.assertTrue(regexes[0].search("edge-42.example")) trie = build_suffix_trie(suffixes) self.assertTrue(suffix_trie_matches("cdn.example.com", trie)) self.assertFalse(suffix_trie_matches("example.net", trie)) self.assertEqual( merge_ip_ranges(["10.0.0.0/25", "10.0.0.128/25"], 4), [(167772160, 167772415)], ) def test_forwarder_primitives(self): self.assertEqual( parse_connect_authority("CONNECT [::1]:443 HTTP/1.1"), ("::1", 443) ) self.assertEqual( parse_http_absolute("GET https://example.com/path HTTP/1.1"), ("example.com", 443), ) request = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" injected = inject_proxy_auth(request, "token") self.assertIn(b"Authorization: Basic token\r\n", injected) self.assertEqual(inject_proxy_auth(injected, "different"), injected) self.assertIn(b"Connection: close\r\n", force_http_close(request)) def test_settings_pac_and_node_secrets_storage(self): with tempfile.TemporaryDirectory() as temporary: directory = Path(temporary) settings = JsonSettingsStore(lambda: directory / "settings.json") self.assertEqual(settings.load(), {}) settings.save({"local_port": 1080}) self.assertEqual(settings.load(), {"local_port": 1080}) payload = {"version": "1", "domains": ["example.com"]} atomic_write(directory, "pac_domains", payload) self.assertEqual(read_version(directory / "pac_domains.json"), ("1", "")) self.assertTrue(validate_document("pac_domains", payload)) secrets = NodeSecretsStore(lambda: directory) self.assertEqual(secrets.decrypt_bytes(secrets.encrypt_text("round-trip")), "round-trip") secrets.save_auth("test-user", "test-password") self.assertEqual( secrets.load_auth(), {"username": "test-user", "password": "test-password"} ) def test_traffic_and_node_protocol_helpers(self): times = iter((10.0, 12.0)) stats = TrafficStats(clock=lambda: next(times)) stats.reset() stats.add(up=20, down=10) self.assertEqual(stats.rate(), (10, 5, 20, 10)) self.assertEqual(format_bytes(1536), "1.5 KB") self.assertEqual(b64url("a/b="), "YS9iPQ") error = NodeAuthError("denied", 403) self.assertEqual((str(error), error.code), ("denied", 403)) def test_network_primitives_and_ttl_cache(self): self.assertTrue(is_private_ipv4_int(0x0A010203)) self.assertTrue(is_private_host("::1")) self.assertFalse(is_private_host("8.8.8.8")) calls = [] @ttl_cache(300) def probe(value): calls.append(value) return value self.assertEqual((probe("x"), probe("x")), ("x", "x")) self.assertEqual(calls, ["x"]) probe.cache_clear() probe("x") self.assertEqual(calls, ["x", "x"]) if __name__ == "__main__": unittest.main(verbosity=2)