mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-08 11:14:51 +00:00
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.
102 lines
4.8 KiB
Swift
102 lines
4.8 KiB
Swift
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)")
|
||
}
|
||
}
|
||
}
|
||
}
|