Files
MacMonitor/Tests/MMSnapshotContractTests.swift
gronodandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 4a8fd0e5ef fix(telemetry): realign snapshot contract — provider IDs and dictionary field keys (fixes #30, fixes #31)
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>
2026-09-08 15:09:19 +01:00

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)
}
}