initial config manager
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package api_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestConfigSetCRUD exercises create → get → version → apply over HTTP, using
|
||||
// the stub data source's writable "setpoint" signal as the apply target.
|
||||
func TestConfigManagerEndToEnd(t *testing.T) {
|
||||
srv, teardown := setup(t)
|
||||
defer teardown()
|
||||
|
||||
// Create a config set targeting the stub's writable setpoint.
|
||||
setBody := map[string]any{
|
||||
"name": "Stub PSU",
|
||||
"parameters": []map[string]any{
|
||||
{"key": "sp", "ds": "stub", "signal": "setpoint", "type": "float64", "default": 42.0, "mandatory": true, "min": 0.0, "max": 100.0},
|
||||
},
|
||||
}
|
||||
resp := postJSON(t, srv, "/api/v1/config/sets", setBody)
|
||||
assertStatus(t, resp, http.StatusCreated)
|
||||
var set struct {
|
||||
ID string `json:"id"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
readJSON(t, resp, &set)
|
||||
if set.ID == "" || set.Version != 1 {
|
||||
t.Fatalf("unexpected created set: %+v", set)
|
||||
}
|
||||
|
||||
// List sets includes it.
|
||||
resp = get(t, srv, "/api/v1/config/sets")
|
||||
assertStatus(t, resp, http.StatusOK)
|
||||
var sets []map[string]any
|
||||
readJSON(t, resp, &sets)
|
||||
if len(sets) != 1 {
|
||||
t.Fatalf("want 1 set, got %d", len(sets))
|
||||
}
|
||||
|
||||
// Create an instance assigning a concrete value.
|
||||
instBody := map[string]any{
|
||||
"name": "nominal",
|
||||
"setId": set.ID,
|
||||
"values": map[string]any{"sp": 73.0},
|
||||
}
|
||||
resp = postJSON(t, srv, "/api/v1/config/instances", instBody)
|
||||
assertStatus(t, resp, http.StatusCreated)
|
||||
var inst struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
readJSON(t, resp, &inst)
|
||||
if inst.ID == "" {
|
||||
t.Fatal("instance missing id")
|
||||
}
|
||||
|
||||
// Apply writes the value to the target signal.
|
||||
resp = postJSON(t, srv, "/api/v1/config/instances/"+inst.ID+"/apply", nil)
|
||||
assertStatus(t, resp, http.StatusOK)
|
||||
var res struct {
|
||||
Applied int `json:"applied"`
|
||||
Failed int `json:"failed"`
|
||||
Entries []struct {
|
||||
Signal string `json:"signal"`
|
||||
OK bool `json:"ok"`
|
||||
} `json:"entries"`
|
||||
}
|
||||
readJSON(t, resp, &res)
|
||||
if res.Applied != 1 || res.Failed != 0 {
|
||||
t.Fatalf("apply summary: applied=%d failed=%d", res.Applied, res.Failed)
|
||||
}
|
||||
if len(res.Entries) != 1 || res.Entries[0].Signal != "setpoint" || !res.Entries[0].OK {
|
||||
t.Errorf("unexpected apply entries: %+v", res.Entries)
|
||||
}
|
||||
|
||||
// Delete the set soft-deletes it.
|
||||
resp = deleteReq(t, srv, "/api/v1/config/sets/"+set.ID)
|
||||
assertStatus(t, resp, http.StatusNoContent)
|
||||
resp = get(t, srv, "/api/v1/config/sets/"+set.ID)
|
||||
assertStatus(t, resp, http.StatusNotFound)
|
||||
}
|
||||
|
||||
// TestConfigInstanceRejectsInvalidValue verifies server-side validation against
|
||||
// the bound set (value above the parameter's max).
|
||||
func TestConfigInstanceRejectsInvalidValue(t *testing.T) {
|
||||
srv, teardown := setup(t)
|
||||
defer teardown()
|
||||
|
||||
resp := postJSON(t, srv, "/api/v1/config/sets", map[string]any{
|
||||
"name": "S",
|
||||
"parameters": []map[string]any{
|
||||
{"key": "sp", "ds": "stub", "signal": "setpoint", "type": "float64", "max": 10.0},
|
||||
},
|
||||
})
|
||||
assertStatus(t, resp, http.StatusCreated)
|
||||
var set struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
readJSON(t, resp, &set)
|
||||
|
||||
resp = postJSON(t, srv, "/api/v1/config/instances", map[string]any{
|
||||
"name": "bad",
|
||||
"setId": set.ID,
|
||||
"values": map[string]any{"sp": 999.0},
|
||||
})
|
||||
assertStatus(t, resp, http.StatusBadRequest)
|
||||
}
|
||||
Reference in New Issue
Block a user