66 lines
1.5 KiB
Go
66 lines
1.5 KiB
Go
package privilege
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type fakeAcquirer struct {
|
|
validateErr error
|
|
validates int32
|
|
refreshes int32
|
|
}
|
|
|
|
func (f *fakeAcquirer) Validate(ctx context.Context) error {
|
|
atomic.AddInt32(&f.validates, 1)
|
|
return f.validateErr
|
|
}
|
|
func (f *fakeAcquirer) ValidateNonInteractive(ctx context.Context) error {
|
|
atomic.AddInt32(&f.refreshes, 1)
|
|
return nil
|
|
}
|
|
|
|
func TestAcquireFailsIfValidateFails(t *testing.T) {
|
|
a := &fakeAcquirer{validateErr: errors.New("wrong password")}
|
|
_, err := Acquire(context.Background(), a, 10*time.Millisecond)
|
|
if err == nil {
|
|
t.Fatal("expected error")
|
|
}
|
|
if atomic.LoadInt32(&a.refreshes) != 0 {
|
|
t.Fatal("keepalive ran despite Validate failure")
|
|
}
|
|
}
|
|
|
|
func TestAcquireStartsKeepaliveAndStops(t *testing.T) {
|
|
a := &fakeAcquirer{}
|
|
k, err := Acquire(context.Background(), a, 5*time.Millisecond)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
time.Sleep(25 * time.Millisecond)
|
|
k.Stop()
|
|
got := atomic.LoadInt32(&a.refreshes)
|
|
if got < 2 {
|
|
t.Fatalf("refreshes = %d, want >= 2", got)
|
|
}
|
|
|
|
// After Stop, no additional refreshes should occur.
|
|
snap := atomic.LoadInt32(&a.refreshes)
|
|
time.Sleep(20 * time.Millisecond)
|
|
if after := atomic.LoadInt32(&a.refreshes); after != snap {
|
|
t.Fatalf("refreshes continued after Stop: %d → %d", snap, after)
|
|
}
|
|
}
|
|
|
|
func TestStopIsIdempotent(t *testing.T) {
|
|
k, err := Acquire(context.Background(), &fakeAcquirer{}, 5*time.Millisecond)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
k.Stop()
|
|
k.Stop() // must not panic or hang
|
|
}
|