package storage import ( "context" "errors" "os" "path/filepath" "testing" ) func TestLocalStoreRoundTrip(t *testing.T) { ctx := context.Background() s, err := NewLocal(t.TempDir()) if err != nil { t.Fatalf("NewLocal: %v", err) } key := "opportunity_records/sam.gov/abc123.json" data := []byte(`{"noticeId":"abc123"}`) if err := s.Put(ctx, key, data); err != nil { t.Fatalf("Put: %v", err) } got, err := s.Get(ctx, key) if err != nil { t.Fatalf("Get: %v", err) } if string(got) != string(data) { t.Fatalf("round trip mismatch: %s", got) } ok, err := s.Exists(ctx, key) if err != nil || !ok { t.Fatalf("Exists = %v, %v", ok, err) } if err := s.Delete(ctx, key); err != nil { t.Fatalf("Delete: %v", err) } if _, err := s.Get(ctx, key); !errors.Is(err, ErrNotFound) { t.Fatalf("after delete want ErrNotFound, got %v", err) } } func TestLocalStoreRejectsTraversal(t *testing.T) { ctx := context.Background() root := t.TempDir() s, err := NewLocal(root) if err != nil { t.Fatalf("NewLocal: %v", err) } for _, key := range []string{"../escape.json", "/etc/passwd", "a/../../escape", "", "..", "."} { if err := s.Put(ctx, key, []byte("x")); err == nil { t.Fatalf("Put(%q) should have been rejected", key) } } if _, err := os.Stat(filepath.Join(filepath.Dir(root), "escape.json")); err == nil { t.Fatal("a traversal key wrote outside the root") } } func TestMemoryStoreRoundTrip(t *testing.T) { ctx := context.Background() s := NewMemory() if err := s.Put(ctx, "k/a.json", []byte("v")); err != nil { t.Fatalf("Put: %v", err) } got, err := s.Get(ctx, "k/a.json") if err != nil || string(got) != "v" { t.Fatalf("Get = %q, %v", got, err) } if _, err := s.Get(ctx, "missing"); !errors.Is(err, ErrNotFound) { t.Fatalf("want ErrNotFound, got %v", err) } // A returned slice must be a copy: mutating it must not change the stored bytes. got[0] = 'X' again, _ := s.Get(ctx, "k/a.json") if string(again) != "v" { t.Fatalf("stored value was aliased: %q", again) } } func TestSHA256HexStable(t *testing.T) { if SHA256Hex([]byte("payload")) != SHA256Hex([]byte("payload")) { t.Fatal("sha not stable") } if SHA256Hex([]byte("a")) == SHA256Hex([]byte("b")) { t.Fatal("sha collision") } }