package web import ( "testing" "time" ) func TestOAuthStateSingleUse(t *testing.T) { s := newOAuthStates() s.put("st", time.Now().Add(time.Minute)) if !s.take("st") { t.Fatal("take of a fresh state = false, want true") } if s.take("st") { t.Fatal("take of a consumed state = true, want false") } } func TestOAuthStateUnknownOrExpired(t *testing.T) { s := newOAuthStates() if s.take("never-seen") { t.Fatal("take of an unknown state = true, want false") } s.put("stale", time.Now().Add(-time.Minute)) if s.take("stale") { t.Fatal("take of an expired state = true, want false") } } // The map is capped: a flood of starts evicts older states instead of growing, // and consumed states must not change that. func TestOAuthStateEviction(t *testing.T) { s := newOAuthStates() key := func(i, salt int) string { return string(rune('a'+i%26)) + string(rune('0'+i/26+salt*16)) } now := time.Now().Add(time.Hour) for i := 0; i < maxStates*2; i++ { s.put(key(i, 0), now) } if got := len(s.expiry); got != maxStates { t.Fatalf("states after a flood = %d, want %d", got, maxStates) } // Consume everything, then flood again: the map stays bounded. for state := range s.expiry { s.take(state) } for i := 0; i < maxStates; i++ { s.put(key(i, 1), now) } if got := len(s.expiry); got != maxStates { t.Fatalf("states after consume+flood = %d, want %d", got, maxStates) } }