Files
2026-07-13 12:22:33 +08:00

508 lines
20 KiB
Swift

import Foundation
import Testing
@testable import CodexBarCore
@Suite(.serialized)
struct DevinUsageFetcherTests {
private static let now = Date(timeIntervalSince1970: 1_780_000_000)
@Test
func `parses quota usage response into daily and weekly windows`() throws {
let response: [String: Any] = [
"plan_name": "pro",
"quota_usage": [
"daily_quota": [
"used": 3,
"limit": 10,
"reset_at": "2026-06-01T08:00:00Z",
],
"weekly_quota": [
"remaining_percent": 0.25,
"next_reset_at": 1_780_560_000,
],
],
]
let snapshot = try DevinUsageParser.parse(response, organization: "org/example-org", now: Self.now)
#expect(snapshot.daily?.usedPercent == 30)
#expect(snapshot.weekly?.usedPercent == 75)
#expect(snapshot.daily?.resetsAt?.timeIntervalSince1970 == 1_780_300_800)
#expect(snapshot.weekly?.resetsAt?.timeIntervalSince1970 == 1_780_560_000)
#expect(snapshot.planName == "Pro")
#expect(snapshot.organization == "example-org")
}
@Test
func `parses current Devin quota response with reset timestamps`() throws {
let response: [String: Any] = [
"is_quota_plan": true,
"has_quota_allocation": true,
"daily_percentage": 0.12,
"weekly_percentage": 42,
"daily_reset_at": "2026-06-11T00:00:00-08:00",
"weekly_reset_at": "2026-06-14T00:00:00-08:00",
"hide_daily_quota": false,
]
let snapshot = try DevinUsageParser.parse(response, organization: "org/example-org", now: Self.now)
#expect(snapshot.daily?.usedPercent == 12)
#expect(snapshot.weekly?.usedPercent == 42)
#expect(snapshot.daily?.resetsAt?.timeIntervalSince1970 == 1_781_164_800)
#expect(snapshot.weekly?.resetsAt?.timeIntervalSince1970 == 1_781_424_000)
}
@Test
func `parses overage balance into extra usage provider cost`() throws {
let response: [String: Any] = [
"daily_percentage": 12,
"weekly_percentage": 42,
"overage_balance": 70.87,
]
let snapshot = try DevinUsageParser.parse(response, organization: nil, now: Self.now)
#expect(snapshot.overageBalance == 70.87)
let cost = try #require(snapshot.toUsageSnapshot().providerCost)
#expect(cost.used == 70.87)
#expect(cost.limit == 0)
#expect(cost.currencyCode == "USD")
#expect(cost.period == "Extra usage balance")
#expect(cost.updatedAt == Self.now)
}
@Test
func `parses overage balance cents into extra usage provider cost`() throws {
let response: [String: Any] = [
"daily_percentage": 12,
"weekly_percentage": 42,
"overage_balance_cents": 7087,
]
let snapshot = try DevinUsageParser.parse(response, organization: nil, now: Self.now)
#expect(snapshot.overageBalance == 70.87)
#expect(snapshot.toUsageSnapshot().providerCost?.period == "Extra usage balance")
}
@Test
func `omits provider cost when overage balance is absent`() throws {
let response: [String: Any] = [
"daily_percentage": 12,
"weekly_percentage": 42,
]
let snapshot = try DevinUsageParser.parse(response, organization: nil, now: Self.now)
#expect(snapshot.overageBalance == nil)
#expect(snapshot.toUsageSnapshot().providerCost == nil)
}
@Test(arguments: ["-1", "Infinity", "NaN"])
func `omits invalid overage balances`(_ balance: String) throws {
let response: [String: Any] = [
"daily_percentage": 12,
"weekly_percentage": 42,
"overage_balance": balance,
]
let snapshot = try DevinUsageParser.parse(response, organization: nil, now: Self.now)
#expect(snapshot.overageBalance == nil)
#expect(snapshot.toUsageSnapshot().providerCost == nil)
}
@Test(arguments: ["-1", "Infinity", "NaN"])
func `omits invalid overage balance cents`(_ balance: String) throws {
let response: [String: Any] = [
"daily_percentage": 12,
"weekly_percentage": 42,
"overage_balance_cents": balance,
]
let snapshot = try DevinUsageParser.parse(response, organization: nil, now: Self.now)
#expect(snapshot.overageBalance == nil)
#expect(snapshot.toUsageSnapshot().providerCost == nil)
}
@Test
func `keeps weekly quota when current plan hides daily quota`() throws {
let response: [String: Any] = [
"weekly_percentage": 25,
"weekly_reset_at": "2026-06-14T00:00:00-08:00",
"hide_daily_quota": true,
]
let usage = try DevinUsageParser.parse(response, organization: nil, now: Self.now).toUsageSnapshot()
#expect(usage.primary == nil)
#expect(usage.secondary?.usedPercent == 25)
}
@Test
func `normalizes mixed-scale current percentages at the one-percent boundary`() throws {
let cases: [(input: Double, expected: Double)] = [
(0.5, 50),
(1, 1),
(1.5, 1.5),
]
for value in cases {
let response: [String: Any] = [
"daily_percentage": value.input,
"weekly_percentage": value.input,
]
let snapshot = try DevinUsageParser.parse(response, organization: nil, now: Self.now)
#expect(snapshot.daily?.usedPercent == value.expected)
#expect(snapshot.weekly?.usedPercent == value.expected)
}
}
@Test
func `preserves fractional boundaries for fallback quota percentages`() throws {
let response: [String: Any] = [
"quota_usage": [
"daily_quota": [
"used_percent": 1,
"reset_at": "2026-06-01T08:00:00Z",
],
"weekly_quota": [
"remaining_percent": 1,
"next_reset_at": 1_780_560_000,
],
],
]
let snapshot = try DevinUsageParser.parse(response, organization: nil, now: Self.now)
#expect(snapshot.daily?.usedPercent == 100)
#expect(snapshot.weekly?.usedPercent == 0)
}
@Test
func `parses zero percentages from JSON response`() throws {
let data = Data("""
{
"daily_percentage": 0,
"weekly_percentage": 0,
"daily_reset_at": "2026-06-11T00:00:00-08:00",
"weekly_reset_at": "2026-06-14T00:00:00-08:00"
}
""".utf8)
let snapshot = try DevinUsageParser.parse(data, organization: nil, now: Self.now)
#expect(snapshot.daily?.usedPercent == 0)
#expect(snapshot.weekly?.usedPercent == 0)
}
@Test
func `usage snapshot maps Devin quotas to primary and secondary windows`() {
let snapshot = DevinUsageSnapshot(
daily: DevinQuotaWindow(usedPercent: 12),
weekly: DevinQuotaWindow(usedPercent: 42),
planName: "Free",
organization: "example-org",
updatedAt: Self.now)
let usage = snapshot.toUsageSnapshot()
#expect(usage.primary?.usedPercent == 12)
#expect(usage.primary?.windowMinutes == 1440)
#expect(usage.primary?.resetDescription == "Daily")
#expect(usage.secondary?.usedPercent == 42)
#expect(usage.secondary?.windowMinutes == 10080)
#expect(usage.secondary?.resetDescription == "Weekly")
#expect(usage.identity?.providerID == .devin)
#expect(usage.identity?.accountOrganization == "example-org")
#expect(usage.identity?.loginMethod == "Free")
}
@Test
func `fetch sends bearer token and organization header`() async throws {
let auth = DevinUsageFetcher.RequestAuth(
bearerToken: "secret-token",
organization: "org/example-org",
internalOrganizationID: "org_GQ6LhcfkW1TSinM6",
sourceLabel: "test")
let stub = ProviderHTTPTransportStub { request in
#expect(request.url?.host == "app.devin.ai")
#expect(request.url?.path == "/api/org_GQ6LhcfkW1TSinM6/billing/quota/usage")
#expect(request.value(forHTTPHeaderField: "Authorization") == "Bearer secret-token")
#expect(request.value(forHTTPHeaderField: "x-cog-org-id") == "org_GQ6LhcfkW1TSinM6")
let body = """
{"daily":{"used_percent":10},"weekly":{"used_percent":20},"plan":"free"}
"""
let response = HTTPURLResponse(
url: request.url!,
statusCode: 200,
httpVersion: nil,
headerFields: nil)!
return (Data(body.utf8), response)
}
let snapshot = try await DevinUsageFetcher.fetchQuotaUsage(
auth: auth,
now: Self.now,
transport: stub)
#expect(snapshot.daily?.usedPercent == 10)
#expect(snapshot.weekly?.usedPercent == 20)
#expect(snapshot.planName == "Free")
}
@Test
func `fetch does not mask parser failure with fallback endpoint errors`() async {
let auth = DevinUsageFetcher.RequestAuth(
bearerToken: "secret-token",
organization: "org/example-org",
internalOrganizationID: "org_GQ6LhcfkW1TSinM6",
sourceLabel: "test")
let stub = ProviderHTTPTransportStub { request in
let response = HTTPURLResponse(
url: request.url!,
statusCode: request.url?.path == "/api/org_GQ6LhcfkW1TSinM6/billing/quota/usage" ? 200 : 404,
httpVersion: nil,
headerFields: nil)!
return (Data("{}".utf8), response)
}
do {
_ = try await DevinUsageFetcher.fetchQuotaUsage(
auth: auth,
now: Self.now,
transport: stub)
Issue.record("Expected quota parsing to fail")
} catch let error as DevinUsageError {
guard case .parseFailed = error else {
Issue.record("Expected parseFailed, got \(error)")
return
}
} catch {
Issue.record("Expected DevinUsageError, got \(error)")
}
#expect(await stub.requests().count == 1)
}
@Test
func `normalizes organization inputs`() {
#expect(DevinUsageFetcher.normalizedOrganization("example-org") == "org/example-org")
#expect(DevinUsageFetcher.normalizedOrganization("org/example-org") == "org/example-org")
#expect(DevinUsageFetcher.normalizedOrganization("org_GQ6LhcfkW1TSinM6") ==
"organizations/org_GQ6LhcfkW1TSinM6")
#expect(DevinUsageFetcher.normalizedOrganization("org-b31f951cd01d4c6da84991cf5b970cfb") ==
"organizations/org-b31f951cd01d4c6da84991cf5b970cfb")
#expect(DevinUsageFetcher.normalizedOrganization("https://app.devin.ai/org/example-org/settings/usage") ==
"org/example-org")
}
@Test
func `manual auth strips Authorization and Bearer prefixes`() throws {
let auth = try #require(DevinUsageFetcher.manualAuth(
from: "Authorization: Bearer secret-token",
organization: "example-org"))
#expect(auth.bearerToken == "secret-token")
#expect(auth.organization == "org/example-org")
#expect(auth.sourceLabel == "manual")
}
#if os(macOS)
@Test
func `empty app organization setting preserves imported organization`() async throws {
defer { DevinSessionImporter.importSessionOverrideForTesting = nil }
DevinSessionImporter.importSessionOverrideForTesting = { _, organizationOverride, _ in
#expect(organizationOverride == nil)
return DevinSessionImporter.SessionInfo(
accessToken: "auth1_abcdefghijklmnopqrstuvwxyz0123456789",
organization: "org/example-org",
internalOrganizationID: "org_GQ6LhcfkW1TSinM6",
sourceLabel: "Chrome Default")
}
let stub = ProviderHTTPTransportStub { request in
#expect(request.url?.path == "/api/org_GQ6LhcfkW1TSinM6/billing/quota/usage")
let response = HTTPURLResponse(
url: request.url!,
statusCode: 200,
httpVersion: nil,
headerFields: nil)!
return (Data(#"{"daily_percentage":0,"weekly_percentage":0}"#.utf8), response)
}
let snapshot = try await DevinUsageFetcher(browserDetection: BrowserDetection(cacheTTL: 0)).fetch(
organizationOverride: "",
now: Self.now,
transport: stub)
#expect(snapshot.organization == "example-org")
#expect(snapshot.daily?.usedPercent == 0)
#expect(snapshot.weekly?.usedPercent == 0)
}
@Test
func `session importer extracts current auth1 token and matching org`() throws {
let accessToken = "auth1_abcdefghijklmnopqrstuvwxyz0123456789"
let storage = [
"_https://app.devin.ai\u{0000}\u{0001}auth1_session":
#"{"token":"\#(accessToken)","userId":"github|123"}"#,
"_https://app.devin.ai\u{0000}\u{0001}last-internal-org-for-external-org-v1-example-org":
"\"org_GQ6LhcfkW1TSinM6\"",
]
let session = try #require(DevinSessionImporter.session(
from: storage,
organizationOverride: "example-org",
sourceLabel: "Chrome Default"))
#expect(session.accessToken == accessToken)
#expect(session.organization == "org/example-org")
#expect(session.internalOrganizationID == "org_GQ6LhcfkW1TSinM6")
#expect(session.sourceLabel == "Chrome Default")
}
@Test
func `session importer infers organization from post auth storage`() throws {
let accessToken = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2F1dGguZGV2aW4uYWkvIn0.signature"
let storage = [
"_https://app.devin.ai\u{0000}\u{0001}@@auth0spajs@@::client::audience::scope":
#"{"body":{"access_token":"\#(accessToken)"}}"#,
"_https://app.devin.ai\u{0000}\u{0001}post-auth-v3-null-github|123-org_name-example-org": """
{
"externalOrgId": null,
"userId": "github|123",
"internalOrgId": "org_GQ6LhcfkW1TSinM6",
"orgName": "example-org"
}
""",
]
let session = try #require(DevinSessionImporter.session(
from: storage,
organizationOverride: nil,
sourceLabel: "Brave Default"))
#expect(session.organization == "org/example-org")
#expect(session.internalOrganizationID == "org_GQ6LhcfkW1TSinM6")
}
@Test
func `session importer infers organization from member info storage`() throws {
let accessToken = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJodHRwczovL2F1dGguZGV2aW4uYWkvIn0.signature"
let storage = [
"_https://app.devin.ai\u{0000}\u{0001}@@auth0spajs@@::client::audience::scope":
#"{"body":{"access_token":"\#(accessToken)"}}"#,
"_https://app.devin.ai\u{0000}\u{0001}member-info-v1-org-github|123": """
{
"value": {
"org_id": "org_GQ6LhcfkW1TSinM6",
"org_name": "example-org"
}
}
""",
]
let session = try #require(DevinSessionImporter.session(
from: storage,
organizationOverride: nil,
sourceLabel: "Brave Default"))
#expect(session.organization == "org/example-org")
#expect(session.internalOrganizationID == "org_GQ6LhcfkW1TSinM6")
}
@Test
func `session importer falls back to internal organization id`() {
let result = DevinSessionImporter.organizationInfo(
from: [
"_https://app.devin.ai\u{0000}\u{0001}feature-flags-cache:org_GQ6LhcfkW1TSinM6": "{}",
"_https://app.devin.ai\u{0000}\u{0001}member-info-v1-org-github|123": """
{"value":{"org_id":"org_GQ6LhcfkW1TSinM6"}}
""",
],
organizationOverride: nil)
#expect(result.organization == "organizations/org_GQ6LhcfkW1TSinM6")
#expect(result.internalOrganizationID == "org_GQ6LhcfkW1TSinM6")
}
@Test
func `session importer ignores org words inside storage key names`() {
let result = DevinSessionImporter.organizationInfo(
from: [
"_https://app.devin.ai\u{0000}\u{0001}last-internal-org-for-external-org-v1-null": "\"null\"",
"_https://app.devin.ai\u{0000}\u{0001}feature-flags-cache:org_GQ6LhcfkW1TSinM6": "{}",
],
organizationOverride: nil)
#expect(result.organization == "organizations/org_GQ6LhcfkW1TSinM6")
#expect(result.internalOrganizationID == "org_GQ6LhcfkW1TSinM6")
}
@Test
func `session importer deduplicates repeated browser tokens using richest organization metadata`() {
let sessions = [
DevinSessionImporter.SessionInfo(
accessToken: "auth1_abcdefghijklmnopqrstuvwxyz0123456789",
organization: nil,
internalOrganizationID: nil,
sourceLabel: "Chrome Default"),
DevinSessionImporter.SessionInfo(
accessToken: "auth1_abcdefghijklmnopqrstuvwxyz0123456789",
organization: "org/example",
internalOrganizationID: "org_GQ6LhcfkW1TSinM6",
sourceLabel: "Chrome Profile 1"),
]
let deduplicated = DevinSessionImporter.deduplicateSessions(sessions)
#expect(deduplicated.count == 1)
#expect(deduplicated.first?.sourceLabel == "Chrome Profile 1")
#expect(deduplicated.first?.organization == "org/example")
#expect(deduplicated.first?.internalOrganizationID == "org_GQ6LhcfkW1TSinM6")
}
@Test
func `session importer ranks organization aware profiles first`() {
let incomplete = DevinSessionImporter.SessionInfo(
accessToken: "auth1_incomplete",
organization: nil,
internalOrganizationID: nil,
sourceLabel: "Chrome Default")
let complete = DevinSessionImporter.SessionInfo(
accessToken: "auth1_complete",
organization: "org/example",
internalOrganizationID: "org_GQ6LhcfkW1TSinM6",
sourceLabel: "Chrome Profile 1")
let ranked = DevinSessionImporter.rankSessions([incomplete, complete])
#expect(ranked.map(\.sourceLabel) == ["Chrome Profile 1", "Chrome Default"])
}
@Test
func `missing organization retries the next browser profile`() {
#expect(DevinUsageFetcher.shouldTryNextSession(after: DevinUsageError.missingOrganization))
#expect(!DevinUsageFetcher.shouldTryNextSession(after: DevinUsageError.parseFailed("invalid response")))
}
@Test
func `automatic local storage import does not fall back beyond Chrome`() throws {
let temp = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
defer { try? FileManager.default.removeItem(at: temp) }
let braveRoot = temp
.appendingPathComponent("Library/Application Support/BraveSoftware/Brave-Browser/Default")
try FileManager.default.createDirectory(at: braveRoot, withIntermediateDirectories: true)
let detection = BrowserDetection(homeDirectory: temp.path, cacheTTL: 0)
#expect(detection.hasUsableProfileData(.brave))
#expect(!detection.hasUsableProfileData(.chrome))
#expect(DevinSessionImporter.localStorageBrowsers(browserDetection: detection).isEmpty)
}
#endif
}