Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

211 lines
4.9 KiB
Go

package streamable
import (
"sync"
"testing"
"time"
)
func TestMemoryStore_CreateAndGet(t *testing.T) {
s := NewMemoryStore(time.Minute)
defer s.Close()
id, err := s.Create(SessionState{ClientName: "claude"})
if err != nil {
t.Fatalf("Create: %v", err)
}
if id == "" {
t.Fatal("Create returned empty id")
}
got, ok := s.Get(id)
if !ok {
t.Fatalf("Get(%q): not found", id)
}
if got.ClientName != "claude" {
t.Errorf("ClientName = %q, want claude", got.ClientName)
}
if got.ID != id {
t.Errorf("ID = %q, want %q", got.ID, id)
}
if got.CreatedAt.IsZero() || got.LastUsed.IsZero() {
t.Error("timestamps not set on create")
}
if s.Len() != 1 {
t.Errorf("Len() = %d, want 1", s.Len())
}
}
func TestMemoryStore_GetUnknownReturnsNotOK(t *testing.T) {
s := NewMemoryStore(time.Minute)
defer s.Close()
if _, ok := s.Get("nonexistent"); ok {
t.Error("Get of unknown id returned ok=true")
}
if _, ok := s.Get(""); ok {
t.Error("Get(\"\") returned ok=true")
}
}
func TestMemoryStore_UpdatePersists(t *testing.T) {
s := NewMemoryStore(time.Minute)
defer s.Close()
id, _ := s.Create(SessionState{})
got, _ := s.Get(id)
got.ClientName = "cursor"
got.Initialized = true
if err := s.Update(got); err != nil {
t.Fatalf("Update: %v", err)
}
back, ok := s.Get(id)
if !ok || back.ClientName != "cursor" || !back.Initialized {
t.Errorf("Update didn't persist: %+v", back)
}
}
func TestMemoryStore_UpdateUnknownIsNoop(t *testing.T) {
s := NewMemoryStore(time.Minute)
defer s.Close()
if err := s.Update(SessionState{ID: "never_seen"}); err != nil {
t.Errorf("Update of unknown id returned err: %v", err)
}
if s.Len() != 0 {
t.Errorf("Update of unknown id added entry: Len() = %d", s.Len())
}
}
func TestMemoryStore_DeleteIsIdempotent(t *testing.T) {
s := NewMemoryStore(time.Minute)
defer s.Close()
id, _ := s.Create(SessionState{})
s.Delete(id)
s.Delete(id)
s.Delete("never_seen")
s.Delete("")
if s.Len() != 0 {
t.Errorf("Len() = %d, want 0", s.Len())
}
}
func TestMemoryStore_TTLEviction(t *testing.T) {
s := NewMemoryStore(50 * time.Millisecond)
defer s.Close()
id, _ := s.Create(SessionState{})
// Sleep past the TTL so the next Get falls into the eviction path.
time.Sleep(80 * time.Millisecond)
if _, ok := s.Get(id); ok {
t.Error("Get returned an expired session")
}
}
func TestMemoryStore_SweepNowEvictsStale(t *testing.T) {
s := NewMemoryStore(50 * time.Millisecond)
defer s.Close()
id1, _ := s.Create(SessionState{})
id2, _ := s.Create(SessionState{})
if s.Len() != 2 {
t.Fatalf("Len() = %d, want 2", s.Len())
}
// Force every session to look stale by sweeping with a far-future "now".
evicted := s.SweepNow(time.Now().Add(1 * time.Hour))
if evicted != 2 {
t.Errorf("SweepNow evicted = %d, want 2", evicted)
}
if _, ok := s.Get(id1); ok {
t.Error("id1 should have been evicted")
}
if _, ok := s.Get(id2); ok {
t.Error("id2 should have been evicted")
}
}
func TestMemoryStore_GetRefreshesLastUsed(t *testing.T) {
s := NewMemoryStore(time.Hour)
defer s.Close()
id, _ := s.Create(SessionState{})
first, _ := s.Get(id)
time.Sleep(10 * time.Millisecond)
second, _ := s.Get(id)
if !second.LastUsed.After(first.LastUsed) {
t.Errorf("LastUsed didn't advance: first=%v second=%v", first.LastUsed, second.LastUsed)
}
}
func TestMemoryStore_ConcurrentCreate(t *testing.T) {
s := NewMemoryStore(time.Hour)
defer s.Close()
const N = 100
var wg sync.WaitGroup
ids := make(chan string, N)
for i := 0; i < N; i++ {
wg.Add(1)
go func() {
defer wg.Done()
id, err := s.Create(SessionState{})
if err != nil {
t.Errorf("Create: %v", err)
return
}
ids <- id
}()
}
wg.Wait()
close(ids)
seen := make(map[string]bool, N)
for id := range ids {
if seen[id] {
t.Errorf("duplicate id: %s", id)
}
seen[id] = true
}
if s.Len() != N {
t.Errorf("Len() = %d, want %d", s.Len(), N)
}
}
func TestMemoryStore_CloseIsIdempotent(t *testing.T) {
s := NewMemoryStore(time.Hour)
s.Close()
s.Close() // would panic on a double-close channel without the once gate.
}
func TestStatelessStore_AllOpsAreNoops(t *testing.T) {
s := StatelessStore{}
id, err := s.Create(SessionState{ClientName: "ignored"})
if err != nil || id != "" {
t.Errorf("Create returned (%q, %v), want (\"\", nil)", id, err)
}
if _, ok := s.Get("anything"); ok {
t.Error("Get returned ok=true")
}
if err := s.Update(SessionState{ID: "x"}); err != nil {
t.Errorf("Update: %v", err)
}
s.Delete("y")
if s.Len() != 0 {
t.Errorf("Len() = %d, want 0", s.Len())
}
}
func TestNewSessionID_IsRandomAndHex(t *testing.T) {
a, err := newSessionID()
if err != nil {
t.Fatalf("newSessionID: %v", err)
}
b, err := newSessionID()
if err != nil {
t.Fatalf("newSessionID: %v", err)
}
if a == b {
t.Errorf("got two identical ids: %q", a)
}
if len(a) != 32 {
t.Errorf("len(id) = %d, want 32", len(a))
}
for _, c := range a {
if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
t.Errorf("id contains non-hex byte %q", c)
}
}
}