Files
auth/token_test.go
T

99 lines
2.6 KiB
Go

package auth
import (
"fmt"
"strings"
"sync"
"testing"
)
func TestSimpleTokenValidator(t *testing.T) {
v := NewSimpleTokenValidator()
const first, second = "test-token-123", "test-token-456"
isTrue(t, !v.ValidateToken(first), "empty validator rejects")
v.AddToken(first)
v.AddToken(second)
isTrue(t, v.ValidateToken(first), "first token")
isTrue(t, v.ValidateToken(second), "second token")
isTrue(t, !v.ValidateToken("invalid-token"), "unknown token")
// matching is exact
isTrue(t, !v.ValidateToken(first+"x"), "suffix")
isTrue(t, !v.ValidateToken(first[:len(first)-1]), "prefix")
isTrue(t, !v.ValidateToken(strings.ToUpper(first)), "case")
isTrue(t, !v.ValidateToken(" "+first), "leading space")
v.RemoveToken(first)
isTrue(t, !v.ValidateToken(first), "removed token")
isTrue(t, v.ValidateToken(second), "surviving token")
// removing an absent token is a no-op
v.RemoveToken("never-added")
eq(t, len(v.tokens), 1, "entry count after no-op removal")
// repeated adds are idempotent
v.AddToken(second)
v.AddToken(second)
eq(t, len(v.tokens), 1, "entry count after duplicate adds")
// the empty token is storable and matches only itself
v.AddToken("")
isTrue(t, v.ValidateToken(""), "empty token accepted once added")
v.RemoveToken("")
isTrue(t, !v.ValidateToken(""), "empty token removed")
}
func TestSimpleTokenValidatorKeying(t *testing.T) {
v := NewSimpleTokenValidator()
tokens := []string{
"", "a", "a\x00b", "a\x00c", "🔑", strings.Repeat("a", 1<<16),
}
for _, tok := range tokens {
v.AddToken(tok)
}
eq(t, len(v.tokens), len(tokens), "distinct entries")
for i, tok := range tokens {
isTrue(t, v.ValidateToken(tok), fmt.Sprintf("token %d", i))
}
for i, tok := range tokens {
v.RemoveToken(tok)
isTrue(t, !v.ValidateToken(tok), fmt.Sprintf("token %d removed", i))
}
eq(t, len(v.tokens), 0, "empty after removal")
}
func TestSimpleTokenValidatorConcurrent(t *testing.T) {
v := NewSimpleTokenValidator()
const n = 256
// pre-populate half the space so readers see hits and misses
for i := n / 2; i < n; i++ {
v.AddToken(fmt.Sprintf("token-%d", i))
}
// each goroutine owns one token, so the final state is deterministic
var wg sync.WaitGroup
for i := range n {
wg.Add(1)
go func() {
defer wg.Done()
token := fmt.Sprintf("token-%d", i)
v.AddToken(token)
v.ValidateToken(token)
v.ValidateToken(fmt.Sprintf("absent-%d", i))
if i%2 == 0 {
v.RemoveToken(token)
}
}()
}
wg.Wait()
for i := range n {
eq(t, v.ValidateToken(fmt.Sprintf("token-%d", i)), i%2 != 0, fmt.Sprintf("token %d", i))
}
eq(t, len(v.tokens), n/2, "surviving entries")
}