Files
rclone/lib/oauthutil/renew_test.go
T
TastyHeadphones 8290a478c8 oauthutil: fix Renew.Shutdown nil timer panic and race
Shutdown was calling expiryTimer.Stop without holding ts.mu, so it could
panic if OnExpiry had not created the timer yet, and raced the write in
OnExpiry. Hold the lock and skip Stop when the timer is still nil.

Fixes #9980

(cherry picked from commit 80e462d48c)
2026-10-08 17:17:11 +01:00

44 lines
1.1 KiB
Go

package oauthutil
import (
"context"
"encoding/json"
"testing"
"time"
"github.com/rclone/rclone/fs/config/configmap"
)
func newTestTokenSource(t *testing.T) *TokenSource {
t.Helper()
tok, err := json.Marshal(map[string]any{
"access_token": "A",
"token_type": "bearer",
"refresh_token": "R",
"expiry": time.Now().Add(time.Hour).UTC().Format(time.RFC3339),
})
if err != nil {
t.Fatal(err)
}
_, ts, err := NewClient(context.Background(), "repro", configmap.Simple{"token": string(tok)},
&Config{TokenURL: "https://127.0.0.1:1/token"})
if err != nil {
t.Fatal(err)
}
return ts
}
// Shutdown before the renewOnExpiry goroutine calls OnExpiry must not panic.
func TestShutdownBeforeRenewerStarts(t *testing.T) {
for i := 0; i < 1000; i++ {
NewRenew("repro", newTestTokenSource(t), func() error { return nil }).Shutdown()
}
}
// Shutdown must not race OnExpiry's write of expiryTimer.
func TestShutdownRacesOnExpiry(t *testing.T) {
r := NewRenew("repro", newTestTokenSource(t), func() error { return nil })
time.Sleep(50 * time.Millisecond)
r.Shutdown()
}