mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-08 19:19:42 +00:00
114 lines
4.4 KiB
Swift
114 lines
4.4 KiB
Swift
import Foundation
|
|
import HapiProtocol
|
|
import Testing
|
|
|
|
/// Decoding of the owner-only dashboard payloads (`GET /api/usage/summary`,
|
|
/// `GET /api/storage/sqlite`) — shaped like `hub/src/sync/usageService.ts`
|
|
/// output: sparse ascending `daily`, desc-sorted `byAgent`/`byModel`,
|
|
/// `range.from = null` on `range=all`, unknown keys ignored. Transcribed
|
|
/// from the Android `UsageDecodingTest`.
|
|
@Suite("Usage/storage wire decoding")
|
|
struct UsageDecodingTests {
|
|
private func decode<T: Decodable>(_ type: T.Type, _ json: String) throws -> T {
|
|
try JSONDecoder().decode(type, from: Data(json.utf8))
|
|
}
|
|
|
|
@Test func decodesARealisticUsageSummary() throws {
|
|
let summary = try decode(UsageSummaryResponse.self, """
|
|
{
|
|
"range": {"from": 1754995200000, "to": 1755600000000},
|
|
"totals": {
|
|
"inputTokens": 12400000,
|
|
"outputTokens": 310000,
|
|
"cacheReadTokens": 9800000,
|
|
"cacheCreationTokens": 1100000,
|
|
"totalTokens": 12710000,
|
|
"uncachedTokens": 2600000,
|
|
"requests": 1842,
|
|
"sessions": 23
|
|
},
|
|
"daily": [
|
|
{"key": "2026-08-12", "inputTokens": 1200000, "outputTokens": 40000,
|
|
"cacheReadTokens": 900000, "cacheCreationTokens": 100000,
|
|
"totalTokens": 1240000, "uncachedTokens": 300000, "requests": 210},
|
|
{"key": "2026-08-16", "inputTokens": 5100000, "outputTokens": 120000,
|
|
"cacheReadTokens": 4000000, "cacheCreationTokens": 500000,
|
|
"totalTokens": 5220000, "uncachedTokens": 1100000, "requests": 720}
|
|
],
|
|
"byAgent": [
|
|
{"key": "claude", "inputTokens": 8600000, "outputTokens": 220000,
|
|
"cacheReadTokens": 7000000, "cacheCreationTokens": 800000,
|
|
"totalTokens": 8820000, "uncachedTokens": 1600000, "requests": 1300}
|
|
],
|
|
"byModel": [
|
|
{"key": "claude-sonnet-4-5", "inputTokens": 8600000, "outputTokens": 220000,
|
|
"cacheReadTokens": 7000000, "cacheCreationTokens": 800000,
|
|
"totalTokens": 8820000, "uncachedTokens": 1600000, "requests": 1300,
|
|
"futureField": {"nested": true}}
|
|
],
|
|
"updatedAt": 1755600000000,
|
|
"unknownTopLevel": "ignored"
|
|
}
|
|
""")
|
|
|
|
#expect(summary.range.from == 1_754_995_200_000)
|
|
#expect(summary.range.to == 1_755_600_000_000)
|
|
#expect(summary.totals.totalTokens == 12_710_000)
|
|
#expect(summary.totals.uncachedTokens == 2_600_000)
|
|
#expect(summary.totals.sessions == 23)
|
|
#expect(summary.daily.map(\.key) == ["2026-08-12", "2026-08-16"])
|
|
#expect(summary.daily[1].requests == 720)
|
|
#expect(summary.byAgent.count == 1)
|
|
#expect(summary.byAgent[0].key == "claude")
|
|
#expect(summary.byModel.count == 1)
|
|
#expect(summary.byModel[0].totalTokens == 8_820_000)
|
|
#expect(summary.updatedAt == 1_755_600_000_000)
|
|
}
|
|
|
|
@Test func rangeAllCarriesANullFromAndTokenCountsMayExceedInt32() throws {
|
|
let summary = try decode(UsageSummaryResponse.self, """
|
|
{
|
|
"range": {"from": null, "to": 1755600000000},
|
|
"totals": {
|
|
"inputTokens": 5100000000,
|
|
"outputTokens": 200000000,
|
|
"cacheReadTokens": 4000000000,
|
|
"cacheCreationTokens": 300000000,
|
|
"totalTokens": 5300000000,
|
|
"uncachedTokens": 1100000000,
|
|
"requests": 250000,
|
|
"sessions": 4100
|
|
},
|
|
"daily": [],
|
|
"byAgent": [],
|
|
"byModel": [],
|
|
"updatedAt": 1755600000000
|
|
}
|
|
""")
|
|
|
|
#expect(summary.range.from == nil)
|
|
#expect(summary.totals.totalTokens == 5_300_000_000)
|
|
#expect(summary.totals.totalTokens > Int(Int32.max))
|
|
#expect(summary.daily.isEmpty)
|
|
}
|
|
|
|
@Test func decodesSqliteStorageUsage() throws {
|
|
let storage = try decode(SqliteStorageUsageResponse.self, """
|
|
{
|
|
"path": "/home/hapi/.hapi/hapi.db",
|
|
"databaseBytes": 84930560,
|
|
"walBytes": 4194304,
|
|
"shmBytes": 32768,
|
|
"totalBytes": 89157632,
|
|
"futureField": 1
|
|
}
|
|
""")
|
|
|
|
#expect(storage.path == "/home/hapi/.hapi/hapi.db")
|
|
#expect(storage.databaseBytes == 84_930_560)
|
|
#expect(storage.walBytes == 4_194_304)
|
|
#expect(storage.shmBytes == 32_768)
|
|
#expect(storage.totalBytes == 89_157_632)
|
|
}
|
|
}
|