package token import ( "context" "sync" "sync/atomic" "testing" "time" "git.5iot.com/iotlcm-public/iotlcm-upstream-chan/internal/model" ) func TestTokenManagersShareRefreshFlightByChannel(t *testing.T) { ctx := context.Background() chanKey := "shared-flight-" + time.Now().Format("150405.000000000") var fetchCalls atomic.Int32 var persistCalls atomic.Int32 start := make(chan struct{}) release := make(chan struct{}) fetcher := TokenFetcherFunc(func(context.Context, string) (OneLinkToken, error) { fetchCalls.Add(1) close(start) <-release return OneLinkToken{Value: "fresh-token", CreatedAt: time.Now(), ExpiresAt: time.Now().Add(time.Hour)}, nil }) persister := TokenPersisterFunc(func(context.Context, *model.UpdateAccessTokenInput) error { persistCalls.Add(1) return nil }) first := NewTokenManager(fetcher, WithPersister(persister)) second := NewTokenManager(fetcher, WithPersister(persister)) results := make(chan OneLinkToken, 2) errors := make(chan error, 2) var wg sync.WaitGroup for _, manager := range []TokenManager{first, second} { wg.Add(1) go func(manager TokenManager) { defer wg.Done() token, err := manager.Get(ctx, chanKey) results <- token errors <- err }(manager) } <-start close(release) wg.Wait() close(results) close(errors) for err := range errors { if err != nil { t.Fatal(err) } } for token := range results { if token.Value != "fresh-token" { t.Fatalf("token = %+v", token) } } if fetchCalls.Load() != 1 || persistCalls.Load() != 1 { t.Fatalf("fetch calls=%d persist calls=%d, want one each", fetchCalls.Load(), persistCalls.Load()) } }