package erasure import ( "sync" "testing" ) func TestShardStorePutGetRoundTrip(t *testing.T) { store := NewShardStore() p := DefaultParams() shards := [][]byte{[]byte("a"), []byte("b"), []byte("c"), []byte("d"), []byte("e"), []byte("f")} store.Put("tok-1", p, shards) got, ok := store.Get("tok-1", 2) if !ok || string(got) != "c" { t.Fatalf("get shard 2 = %q ok=%v", got, ok) } storedP, ok := store.ParamsFor("tok-1") if !ok || storedP.DataShards != DefaultDataShards { t.Fatalf("params=%+v ok=%v", storedP, ok) } } func TestShardStoreGetReturnsCopy(t *testing.T) { store := NewShardStore() p := DefaultParams() shards := [][]byte{[]byte("mutable")} store.Put("tok-copy", p, shards) got, ok := store.Get("tok-copy", 0) if !ok { t.Fatal("expected shard") } got[0] = 'X' again, _ := store.Get("tok-copy", 0) if again[0] == 'X' { t.Fatal("Get should return defensive copy") } } func TestShardStoreNilAndEmptyGuards(t *testing.T) { var nilStore *ShardStore nilStore.Put("x", DefaultParams(), [][]byte{[]byte("a")}) if _, ok := nilStore.Get("x", 0); ok { t.Fatal("nil store should not serve shards") } if _, ok := nilStore.ParamsFor("x"); ok { t.Fatal("nil store should not serve params") } nilStore.Delete("x") store := NewShardStore() store.Put("", DefaultParams(), [][]byte{[]byte("a")}) store.Put("empty-shards", DefaultParams(), nil) if _, ok := store.Get("", 0); ok { t.Fatal("empty token should not be stored") } if _, ok := store.Get("empty-shards", 0); ok { t.Fatal("empty shard list should not be stored") } if _, ok := store.Get("missing", 0); ok { t.Fatal("missing token should miss") } if _, ok := store.Get("missing", -1); ok { t.Fatal("negative index should miss") } } func TestShardStoreDelete(t *testing.T) { store := NewShardStore() p := DefaultParams() store.Put("gone", p, [][]byte{[]byte("x")}) store.Delete("gone") if _, ok := store.Get("gone", 0); ok { t.Fatal("deleted token should miss") } if _, ok := store.ParamsFor("gone"); ok { t.Fatal("deleted token params should miss") } } func TestShardStoreConcurrentAccess(t *testing.T) { store := NewShardStore() p := DefaultParams() payload := []byte("concurrent-erasure-store-payload") shards, _, err := Encode(payload, p) if err != nil { t.Fatal(err) } store.Put("concurrent", p, shards) var wg sync.WaitGroup for i := 0; i < 8; i++ { wg.Add(1) go func(idx int) { defer wg.Done() for j := 0; j < 50; j++ { if _, ok := store.Get("concurrent", idx%len(shards)); !ok { t.Errorf("worker %d miss on iter %d", idx, j) } if _, ok := store.ParamsFor("concurrent"); !ok { t.Errorf("worker %d params miss", idx) } } }(i) } wg.Wait() }