package main import ( "encoding/json" "net/http" "testing" "gcy_hpc_server/internal/testutil/testenv" ) // clusterNodeData mirrors the NodeResponse DTO returned by the API. type clusterNodeData struct { Name string `json:"name"` State []string `json:"state"` CPUs int32 `json:"cpus"` RealMemory int64 `json:"real_memory"` } // clusterPartitionData mirrors the PartitionResponse DTO returned by the API. type clusterPartitionData struct { Name string `json:"name"` State []string `json:"state"` TotalNodes int32 `json:"total_nodes,omitempty"` TotalCPUs int32 `json:"total_cpus,omitempty"` } // clusterDiagStat mirrors a single entry from the diag statistics. type clusterDiagStat struct { Parts []struct { Param string `json:"param"` } `json:"parts,omitempty"` } // clusterDecodeAll decodes the response and returns status, success, and raw data. func clusterDecodeAll(env *testenv.TestEnv, resp *http.Response) (statusCode int, success bool, data json.RawMessage, err error) { statusCode = resp.StatusCode success, data, err = env.DecodeResponse(resp) return } // TestIntegration_Cluster_Nodes verifies GET /api/v1/nodes returns the 3 pre-loaded mock nodes. func TestIntegration_Cluster_Nodes(t *testing.T) { env := testenv.NewTestEnv(t) resp := env.DoRequest(http.MethodGet, "/api/v1/nodes", nil) status, success, data, err := clusterDecodeAll(env, resp) if err != nil { t.Fatalf("decode response: %v", err) } if status != http.StatusOK { t.Fatalf("expected status 200, got %d", status) } if !success { t.Fatal("expected success=true") } var nodes []clusterNodeData if err := json.Unmarshal(data, &nodes); err != nil { t.Fatalf("unmarshal nodes: %v", err) } if len(nodes) != 3 { t.Fatalf("expected 3 nodes, got %d", len(nodes)) } names := make(map[string]bool, len(nodes)) for _, n := range nodes { names[n.Name] = true } for _, expected := range []string{"node01", "node02", "node03"} { if !names[expected] { t.Errorf("missing expected node %q", expected) } } } // TestIntegration_Cluster_NodeByName verifies GET /api/v1/nodes/:name returns a single node. func TestIntegration_Cluster_NodeByName(t *testing.T) { env := testenv.NewTestEnv(t) resp := env.DoRequest(http.MethodGet, "/api/v1/nodes/node01", nil) status, success, data, err := clusterDecodeAll(env, resp) if err != nil { t.Fatalf("decode response: %v", err) } if status != http.StatusOK { t.Fatalf("expected status 200, got %d", status) } if !success { t.Fatal("expected success=true") } var node clusterNodeData if err := json.Unmarshal(data, &node); err != nil { t.Fatalf("unmarshal node: %v", err) } if node.Name != "node01" { t.Fatalf("expected name=node01, got %q", node.Name) } } // TestIntegration_Cluster_Partitions verifies GET /api/v1/partitions returns the 2 pre-loaded partitions. func TestIntegration_Cluster_Partitions(t *testing.T) { env := testenv.NewTestEnv(t) resp := env.DoRequest(http.MethodGet, "/api/v1/partitions", nil) status, success, data, err := clusterDecodeAll(env, resp) if err != nil { t.Fatalf("decode response: %v", err) } if status != http.StatusOK { t.Fatalf("expected status 200, got %d", status) } if !success { t.Fatal("expected success=true") } var partitions []clusterPartitionData if err := json.Unmarshal(data, &partitions); err != nil { t.Fatalf("unmarshal partitions: %v", err) } if len(partitions) != 2 { t.Fatalf("expected 2 partitions, got %d", len(partitions)) } names := make(map[string]bool, len(partitions)) for _, p := range partitions { names[p.Name] = true } if !names["normal"] { t.Error("missing expected partition \"normal\"") } if !names["gpu"] { t.Error("missing expected partition \"gpu\"") } } // TestIntegration_Cluster_PartitionByName verifies GET /api/v1/partitions/:name returns a single partition. func TestIntegration_Cluster_PartitionByName(t *testing.T) { env := testenv.NewTestEnv(t) resp := env.DoRequest(http.MethodGet, "/api/v1/partitions/normal", nil) status, success, data, err := clusterDecodeAll(env, resp) if err != nil { t.Fatalf("decode response: %v", err) } if status != http.StatusOK { t.Fatalf("expected status 200, got %d", status) } if !success { t.Fatal("expected success=true") } var part clusterPartitionData if err := json.Unmarshal(data, &part); err != nil { t.Fatalf("unmarshal partition: %v", err) } if part.Name != "normal" { t.Fatalf("expected name=normal, got %q", part.Name) } } // TestIntegration_Cluster_Diag verifies GET /api/v1/diag returns diagnostics data. func TestIntegration_Cluster_Diag(t *testing.T) { env := testenv.NewTestEnv(t) resp := env.DoRequest(http.MethodGet, "/api/v1/diag", nil) status, success, data, err := clusterDecodeAll(env, resp) if err != nil { t.Fatalf("decode response: %v", err) } if status != http.StatusOK { t.Fatalf("expected status 200, got %d", status) } if !success { t.Fatal("expected success=true") } // Verify the response contains a "statistics" field (non-empty JSON object). var raw map[string]json.RawMessage if err := json.Unmarshal(data, &raw); err != nil { t.Fatalf("unmarshal diag top-level: %v", err) } if _, ok := raw["statistics"]; !ok { t.Fatal("diag response missing \"statistics\" field") } }