Files
ShadowsocksX-NG/ShadowsocksX-NG2/Tests/Runtime/RuntimeLogSystemLogRouteTests.swift
Qiu Yuzhou ec09d79399 feat(runtime): route runtime events to the unified log
Emit every RuntimeLogEvent to os.Logger under a shared subsystem with
per-event category and level, so GUI and wrapper output can be filtered
in Console.app. Public text is split from private detail (free-form error
text and connectivity measurement content) on the closed enum, keeping
server addresses out of the public log surface. The stderr line and the
event sink stay unchanged. Add the system log glossary term.
2026-10-20 11:06:14 +08:00

102 lines
4.8 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
import Testing
import os
@testable import ShadowsocksX_NG2
/// 系统日志路由基线:level 三分(失败 error / 里程碑 default / 冗长测量
/// info)、category 五分、公开文本与 private detail 的拆分。映射是封闭枚举
/// 上的纯数据,测数据不测转发。
@Suite struct RuntimeLogSystemLogRouteTests {
private let detail = "SECRET-DETAIL"
private struct Expectation {
var event: RuntimeLogEvent
var level: OSLogType
var category: String
var detail: String?
}
/// 全部事件的路由事实;新增事件漏路由由穷举 switch 兜底,本表锁定
/// level / category / detail 拆分不随重构漂移。
private var expectations: [Expectation] {
let trace = ConnectivityTrace(phase: .sample, status: .success)
return [
Expectation(
event: .contractWritten(serverCount: 2), level: .default, category: "runtime", detail: nil),
Expectation(event: .contractUnchanged, level: .default, category: "runtime", detail: nil),
Expectation(event: .runtimeFilesDeleted, level: .default, category: "runtime", detail: nil),
Expectation(event: .contractMissing, level: .error, category: "runtime", detail: nil),
Expectation(event: .contractInvalid, level: .error, category: "runtime", detail: nil),
Expectation(
event: .activationFailed(reason: "no usable server"), level: .error, category: "runtime",
detail: nil),
Expectation(
event: .runtimePersistFailed(detail: detail), level: .error, category: "runtime",
detail: detail),
Expectation(
event: .settingsUnreadable(detail: detail), level: .error, category: "runtime",
detail: detail),
Expectation(event: .agentRegistered, level: .default, category: "supervision", detail: nil),
Expectation(event: .agentUnregistered, level: .default, category: "supervision", detail: nil),
Expectation(
event: .sslocalSpawned(pid: 1), level: .default, category: "supervision", detail: nil),
Expectation(
event: .sslocalStopRequested, level: .default, category: "supervision", detail: nil),
Expectation(event: .reloadForwarded, level: .default, category: "supervision", detail: nil),
Expectation(event: .reloadDeferred, level: .default, category: "supervision", detail: nil),
Expectation(event: .reloadRestarted, level: .default, category: "supervision", detail: nil),
Expectation(event: .sslocalSpawnFailed, level: .error, category: "supervision", detail: nil),
Expectation(
event: .sslocalExitedUnexpectedly(status: 1), level: .error, category: "supervision",
detail: nil),
Expectation(
event: .listenNotEstablished(detail: "socks 127.0.0.1:11086"),
level: .error, category: "supervision", detail: nil),
Expectation(
event: .agentRegisterFailed(detail: detail), level: .error, category: "supervision",
detail: detail),
Expectation(
event: .agentUnregisterFailed(detail: detail), level: .error, category: "supervision",
detail: detail),
Expectation(
event: .systemProxyUnchanged, level: .default, category: "system-proxy", detail: nil),
Expectation(
event: .systemProxyHelperRegisterFailed(detail: detail),
level: .error, category: "system-proxy", detail: detail),
Expectation(
event: .systemProxyWriteFailed(detail: detail), level: .error, category: "system-proxy",
detail: detail),
Expectation(
event: .connectivityMeasurement(id: UUID(), entry: trace),
level: .info, category: "connectivity", detail: trace.description),
Expectation(
event: .endpointProbeFailed(host: "127.0.0.1", port: 11086, detail: detail),
level: .error, category: "connectivity", detail: detail),
Expectation(
event: .diagnosticsExported, level: .default, category: "diagnostics", detail: nil),
]
}
@Test func everyEventRoutesToLevelCategoryAndPrivacySplit() {
for row in expectations {
let route = row.event.systemLogRoute
#expect(route.level == row.level, "level 漂移:\(row.event)")
#expect(route.category == row.category, "category 漂移:\(row.event)")
#expect(route.privateDetail == row.detail, "detail 拆分漂移:\(row.event)")
}
}
@Test func publicTextPlusPrivateDetailMatchesDescription() {
for row in expectations {
let route = row.event.systemLogRoute
// 公开文本只到分隔符为止;detail(含连通性测量的目标 IP)只进 private 段。
#expect(
route.text + (route.privateDetail ?? "") == row.event.description, "公开文本漂移:\(row.event)")
if let detail = route.privateDetail {
#expect(!route.text.contains(detail), "公开文本不得携带 private detail:\(row.event)")
}
}
}
}