Testing
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user