147 lines
4.3 KiB
Go
147 lines
4.3 KiB
Go
package api_test
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
)
|
|
|
|
// TestConfigRuleCRUD exercises the full config-rule REST surface: list, create,
|
|
// get, update, versioning (list/get/promote/fork), check, preview, and delete,
|
|
// plus the principal error paths.
|
|
func TestConfigRuleCRUD(t *testing.T) {
|
|
srv, teardown := setup(t)
|
|
defer teardown()
|
|
|
|
// A set the rule (and preview) can bind to.
|
|
resp := postJSON(t, srv, "/api/v1/config/sets", map[string]any{
|
|
"name": "S",
|
|
"parameters": []map[string]any{
|
|
{"key": "voltage", "ds": "stub", "signal": "setpoint", "type": "float64", "default": 12.0},
|
|
},
|
|
})
|
|
assertStatus(t, resp, http.StatusCreated)
|
|
var set struct {
|
|
ID string `json:"id"`
|
|
}
|
|
readJSON(t, resp, &set)
|
|
|
|
// Empty list initially.
|
|
resp = get(t, srv, "/api/v1/config/rules")
|
|
assertStatus(t, resp, http.StatusOK)
|
|
var list []map[string]any
|
|
readJSON(t, resp, &list)
|
|
if len(list) != 0 {
|
|
t.Fatalf("expected no rules, got %d", len(list))
|
|
}
|
|
|
|
// Create.
|
|
resp = postJSON(t, srv, "/api/v1/config/rules", map[string]any{
|
|
"name": "cap",
|
|
"setId": set.ID,
|
|
"source": "voltage: <=24",
|
|
})
|
|
assertStatus(t, resp, http.StatusCreated)
|
|
var rule struct {
|
|
ID string `json:"id"`
|
|
Version int `json:"version"`
|
|
}
|
|
readJSON(t, resp, &rule)
|
|
if rule.ID == "" {
|
|
t.Fatal("rule missing id")
|
|
}
|
|
|
|
// Create with invalid CUE → 400.
|
|
resp = postJSON(t, srv, "/api/v1/config/rules", map[string]any{
|
|
"name": "bad",
|
|
"setId": set.ID,
|
|
"source": "voltage: <=",
|
|
})
|
|
assertStatus(t, resp, http.StatusBadRequest)
|
|
|
|
// Create with malformed JSON → 400.
|
|
resp = postRaw(t, srv, "/api/v1/config/rules", "application/json", []byte(`{not json`))
|
|
assertStatus(t, resp, http.StatusBadRequest)
|
|
|
|
// Get.
|
|
resp = get(t, srv, "/api/v1/config/rules/"+rule.ID)
|
|
assertStatus(t, resp, http.StatusOK)
|
|
resp.Body.Close()
|
|
|
|
// Get missing → 404.
|
|
resp = get(t, srv, "/api/v1/config/rules/nope")
|
|
assertStatus(t, resp, http.StatusNotFound)
|
|
|
|
// Update (bumps version, creates backup).
|
|
resp = putRaw(t, srv, "/api/v1/config/rules/"+rule.ID, "application/json",
|
|
[]byte(`{"name":"cap2","setId":"`+set.ID+`","source":"voltage: <=30"}`))
|
|
assertStatus(t, resp, http.StatusOK)
|
|
|
|
// List versions.
|
|
resp = get(t, srv, "/api/v1/config/rules/"+rule.ID+"/versions")
|
|
assertStatus(t, resp, http.StatusOK)
|
|
var versions []map[string]any
|
|
readJSON(t, resp, &versions)
|
|
if len(versions) < 2 {
|
|
t.Fatalf("expected >=2 rule versions, got %d", len(versions))
|
|
}
|
|
|
|
// Get v1.
|
|
resp = get(t, srv, "/api/v1/config/rules/"+rule.ID+"/versions/1")
|
|
assertStatus(t, resp, http.StatusOK)
|
|
resp.Body.Close()
|
|
|
|
// Bad version path → 400.
|
|
resp = get(t, srv, "/api/v1/config/rules/"+rule.ID+"/versions/xyz")
|
|
assertStatus(t, resp, http.StatusBadRequest)
|
|
|
|
// Promote v1.
|
|
resp = postRaw(t, srv, "/api/v1/config/rules/"+rule.ID+"/versions/1/promote", "application/json", nil)
|
|
assertStatus(t, resp, http.StatusOK)
|
|
|
|
// Fork v1 → new id.
|
|
resp = postRaw(t, srv, "/api/v1/config/rules/"+rule.ID+"/versions/1/fork", "application/json", nil)
|
|
assertStatus(t, resp, http.StatusCreated)
|
|
var fork struct {
|
|
ID string `json:"id"`
|
|
}
|
|
readJSON(t, resp, &fork)
|
|
if fork.ID == "" || fork.ID == rule.ID {
|
|
t.Errorf("fork id = %q, want fresh id", fork.ID)
|
|
}
|
|
|
|
// Check (live validation of an unsaved source against sample values).
|
|
resp = postJSON(t, srv, "/api/v1/config/rules/check", map[string]any{
|
|
"source": "voltage: <=24",
|
|
"values": map[string]any{"voltage": 20.0},
|
|
})
|
|
assertStatus(t, resp, http.StatusOK)
|
|
resp.Body.Close()
|
|
|
|
// Check with malformed JSON → 400.
|
|
resp = postRaw(t, srv, "/api/v1/config/rules/check", "application/json", []byte(`{`))
|
|
assertStatus(t, resp, http.StatusBadRequest)
|
|
|
|
// Preview against the bound set's live signals.
|
|
resp = postJSON(t, srv, "/api/v1/config/rules/preview", map[string]any{
|
|
"setId": set.ID,
|
|
"source": "voltage: <=24",
|
|
})
|
|
assertStatus(t, resp, http.StatusOK)
|
|
resp.Body.Close()
|
|
|
|
// Preview with an unknown set → 404.
|
|
resp = postJSON(t, srv, "/api/v1/config/rules/preview", map[string]any{
|
|
"setId": "does-not-exist",
|
|
"source": "voltage: <=24",
|
|
})
|
|
assertStatus(t, resp, http.StatusNotFound)
|
|
|
|
// Delete.
|
|
resp = deleteReq(t, srv, "/api/v1/config/rules/"+rule.ID)
|
|
assertStatus(t, resp, http.StatusNoContent)
|
|
|
|
// Delete missing → 404.
|
|
resp = deleteReq(t, srv, "/api/v1/config/rules/"+rule.ID)
|
|
assertStatus(t, resp, http.StatusNotFound)
|
|
}
|