RadrootsAppleLoggerTelemetryTests.swift (4220B)
1 import Foundation 2 import Testing 3 @testable import RadrootsKit 4 5 @Test func appleLoggerTelemetryEmitsRedactedBoundedRecords() async throws { 6 let probe = RadrootsAppleLoggerTelemetryProbe() 7 let telemetry = RadrootsAppleLoggerTelemetry( 8 subsystem: " org.radroots.field ios ", 9 adapters: RadrootsAppleLoggerTelemetryAdapters(emit: probe.emit), 10 maximumRenderedMessageLength: 220 11 ) 12 let event = try RadrootsTelemetryEvent( 13 name: "field_ios.identity.import", 14 category: "field_ios", 15 level: .error, 16 message: "imported nsec1secret", 17 fields: [ 18 try .string("relay_light", "red"), 19 try .string("selected_secret_key_name", "field identity") 20 ], 21 occurredAt: Date(timeIntervalSince1970: 10) 22 ) 23 24 await telemetry.record(event) 25 26 let record = try #require(probe.records.first) 27 #expect(record.subsystem == "org.radroots.field_ios") 28 #expect(record.category == "field_ios") 29 #expect(record.level == .error) 30 #expect(record.renderedMessage.contains("\"event\":\"field_ios.identity.import\"")) 31 #expect(record.renderedMessage.contains("\"message\":\"[redacted]\"")) 32 #expect(record.renderedMessage.contains("\"selected_secret_key_name\":\"[redacted]\"")) 33 #expect(!record.renderedMessage.contains("nsec1secret")) 34 #expect(!record.renderedMessage.contains("field identity")) 35 #expect(record.renderedMessage.count <= 220) 36 } 37 38 @Test func appleLoggerTelemetrySanitizesSubsystemAndCategory() async throws { 39 #expect(RadrootsAppleLoggerTelemetry.normalizedSubsystem(" Field iOS / Local ") == "Field_iOS_Local") 40 #expect(RadrootsAppleLoggerTelemetry.normalizedSubsystem(" ") == "org.radroots.apple_kit") 41 #expect(RadrootsAppleLoggerTelemetry.normalizedCategory(" relay/status ") == "relay_status") 42 #expect(RadrootsAppleLoggerTelemetry.normalizedCategory(" -- ") == "app") 43 } 44 45 @Test func appleLoggerTelemetryMapsLevelsToOsLogTypes() { 46 #expect(RadrootsAppleTelemetryLogRecord( 47 subsystem: "org.radroots.tests", 48 category: "tests", 49 level: .trace, 50 renderedMessage: "{}" 51 ).osLogType == .debug) 52 #expect(RadrootsAppleTelemetryLogRecord( 53 subsystem: "org.radroots.tests", 54 category: "tests", 55 level: .info, 56 renderedMessage: "{}" 57 ).osLogType == .info) 58 #expect(RadrootsAppleTelemetryLogRecord( 59 subsystem: "org.radroots.tests", 60 category: "tests", 61 level: .warning, 62 renderedMessage: "{}" 63 ).osLogType == .default) 64 #expect(RadrootsAppleTelemetryLogRecord( 65 subsystem: "org.radroots.tests", 66 category: "tests", 67 level: .error, 68 renderedMessage: "{}" 69 ).osLogType == .error) 70 #expect(RadrootsAppleTelemetryLogRecord( 71 subsystem: "org.radroots.tests", 72 category: "tests", 73 level: .critical, 74 renderedMessage: "{}" 75 ).osLogType == .fault) 76 } 77 78 @Test func appleLoggerTelemetryRendersSortedPayloads() throws { 79 let event = try RadrootsTelemetryEvent( 80 name: "field_ios.relay.status", 81 category: "field_ios", 82 level: .notice, 83 fields: [ 84 try .integer("connecting_count", 1), 85 try .integer("connected_count", 2) 86 ], 87 occurredAt: Date(timeIntervalSince1970: 1) 88 ) 89 90 let rendered = RadrootsAppleLoggerTelemetry.renderedMessage(for: event) 91 92 #expect(rendered.contains("\"category\":\"field_ios\"")) 93 #expect(rendered.contains("\"connected_count\":\"2\"")) 94 #expect(rendered.contains("\"connecting_count\":\"1\"")) 95 #expect(rendered.contains("\"event\":\"field_ios.relay.status\"")) 96 #expect(rendered.contains("\"level\":\"notice\"")) 97 #expect(rendered.contains("\"occurred_at_unix_ms\":1000")) 98 } 99 100 private final class RadrootsAppleLoggerTelemetryProbe: @unchecked Sendable { 101 private let lock = NSLock() 102 private var recordsValue: [RadrootsAppleTelemetryLogRecord] = [] 103 104 func emit(_ record: RadrootsAppleTelemetryLogRecord) { 105 lock.withLock { 106 recordsValue.append(record) 107 } 108 } 109 110 var records: [RadrootsAppleTelemetryLogRecord] { 111 lock.withLock { 112 recordsValue 113 } 114 } 115 }