v0.3.1 minor refactor, tests changed to standard library
This commit is contained in:
+73
-56
@@ -2,80 +2,97 @@ package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSimpleTokenValidator(t *testing.T) {
|
||||
validator := NewSimpleTokenValidator()
|
||||
v := NewSimpleTokenValidator()
|
||||
const first, second = "test-token-123", "test-token-456"
|
||||
|
||||
token1 := "test-token-123"
|
||||
token2 := "test-token-456"
|
||||
isTrue(t, !v.ValidateToken(first), "empty validator rejects")
|
||||
|
||||
// Add tokens
|
||||
validator.AddToken(token1)
|
||||
validator.AddToken(token2)
|
||||
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")
|
||||
|
||||
// Validate existing tokens
|
||||
assert.True(t, validator.ValidateToken(token1))
|
||||
assert.True(t, validator.ValidateToken(token2))
|
||||
// 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")
|
||||
|
||||
// Invalid token
|
||||
assert.False(t, validator.ValidateToken("invalid-token"))
|
||||
v.RemoveToken(first)
|
||||
isTrue(t, !v.ValidateToken(first), "removed token")
|
||||
isTrue(t, v.ValidateToken(second), "surviving token")
|
||||
|
||||
// Remove token
|
||||
validator.RemoveToken(token1)
|
||||
assert.False(t, validator.ValidateToken(token1))
|
||||
assert.True(t, validator.ValidateToken(token2))
|
||||
// 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 TestConcurrentTokenValidator(t *testing.T) {
|
||||
validator := NewSimpleTokenValidator()
|
||||
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")
|
||||
|
||||
// Add tokens concurrently
|
||||
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 := 0; i < 100; i++ {
|
||||
for i := range n {
|
||||
wg.Add(1)
|
||||
go func(idx int) {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
token := fmt.Sprintf("token-%d", idx)
|
||||
validator.AddToken(token)
|
||||
}(i)
|
||||
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()
|
||||
|
||||
// Validate concurrently
|
||||
for i := 0; i < 100; i++ {
|
||||
wg.Add(1)
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
token := fmt.Sprintf("token-%d", idx)
|
||||
assert.True(t, validator.ValidateToken(token))
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// Remove concurrently
|
||||
for i := 0; i < 50; i++ {
|
||||
wg.Add(1)
|
||||
go func(idx int) {
|
||||
defer wg.Done()
|
||||
token := fmt.Sprintf("token-%d", idx)
|
||||
validator.RemoveToken(token)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
// Verify removal
|
||||
for i := 0; i < 50; i++ {
|
||||
token := fmt.Sprintf("token-%d", i)
|
||||
assert.False(t, validator.ValidateToken(token))
|
||||
}
|
||||
for i := 50; i < 100; i++ {
|
||||
token := fmt.Sprintf("token-%d", i)
|
||||
assert.True(t, validator.ValidateToken(token))
|
||||
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")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user