Public source validation / validate (push) Failing after 3m8s
155 lines
3.7 KiB
Go
155 lines
3.7 KiB
Go
package authapi
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/itworx/pulse/internal/auth"
|
|
)
|
|
|
|
func testFlow(state string) flow {
|
|
return flow{authorization: auth.Authorization{State: state, Nonce: "nonce", CodeVerifier: "verifier"}, redirect: "/"}
|
|
}
|
|
|
|
func TestFlowStoreSingleUseAndExpiry(t *testing.T) {
|
|
now := time.Date(2026, 8, 4, 10, 0, 0, 0, time.UTC)
|
|
for _, test := range []struct {
|
|
name string
|
|
takeAt time.Time
|
|
twice bool
|
|
wantOK bool
|
|
wantAll int
|
|
}{
|
|
{name: "within ttl", takeAt: now.Add(time.Minute), wantOK: true},
|
|
{name: "at ttl boundary", takeAt: now.Add(defaultFlowTTL), wantOK: false},
|
|
{name: "after ttl", takeAt: now.Add(defaultFlowTTL + time.Second), wantOK: false},
|
|
{name: "replayed", takeAt: now.Add(time.Minute), twice: true, wantOK: false},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
store := newFlowStore(0, 0)
|
|
id, err := store.create(testFlow("state-1"), now)
|
|
if err != nil {
|
|
t.Fatalf("create: %v", err)
|
|
}
|
|
if test.twice {
|
|
if _, ok := store.take(id, test.takeAt); !ok {
|
|
t.Fatal("first take failed")
|
|
}
|
|
}
|
|
entry, ok := store.take(id, test.takeAt)
|
|
if ok != test.wantOK {
|
|
t.Fatalf("take ok = %v, want %v", ok, test.wantOK)
|
|
}
|
|
if ok && entry.authorization.State != "state-1" {
|
|
t.Fatalf("state = %q", entry.authorization.State)
|
|
}
|
|
if store.size() != 0 {
|
|
t.Fatalf("take left %d entries behind", store.size())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFlowStoreRejectsUnknownIdentifiers(t *testing.T) {
|
|
store := newFlowStore(0, 0)
|
|
for _, id := range []string{"", "unknown", " "} {
|
|
if _, ok := store.take(id, time.Now()); ok {
|
|
t.Fatalf("identifier %q was accepted", id)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFlowStoreIsBounded(t *testing.T) {
|
|
now := time.Now().UTC()
|
|
store := newFlowStore(time.Minute, 4)
|
|
for index := range 50 {
|
|
if _, err := store.create(testFlow("state"), now.Add(time.Duration(index)*time.Second)); err != nil {
|
|
t.Fatalf("create: %v", err)
|
|
}
|
|
}
|
|
if store.size() != 4 {
|
|
t.Fatalf("size = %d, want 4", store.size())
|
|
}
|
|
|
|
expired, err := store.create(testFlow("expired"), now)
|
|
if err != nil {
|
|
t.Fatalf("create: %v", err)
|
|
}
|
|
if _, err := store.create(testFlow("fresh"), now.Add(2*time.Minute)); err != nil {
|
|
t.Fatalf("create: %v", err)
|
|
}
|
|
if _, ok := store.take(expired, now.Add(2*time.Minute)); ok {
|
|
t.Fatal("expired flow survived the purge")
|
|
}
|
|
if store.size() > 4 {
|
|
t.Fatalf("size = %d, want at most 4", store.size())
|
|
}
|
|
}
|
|
|
|
func TestFlowStoreConcurrentAccess(t *testing.T) {
|
|
const workers = 128
|
|
store := newFlowStore(time.Minute, 64)
|
|
now := time.Now().UTC()
|
|
identifiers := make([]string, workers)
|
|
var wait sync.WaitGroup
|
|
for index := range workers {
|
|
wait.Add(1)
|
|
go func() {
|
|
defer wait.Done()
|
|
id, err := store.create(testFlow("state"), now)
|
|
if err != nil {
|
|
t.Errorf("create: %v", err)
|
|
return
|
|
}
|
|
identifiers[index] = id
|
|
}()
|
|
}
|
|
wait.Wait()
|
|
|
|
unique := make(map[string]struct{}, workers)
|
|
for _, id := range identifiers {
|
|
if id == "" {
|
|
t.Fatal("empty flow identifier")
|
|
}
|
|
unique[id] = struct{}{}
|
|
}
|
|
if len(unique) != workers {
|
|
t.Fatalf("unique identifiers = %d, want %d", len(unique), workers)
|
|
}
|
|
if store.size() > 64 {
|
|
t.Fatalf("size = %d, want at most 64", store.size())
|
|
}
|
|
|
|
var taken sync.WaitGroup
|
|
results := make(chan bool, 2*workers)
|
|
for _, id := range identifiers {
|
|
taken.Add(1)
|
|
go func() {
|
|
defer taken.Done()
|
|
_, ok := store.take(id, now)
|
|
results <- ok
|
|
}()
|
|
taken.Add(1)
|
|
go func() {
|
|
defer taken.Done()
|
|
_, ok := store.take(id, now)
|
|
results <- ok
|
|
}()
|
|
}
|
|
taken.Wait()
|
|
close(results)
|
|
accepted := 0
|
|
for ok := range results {
|
|
if ok {
|
|
accepted++
|
|
}
|
|
}
|
|
if accepted > 64 {
|
|
t.Fatalf("accepted %d flows, want at most the store capacity", accepted)
|
|
}
|
|
if store.size() != 0 {
|
|
t.Fatalf("size = %d, want 0", store.size())
|
|
}
|
|
}
|