108 lines
3.1 KiB
Go
108 lines
3.1 KiB
Go
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)
|
|
}
|