mirror of
https://github.com/Twigpine/zero.git
synced 2026-11-11 18:00:54 -10:00
Surfaced by a full-tree audit; each ships a regression test where the behavior is deterministically testable. - swarm: deliver a handoff's mailbox note BEFORE registering the new task, so a mailbox failure can't leave a phantom pending task in the coordinator. - specialist: put a foreground sub-agent child in its own process group and group-kill on cancel/timeout (+ WaitDelay backstop), so a build/server it forked dies with it instead of orphaning. - oauth: serialize on-demand token refresh per key (keyed mutex) and re-load inside the lock, so parallel callers don't each spend the single-use refresh token (all but one would otherwise fail at the token endpoint). - mcp: treat a "source already gone" rename during legacy-token migration as success, so a concurrent migrator doesn't wrongly drop an OAuth MCP server. - cron: claim a due job atomically (advance NextRunAt under the per-job lock) before running it, so two schedulers can't double-fire the same job.
48 lines
1.3 KiB
Go
48 lines
1.3 KiB
Go
package oauth
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRefreshSingleflightsConcurrentCallers(t *testing.T) {
|
|
// The fake token endpoint counts refreshes; with a single-use refresh token,
|
|
// only ONE concurrent refresh must happen — the rest reuse the rotated token (M7).
|
|
fp := newFakeProvider(t, `{"access_token":"fresh-at","expires_in":3600}`)
|
|
env := map[string]string{
|
|
"ZERO_OAUTH_DEMO_CLIENT_ID": "client",
|
|
"ZERO_OAUTH_DEMO_TOKEN_URL": fp.server.URL + "/token",
|
|
}
|
|
m := managerFor(t, env, nil)
|
|
if err := m.store.Save(ProviderKey("demo"), Token{AccessToken: "stale", RefreshToken: "rt", ExpiresAt: time.Now().Add(-time.Hour)}); err != nil {
|
|
t.Fatalf("seed: %v", err)
|
|
}
|
|
|
|
const N = 10
|
|
var wg sync.WaitGroup
|
|
got := make([]string, N)
|
|
errs := make([]error, N)
|
|
for i := 0; i < N; i++ {
|
|
wg.Add(1)
|
|
go func(i int) {
|
|
defer wg.Done()
|
|
got[i], errs[i] = m.GetFresh(context.Background(), ProviderKey("demo"))
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
|
|
for i := range got {
|
|
if errs[i] != nil {
|
|
t.Fatalf("GetFresh[%d]: %v", i, errs[i])
|
|
}
|
|
if got[i] != "fresh-at" {
|
|
t.Errorf("GetFresh[%d] = %q, want fresh-at", i, got[i])
|
|
}
|
|
}
|
|
if hits := fp.tokenHits.Load(); hits != 1 {
|
|
t.Fatalf("expected exactly 1 refresh across %d concurrent callers, got %d", N, hits)
|
|
}
|
|
}
|