feat(worker): add OAuth usage client + poller
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).
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user