233 lines
6.0 KiB
Go
233 lines
6.0 KiB
Go
package storage_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/uopi/uopi/internal/storage"
|
|
)
|
|
|
|
const sampleXML = `<interface id="test-if" name="Test Interface" version="1"><widget/></interface>`
|
|
|
|
func newStore(t *testing.T) *storage.Store {
|
|
t.Helper()
|
|
s, err := storage.New(t.TempDir())
|
|
if err != nil {
|
|
t.Fatalf("New: %v", err)
|
|
}
|
|
return s
|
|
}
|
|
|
|
// -------------------------------------------------------------------------- //
|
|
// List //
|
|
// -------------------------------------------------------------------------- //
|
|
|
|
func TestListEmpty(t *testing.T) {
|
|
s := newStore(t)
|
|
list, err := s.List()
|
|
if err != nil {
|
|
t.Fatalf("List: %v", err)
|
|
}
|
|
if len(list) != 0 {
|
|
t.Errorf("expected empty list, got %d items", len(list))
|
|
}
|
|
}
|
|
|
|
func TestListAfterCreate(t *testing.T) {
|
|
s := newStore(t)
|
|
if _, err := s.Create([]byte(sampleXML)); err != nil {
|
|
t.Fatalf("Create: %v", err)
|
|
}
|
|
list, err := s.List()
|
|
if err != nil {
|
|
t.Fatalf("List: %v", err)
|
|
}
|
|
if len(list) != 1 {
|
|
t.Fatalf("expected 1 item, got %d", len(list))
|
|
}
|
|
if list[0].Name != "Test Interface" {
|
|
t.Errorf("Name = %q, want %q", list[0].Name, "Test Interface")
|
|
}
|
|
if list[0].Version != 1 {
|
|
t.Errorf("Version = %d, want 1", list[0].Version)
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------- //
|
|
// Create + Get //
|
|
// -------------------------------------------------------------------------- //
|
|
|
|
func TestCreateAndGet(t *testing.T) {
|
|
s := newStore(t)
|
|
id, err := s.Create([]byte(sampleXML))
|
|
if err != nil {
|
|
t.Fatalf("Create: %v", err)
|
|
}
|
|
if id == "" {
|
|
t.Fatal("Create returned empty ID")
|
|
}
|
|
|
|
data, err := s.Get(id)
|
|
if err != nil {
|
|
t.Fatalf("Get(%q): %v", id, err)
|
|
}
|
|
if string(data) != sampleXML {
|
|
t.Errorf("Get returned %q, want %q", data, sampleXML)
|
|
}
|
|
}
|
|
|
|
func TestCreateUsesEmbeddedID(t *testing.T) {
|
|
s := newStore(t)
|
|
id, err := s.Create([]byte(sampleXML))
|
|
if err != nil {
|
|
t.Fatalf("Create: %v", err)
|
|
}
|
|
// ID derived from xml id attr or name slug.
|
|
if id == "" {
|
|
t.Error("ID should not be empty")
|
|
}
|
|
}
|
|
|
|
func TestCreateDuplicateGetsUniqueID(t *testing.T) {
|
|
s := newStore(t)
|
|
id1, err := s.Create([]byte(sampleXML))
|
|
if err != nil {
|
|
t.Fatalf("first Create: %v", err)
|
|
}
|
|
id2, err := s.Create([]byte(sampleXML))
|
|
if err != nil {
|
|
t.Fatalf("second Create: %v", err)
|
|
}
|
|
if id1 == id2 {
|
|
t.Errorf("duplicate Create returned same ID %q", id1)
|
|
}
|
|
}
|
|
|
|
func TestCreateInvalidXML(t *testing.T) {
|
|
s := newStore(t)
|
|
_, err := s.Create([]byte("not xml"))
|
|
if err == nil {
|
|
t.Error("expected error for invalid XML")
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------- //
|
|
// Get errors //
|
|
// -------------------------------------------------------------------------- //
|
|
|
|
func TestGetNotFound(t *testing.T) {
|
|
s := newStore(t)
|
|
_, err := s.Get("does-not-exist")
|
|
if !errors.Is(err, storage.ErrNotFound) {
|
|
t.Errorf("Get missing: want ErrNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetInvalidID(t *testing.T) {
|
|
s := newStore(t)
|
|
_, err := s.Get("../traversal")
|
|
if !errors.Is(err, storage.ErrNotFound) {
|
|
t.Errorf("Get path-traversal ID: want ErrNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetEmptyID(t *testing.T) {
|
|
s := newStore(t)
|
|
_, err := s.Get("")
|
|
if !errors.Is(err, storage.ErrNotFound) {
|
|
t.Errorf("Get empty ID: want ErrNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------- //
|
|
// Update //
|
|
// -------------------------------------------------------------------------- //
|
|
|
|
func TestUpdate(t *testing.T) {
|
|
s := newStore(t)
|
|
id, err := s.Create([]byte(sampleXML))
|
|
if err != nil {
|
|
t.Fatalf("Create: %v", err)
|
|
}
|
|
|
|
updated := `<interface id="test-if" name="Updated" version="2"><widget/></interface>`
|
|
if err := s.Update(id, []byte(updated)); err != nil {
|
|
t.Fatalf("Update: %v", err)
|
|
}
|
|
|
|
data, err := s.Get(id)
|
|
if err != nil {
|
|
t.Fatalf("Get after update: %v", err)
|
|
}
|
|
if string(data) != updated {
|
|
t.Errorf("post-update content mismatch")
|
|
}
|
|
}
|
|
|
|
func TestUpdateNotFound(t *testing.T) {
|
|
s := newStore(t)
|
|
err := s.Update("no-such-id", []byte(sampleXML))
|
|
if !errors.Is(err, storage.ErrNotFound) {
|
|
t.Errorf("Update missing: want ErrNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------- //
|
|
// Delete //
|
|
// -------------------------------------------------------------------------- //
|
|
|
|
func TestDelete(t *testing.T) {
|
|
s := newStore(t)
|
|
id, err := s.Create([]byte(sampleXML))
|
|
if err != nil {
|
|
t.Fatalf("Create: %v", err)
|
|
}
|
|
if err := s.Delete(id); err != nil {
|
|
t.Fatalf("Delete: %v", err)
|
|
}
|
|
_, err = s.Get(id)
|
|
if !errors.Is(err, storage.ErrNotFound) {
|
|
t.Errorf("Get after delete: want ErrNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDeleteNotFound(t *testing.T) {
|
|
s := newStore(t)
|
|
err := s.Delete("ghost")
|
|
if !errors.Is(err, storage.ErrNotFound) {
|
|
t.Errorf("Delete missing: want ErrNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------- //
|
|
// Clone //
|
|
// -------------------------------------------------------------------------- //
|
|
|
|
func TestClone(t *testing.T) {
|
|
s := newStore(t)
|
|
id, err := s.Create([]byte(sampleXML))
|
|
if err != nil {
|
|
t.Fatalf("Create: %v", err)
|
|
}
|
|
newID, err := s.Clone(id)
|
|
if err != nil {
|
|
t.Fatalf("Clone: %v", err)
|
|
}
|
|
if newID == id {
|
|
t.Error("Clone should produce a different ID")
|
|
}
|
|
orig, _ := s.Get(id)
|
|
copy, _ := s.Get(newID)
|
|
if string(orig) != string(copy) {
|
|
t.Error("Clone content should match original")
|
|
}
|
|
}
|
|
|
|
func TestCloneNotFound(t *testing.T) {
|
|
s := newStore(t)
|
|
_, err := s.Clone("ghost")
|
|
if !errors.Is(err, storage.ErrNotFound) {
|
|
t.Errorf("Clone missing: want ErrNotFound, got %v", err)
|
|
}
|
|
}
|