Adds Usage/ with ClaudeOAuthUsageClient (reads the access token Claude Code keeps fresh at ~/.claude/.credentials.json, calls the Anthropic OAuth usage endpoint, defensively parses buckets/limits), UsageState (threadsafe last-good-snapshot holder that never regresses on failure), and UsageMonitorService (BackgroundService polling on the new usage_poll_interval_seconds config, min 15s, one poll at startup, warns at most once per distinct error).
49 lines
1.3 KiB
C#
49 lines
1.3 KiB
C#
using ClaudeDo.Worker.Usage;
|
|
|
|
namespace ClaudeDo.Worker.Tests.Usage;
|
|
|
|
public sealed class UsageStateTests
|
|
{
|
|
private static UsageSnapshot MakeSnapshot(double fiveHourUtilization) => new(
|
|
new UsageBucket(fiveHourUtilization, null),
|
|
null,
|
|
[],
|
|
DateTime.UtcNow);
|
|
|
|
[Fact]
|
|
public void ReportSuccess_SetsSnapshotAndClearsError()
|
|
{
|
|
var state = new UsageState();
|
|
state.ReportFailure("boom", DateTime.UtcNow);
|
|
|
|
state.ReportSuccess(MakeSnapshot(42));
|
|
|
|
Assert.NotNull(state.Snapshot);
|
|
Assert.Equal(42, state.Snapshot!.FiveHour!.Utilization);
|
|
Assert.Null(state.LastError);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReportFailure_AfterSuccess_KeepsOldSnapshotButSetsError()
|
|
{
|
|
var state = new UsageState();
|
|
state.ReportSuccess(MakeSnapshot(10));
|
|
|
|
state.ReportFailure("network down", DateTime.UtcNow);
|
|
|
|
Assert.NotNull(state.Snapshot);
|
|
Assert.Equal(10, state.Snapshot!.FiveHour!.Utilization);
|
|
Assert.Equal("network down", state.LastError);
|
|
}
|
|
|
|
[Fact]
|
|
public void NoAttemptYet_SnapshotAndErrorAreNull()
|
|
{
|
|
var state = new UsageState();
|
|
|
|
Assert.Null(state.Snapshot);
|
|
Assert.Null(state.LastError);
|
|
Assert.Null(state.LastAttemptUtc);
|
|
}
|
|
}
|