201 lines
5.2 KiB
Go
201 lines
5.2 KiB
Go
package confmgr
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func fptr(f float64) *float64 { return &f }
|
|
|
|
func sampleSet() ConfigSet {
|
|
return ConfigSet{
|
|
Name: "PSU",
|
|
Description: "power supply config",
|
|
Parameters: []Parameter{
|
|
{Key: "voltage", DS: "epics", Signal: "PSU:V", Type: TypeFloat, Default: 12.0, Mandatory: true, Min: fptr(0), Max: fptr(48)},
|
|
{Key: "enabled", DS: "epics", Signal: "PSU:EN", Type: TypeBool, Default: false},
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestCreateAndGetSet(t *testing.T) {
|
|
s, err := New(t.TempDir())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out, err := s.CreateSet(sampleSet(), "initial")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out.ID == "" {
|
|
t.Fatal("expected generated ID")
|
|
}
|
|
if out.Version != 1 {
|
|
t.Errorf("version: want 1, got %d", out.Version)
|
|
}
|
|
got, err := s.GetSet(out.ID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got.Name != "PSU" || len(got.Parameters) != 2 {
|
|
t.Errorf("round-trip mismatch: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestSetVersioning(t *testing.T) {
|
|
s, _ := New(t.TempDir())
|
|
created, _ := s.CreateSet(sampleSet(), "")
|
|
id := created.ID
|
|
|
|
// Update -> v2.
|
|
upd := sampleSet()
|
|
upd.Description = "edited"
|
|
v2, err := s.UpdateSet(id, upd, "edit")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v2.Version != 2 {
|
|
t.Fatalf("version after update: want 2, got %d", v2.Version)
|
|
}
|
|
|
|
versions, err := s.Versions(KindSet, id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(versions) != 2 {
|
|
t.Fatalf("want 2 versions, got %d", len(versions))
|
|
}
|
|
if !versions[0].Current || versions[0].Version != 2 {
|
|
t.Errorf("newest should be current v2: %+v", versions[0])
|
|
}
|
|
|
|
// Old version still retrievable.
|
|
old, err := s.GetSetVersion(id, 1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if old.Description != "power supply config" {
|
|
t.Errorf("v1 description changed: %q", old.Description)
|
|
}
|
|
|
|
// Promote v1 -> becomes v3 with original content.
|
|
if err := s.Promote(KindSet, id, 1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cur, _ := s.GetSet(id)
|
|
if cur.Version != 3 || cur.Description != "power supply config" {
|
|
t.Errorf("after promote: want v3 original desc, got v%d %q", cur.Version, cur.Description)
|
|
}
|
|
}
|
|
|
|
func TestForkSet(t *testing.T) {
|
|
s, _ := New(t.TempDir())
|
|
created, _ := s.CreateSet(sampleSet(), "")
|
|
_, _ = s.UpdateSet(created.ID, sampleSet(), "")
|
|
|
|
newID, err := s.Fork(KindSet, created.ID, 1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
forked, err := s.GetSet(newID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if forked.ID == created.ID {
|
|
t.Error("fork should have a new ID")
|
|
}
|
|
if forked.Version != 1 {
|
|
t.Errorf("fork version: want 1, got %d", forked.Version)
|
|
}
|
|
if forked.Tag != "" {
|
|
t.Errorf("fork tag should be cleared, got %q", forked.Tag)
|
|
}
|
|
}
|
|
|
|
func TestDeleteSetSoftDeletes(t *testing.T) {
|
|
s, _ := New(t.TempDir())
|
|
created, _ := s.CreateSet(sampleSet(), "")
|
|
if err := s.Delete(KindSet, created.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := s.GetSet(created.ID); err == nil {
|
|
t.Error("expected set to be gone after delete")
|
|
}
|
|
// Deleting again is a not-found.
|
|
if err := s.Delete(KindSet, created.ID); err != ErrNotFound {
|
|
t.Errorf("want ErrNotFound, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSetValidation(t *testing.T) {
|
|
s, _ := New(t.TempDir())
|
|
bad := ConfigSet{Name: "", Parameters: nil}
|
|
if _, err := s.CreateSet(bad, ""); err == nil {
|
|
t.Error("expected empty-name validation error")
|
|
}
|
|
dup := ConfigSet{Name: "x", Parameters: []Parameter{
|
|
{Key: "a", DS: "d", Signal: "s", Type: TypeFloat},
|
|
{Key: "a", DS: "d", Signal: "s2", Type: TypeFloat},
|
|
}}
|
|
if _, err := s.CreateSet(dup, ""); err == nil {
|
|
t.Error("expected duplicate-key validation error")
|
|
}
|
|
defaultOOR := ConfigSet{Name: "x", Parameters: []Parameter{
|
|
{Key: "a", DS: "d", Signal: "s", Type: TypeFloat, Default: 100.0, Max: fptr(10)},
|
|
}}
|
|
if _, err := s.CreateSet(defaultOOR, ""); err == nil {
|
|
t.Error("expected out-of-range default validation error")
|
|
}
|
|
}
|
|
|
|
func TestInstanceLifecycle(t *testing.T) {
|
|
s, _ := New(t.TempDir())
|
|
set, _ := s.CreateSet(sampleSet(), "")
|
|
|
|
inst := ConfigInstance{
|
|
Name: "nominal",
|
|
SetID: set.ID,
|
|
Values: map[string]any{"voltage": 24.0, "enabled": true},
|
|
}
|
|
out, err := s.CreateInstance(inst, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out.Version != 1 {
|
|
t.Errorf("instance version: want 1, got %d", out.Version)
|
|
}
|
|
|
|
// Update value -> v2.
|
|
out.Values["voltage"] = 36.0
|
|
v2, err := s.UpdateInstance(out.ID, out, "bump")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v2.Version != 2 {
|
|
t.Errorf("instance version after update: want 2, got %d", v2.Version)
|
|
}
|
|
}
|
|
|
|
func TestInstanceValidation(t *testing.T) {
|
|
s, _ := New(t.TempDir())
|
|
set, _ := s.CreateSet(sampleSet(), "")
|
|
|
|
// voltage is mandatory with a default, so omitting it is OK; but an
|
|
// out-of-range value must fail.
|
|
bad := ConfigInstance{Name: "x", SetID: set.ID, Values: map[string]any{"voltage": 999.0}}
|
|
if _, err := s.CreateInstance(bad, ""); err == nil {
|
|
t.Error("expected out-of-range value error")
|
|
}
|
|
|
|
// Unknown parameter key must fail.
|
|
unknown := ConfigInstance{Name: "x", SetID: set.ID, Values: map[string]any{"nope": 1.0}}
|
|
if _, err := s.CreateInstance(unknown, ""); err == nil {
|
|
t.Error("expected unknown-parameter error")
|
|
}
|
|
|
|
// Unknown set must fail.
|
|
missing := ConfigInstance{Name: "x", SetID: "does-not-exist", Values: map[string]any{}}
|
|
if _, err := s.CreateInstance(missing, ""); err == nil {
|
|
t.Error("expected missing-set error")
|
|
}
|
|
}
|