mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-10-21 14:12:34 +00:00
Command Code's credits endpoint only reports monthly credits left, so the monthly window was dropped. For an active subscription on a known plan the plan price now comes from a small table (the API has no monthly cap field): pool = max(plan, left), used = pool - left, reset = currentPeriodEnd. Unknown plans and purchased/free credits stay out. CLI and menubar mirrored.
128 lines
6.4 KiB
Swift
128 lines
6.4 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import CodeBurnMenubar
|
|
|
|
@Suite("Command Code quota")
|
|
@MainActor
|
|
struct CommandCodeQuotaTests {
|
|
private final class RequestRecorder: @unchecked Sendable {
|
|
private(set) var requests: [URLRequest] = []
|
|
func record(_ request: URLRequest) { requests.append(request) }
|
|
}
|
|
|
|
nonisolated private static let creditsBody = """
|
|
{"credits":{"monthlyCredits":3.9706645399,"purchasedCredits":0,"freeCredits":0},
|
|
"windowLimits":{"limited":true,"exceeded":"weekly",
|
|
"fiveHour":{"used":0.75,"cap":3,"exceeded":false,"resetAt":0},
|
|
"weekly":{"used":6.0293354601,"cap":6,"exceeded":true,"resetAt":1791653049551}}}
|
|
"""
|
|
nonisolated private static let subscriptionBody = #"{"success":true,"data":{"status":"active","planId":"individual-go-v1","currentPeriodEnd":"2026-11-01T10:38:29.000Z"}}"#
|
|
|
|
nonisolated private static func response(_ request: URLRequest, _ status: Int) -> HTTPURLResponse {
|
|
HTTPURLResponse(url: request.url!, statusCode: status, httpVersion: nil, headerFields: nil)!
|
|
}
|
|
|
|
private static func deps(
|
|
key: String? = "synthetic-commandcode-key",
|
|
recorder: RequestRecorder = RequestRecorder(),
|
|
respond: @escaping @Sendable (URLRequest) throws -> (Data, HTTPURLResponse)
|
|
) -> CommandCodeSubscriptionService.Deps {
|
|
CommandCodeSubscriptionService.Deps(
|
|
loadAPIKey: { key },
|
|
fetch: { request in
|
|
recorder.record(request)
|
|
return try respond(request)
|
|
}
|
|
)
|
|
}
|
|
|
|
@Test("maps both windows, the plan and the remaining credits")
|
|
func decodesLiveShape() async throws {
|
|
let recorder = RequestRecorder()
|
|
let summary = try await CommandCodeSubscriptionService.refresh(deps: Self.deps(recorder: recorder) { request in
|
|
let body = request.url == CommandCodeSubscriptionService.creditsURL ? Self.creditsBody : Self.subscriptionBody
|
|
return (Data(body.utf8), Self.response(request, 200))
|
|
})
|
|
#expect(summary.details.map(\.label) == ["5-hour", "Weekly", "Monthly"])
|
|
#expect(summary.details[0].percent == 0.25)
|
|
#expect(summary.details[1].percent == 1)
|
|
#expect(abs(summary.details[2].percent - 0.6029) < 0.0001)
|
|
#expect(summary.details[0].resetsAt == nil)
|
|
#expect(summary.details[1].resetsAt == Date(timeIntervalSince1970: 1_791_653_049.551))
|
|
#expect(summary.details[2].resetsAt == Date(timeIntervalSince1970: 1_793_529_509))
|
|
#expect(summary.primary?.label == "Weekly")
|
|
#expect(summary.planLabel == "Go")
|
|
#expect(summary.footerLines == ["Credits left: $3.97 monthly"])
|
|
#expect(recorder.requests.count == 2)
|
|
for request in recorder.requests {
|
|
#expect(request.value(forHTTPHeaderField: "Authorization") == "Bearer synthetic-commandcode-key")
|
|
#expect(request.value(forHTTPHeaderField: "User-Agent") == "CodeBurn")
|
|
}
|
|
}
|
|
|
|
@Test("the monthly window needs an active subscription on a known plan")
|
|
func monthlyNeedsKnownActivePlan() throws {
|
|
let body = Data(Self.creditsBody.utf8)
|
|
let known = CommandCodeSubscriptionService.Subscription(
|
|
planID: "individual-go-v1", status: "active", currentPeriodEnd: "2026-11-01T10:38:29Z")
|
|
let go = try CommandCodeSubscriptionService.decode(body, subscription: known)
|
|
#expect(go.details.last?.label == "Monthly")
|
|
#expect(go.details.last?.resetsAt == Date(timeIntervalSince1970: 1_793_529_509))
|
|
#expect(go.primary?.label == "Weekly")
|
|
var unknown = known
|
|
unknown.planID = "individual-mystery"
|
|
#expect(try CommandCodeSubscriptionService.decode(body, subscription: unknown).details.map(\.label) == ["5-hour", "Weekly"])
|
|
var inactive = known
|
|
inactive.status = "canceled"
|
|
#expect(try CommandCodeSubscriptionService.decode(body, subscription: inactive).details.map(\.label) == ["5-hour", "Weekly"])
|
|
}
|
|
|
|
@Test("a failed subscription call only drops the plan label")
|
|
func subscriptionFailureKeepsWindows() async throws {
|
|
let summary = try await CommandCodeSubscriptionService.refresh(deps: Self.deps { request in
|
|
request.url == CommandCodeSubscriptionService.creditsURL
|
|
? (Data(Self.creditsBody.utf8), Self.response(request, 200))
|
|
: (Data("{}".utf8), Self.response(request, 500))
|
|
})
|
|
#expect(summary.planLabel == nil)
|
|
#expect(summary.details.count == 2)
|
|
}
|
|
|
|
@Test("missing key, rejected key and bad bodies map to their errors")
|
|
func errors() async {
|
|
let noKey = Self.deps(key: nil) { _ in
|
|
Issue.record("must not fetch without a key")
|
|
throw URLError(.badURL)
|
|
}
|
|
await #expect(throws: CommandCodeSubscriptionService.FetchError.noCredentials) {
|
|
try await CommandCodeSubscriptionService.refresh(deps: noKey)
|
|
}
|
|
let cases: [(Int, String, CommandCodeSubscriptionService.FetchError)] = [
|
|
(401, "{}", .authenticationRejected),
|
|
(429, "{}", .rateLimited),
|
|
(503, "{}", .providerUnavailable),
|
|
(200, #"{"windowLimits":{}}"#, .parseFailure),
|
|
]
|
|
for (status, body, expected) in cases {
|
|
await #expect(throws: expected) {
|
|
try await CommandCodeSubscriptionService.refresh(deps: Self.deps { request in
|
|
(Data(body.utf8), Self.response(request, status))
|
|
})
|
|
}
|
|
}
|
|
await #expect(throws: CommandCodeSubscriptionService.FetchError.network) {
|
|
try await CommandCodeSubscriptionService.refresh(deps: Self.deps { _ in throw URLError(.notConnectedToInternet) })
|
|
}
|
|
}
|
|
|
|
@Test("plan labels and the auth file")
|
|
func planLabelAndAuthFile() throws {
|
|
#expect(CommandCodeSubscriptionService.planLabel("individual-pro-v1") == "Pro")
|
|
#expect(CommandCodeSubscriptionService.planLabel("") == nil)
|
|
let file = FileManager.default.temporaryDirectory.appendingPathComponent("cc-auth-\(UUID().uuidString).json")
|
|
defer { try? FileManager.default.removeItem(at: file) }
|
|
try Data(#"{"apiKey":" synthetic ","userName":"x"}"#.utf8).write(to: file)
|
|
#expect(CommandCodeSubscriptionService.apiKey(fromAuthFile: file) == "synthetic")
|
|
#expect(CommandCodeSubscriptionService.apiKey(fromAuthFile: file.appendingPathExtension("missing")) == nil)
|
|
}
|
|
}
|