Providers emitted identifiers and field keys that decodeSnapshot never
looked up, leaving CPU/kernel/load/disk sections zeroed and memory%,
storage%, network, process RSS, and fan fields decoded as zero.
Store-side decode now reads the emitted schema; providers gain the
previously-missing fields: network isUp (IFF_UP via getifaddrs), process
isStopped/isZombie (pbi_status), fan name (F{i}ID). Memory utilization is
computed as used/total in the decoder. decodeSnapshot is internal for
@testable access; new MMSnapshotContractTests cover the emitted-key
contract with synthetic dictionaries (93 tests total, 0 failures).
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
163 lines
7.2 KiB
Swift
163 lines
7.2 KiB
Swift
import XCTest
|
|
@testable import MacMonitor
|
|
|
|
/// Snapshot contract conformance tests (Issues #30 / #31).
|
|
/// Feeds synthetic dictionaries keyed exactly as the Objective-C providers emit them
|
|
/// through `SystemTelemetryStore.decodeSnapshot` and asserts the decoded Swift models
|
|
/// populate — guarding against provider-identifier and field-name drift.
|
|
@MainActor
|
|
final class MMSnapshotContractTests: XCTestCase {
|
|
|
|
private var store: SystemTelemetryStore { SystemTelemetryStore.shared }
|
|
|
|
// MARK: - Provider identifier coverage (#30)
|
|
|
|
func testEmittedProviderIdentifiersAreDecoded() {
|
|
// The four identifiers that previously never reached the decoder.
|
|
let snapshot: [String: [String: Any]] = [
|
|
"com.i3omb.macmonitor.telemetry.cpuload": [
|
|
"userPercent": 25.0, "systemPercent": 15.0,
|
|
"idlePercent": 60.0, "totalPercent": 40.0,
|
|
"cores": [["totalPercent": 10.0], ["totalPercent": 90.0]],
|
|
"frequencyHz": 2.4e9, "isThrottled": false
|
|
],
|
|
"com.i3omb.macmonitor.telemetry.kernel.counters": [
|
|
"contextSwitchesRate": 1234.5, "syscallsRate": 9876.5,
|
|
"pageFaultsRate": 42.0, "cowFaultsRate": 3.0,
|
|
"zeroFillsRate": 7.0, "pageinsRate": 1.0, "pageoutsRate": 0.5,
|
|
"cumulative_contextSwitches": 999_999 as UInt64,
|
|
"cumulative_syscalls": 888_888 as UInt64,
|
|
"cumulative_pageFaults": 777_777 as UInt64
|
|
],
|
|
"com.i3omb.macmonitor.telemetry.system.load": [
|
|
"load1m": 1.5, "load5m": 2.0, "load15m": 2.5,
|
|
"taskCount": 400, "threadCount": 2000, "machFactor": 0.75
|
|
],
|
|
"com.i3omb.macmonitor.telemetry.storage.io": [
|
|
"disks": [[
|
|
"bsdName": "disk0",
|
|
"readBytesPerSec": 1_048_576.0, "writeBytesPerSec": 524_288.0,
|
|
"readIOPS": 120.0, "writeIOPS": 60.0,
|
|
"cumulativeReadBytes": 9_999_999 as UInt64,
|
|
"cumulativeWriteBytes": 8_888_888 as UInt64
|
|
]]
|
|
]
|
|
]
|
|
|
|
store.decodeSnapshot(snapshot)
|
|
|
|
XCTAssertEqual(store.cpuLoad.userLoad, 25.0, accuracy: 0.001)
|
|
XCTAssertEqual(store.cpuLoad.systemLoad, 15.0, accuracy: 0.001)
|
|
XCTAssertEqual(store.cpuLoad.totalLoad, 40.0, accuracy: 0.001)
|
|
XCTAssertEqual(store.cpuLoad.perCoreLoad, [10.0, 90.0])
|
|
XCTAssertEqual(store.cpuLoad.cpuFrequencyMHz, 2400.0, accuracy: 0.001)
|
|
|
|
XCTAssertEqual(store.kernelCounters.contextSwitchesPerSec, 1234.5, accuracy: 0.001)
|
|
XCTAssertEqual(store.kernelCounters.syscallsPerSec, 9876.5, accuracy: 0.001)
|
|
XCTAssertEqual(store.kernelCounters.totalContextSwitches, 999_999)
|
|
XCTAssertEqual(store.kernelCounters.totalSyscalls, 888_888)
|
|
XCTAssertEqual(store.kernelCounters.totalPageFaults, 777_777)
|
|
|
|
XCTAssertEqual(store.systemLoad.load1Min, 1.5, accuracy: 0.001)
|
|
XCTAssertEqual(store.systemLoad.load5Min, 2.0, accuracy: 0.001)
|
|
XCTAssertEqual(store.systemLoad.load15Min, 2.5, accuracy: 0.001)
|
|
XCTAssertEqual(store.systemLoad.taskCount, 400)
|
|
XCTAssertEqual(store.systemLoad.threadCount, 2000)
|
|
|
|
XCTAssertEqual(store.diskIO.count, 1)
|
|
XCTAssertEqual(store.diskIO[0].bsdName, "disk0")
|
|
XCTAssertEqual(store.diskIO[0].readBps, 1_048_576.0, accuracy: 0.001)
|
|
XCTAssertEqual(store.diskIO[0].totalBytesRead, 9_999_999)
|
|
}
|
|
|
|
// MARK: - Field-name drift (#31)
|
|
|
|
func testMemoryUtilizationComputedFromUsedOverTotal() {
|
|
store.decodeSnapshot([
|
|
"com.i3omb.macmonitor.telemetry.memory": [
|
|
"totalBytes": 16_000_000_000 as UInt64,
|
|
"usedBytes": 8_000_000_000 as UInt64,
|
|
"freeBytes": 8_000_000_000 as UInt64,
|
|
"memoryPressureStatus": "Normal"
|
|
]
|
|
])
|
|
XCTAssertEqual(store.memory.utilizationPercentage, 50.0, accuracy: 0.001)
|
|
}
|
|
|
|
func testStorageVolumeEmitsUsedPercentAndFSType() {
|
|
store.decodeSnapshot([
|
|
"com.i3omb.macmonitor.telemetry.storage": [
|
|
"volumes": [[
|
|
"volumeName": "Macintosh HD", "mountPoint": "/",
|
|
"devicePath": "/dev/disk1s1", "fsType": "apfs",
|
|
"totalBytes": 500_000_000_000 as UInt64,
|
|
"usedBytes": 250_000_000_000 as UInt64,
|
|
"freeBytes": 250_000_000_000 as UInt64,
|
|
"usedPercent": 50.0, "isReadOnly": false
|
|
]]
|
|
]
|
|
])
|
|
XCTAssertEqual(store.storageVolumes.count, 1)
|
|
XCTAssertEqual(store.storageVolumes[0].usedPercentage, 50.0, accuracy: 0.001)
|
|
XCTAssertEqual(store.storageVolumes[0].fileSystem, "apfs")
|
|
}
|
|
|
|
func testNetworkInterfaceEmittedKeys() {
|
|
store.decodeSnapshot([
|
|
"com.i3omb.macmonitor.telemetry.network.bandwidth": [
|
|
"interfaces": [[
|
|
"name": "en0", "isUp": true, "ipv4Address": "192.168.1.10",
|
|
"downloadBytesPerSec": 5_000.0, "uploadBytesPerSec": 1_000.0,
|
|
"downloadPacketsPerSec": 40.0, "uploadPacketsPerSec": 20.0,
|
|
"cumulativeInBytes": 10_000_000 as UInt64,
|
|
"cumulativeOutBytes": 5_000_000 as UInt64
|
|
]]
|
|
]
|
|
])
|
|
XCTAssertEqual(store.networkBandwidth.count, 1)
|
|
let iface = store.networkBandwidth[0]
|
|
XCTAssertEqual(iface.interfaceName, "en0")
|
|
XCTAssertTrue(iface.isUp)
|
|
XCTAssertEqual(iface.ipAddress, "192.168.1.10")
|
|
XCTAssertEqual(iface.downloadBps, 5_000.0, accuracy: 0.001)
|
|
XCTAssertEqual(iface.totalBytesIn, 10_000_000)
|
|
}
|
|
|
|
func testProcessResidentAndVirtualBytesDecode() {
|
|
store.decodeSnapshot([
|
|
"com.i3omb.macmonitor.telemetry.process": [
|
|
"processes": [[
|
|
"pid": 42, "ppid": 1, "name": "testproc",
|
|
"cpuPercent": 3.5,
|
|
"residentBytes": 100_000_000 as UInt64,
|
|
"virtualBytes": 400_000_000 as UInt64,
|
|
"threadCount": 5, "uid": 501, "username": "gordon",
|
|
"isStopped": false, "isZombie": false
|
|
]]
|
|
]
|
|
])
|
|
XCTAssertEqual(store.processes.count, 1)
|
|
XCTAssertEqual(store.processes[0].residentSize, 100_000_000)
|
|
XCTAssertEqual(store.processes[0].virtualSize, 400_000_000)
|
|
XCTAssertFalse(store.processes[0].isStopped)
|
|
XCTAssertFalse(store.processes[0].isZombie)
|
|
}
|
|
|
|
func testFanEmittedKeysDecode() {
|
|
store.decodeSnapshot([
|
|
"com.i3omb.macmonitor.telemetry.fan": [
|
|
"fans": [[
|
|
"fanIndex": 0, "name": "Exhaust",
|
|
"currentRPM": 2000.0, "minRPM": 1200.0,
|
|
"maxRPM": 6000.0, "targetRPM": 2000.0,
|
|
"utilizationPercent": 16.67
|
|
]]
|
|
]
|
|
])
|
|
XCTAssertEqual(store.fans.count, 1)
|
|
XCTAssertEqual(store.fans[0].index, 0)
|
|
XCTAssertEqual(store.fans[0].name, "Exhaust")
|
|
XCTAssertEqual(store.fans[0].utilization, 16.67, accuracy: 0.01)
|
|
}
|
|
}
|