package edgestacks import ( "bytes" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" portainer "github.com/portainer/portainer/api" ) // Update Status func TestUpdateStatusAndInspect(t *testing.T) { handler, rawAPIKey, teardown := setupHandler(t) defer teardown() endpoint := createEndpoint(t, handler.DataStore) edgeStack := createEdgeStack(t, handler.DataStore, endpoint.ID) // Update edge stack status newStatus := portainer.EdgeStackStatusError payload := updateStatusPayload{ Error: "test-error", Status: &newStatus, EndpointID: endpoint.ID, } jsonPayload, err := json.Marshal(payload) if err != nil { t.Fatal("request error:", err) } r := bytes.NewBuffer(jsonPayload) req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("/edge_stacks/%d/status", edgeStack.ID), r) if err != nil { t.Fatal("request error:", err) } req.Header.Set(portainer.PortainerAgentEdgeIDHeader, endpoint.EdgeID) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected a %d response, found: %d", http.StatusOK, rec.Code) } // Get updated edge stack req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("/edge_stacks/%d", edgeStack.ID), nil) if err != nil { t.Fatal("request error:", err) } req.Header.Add("x-api-key", rawAPIKey) rec = httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected a %d response, found: %d", http.StatusOK, rec.Code) } data := portainer.EdgeStack{} err = json.NewDecoder(rec.Body).Decode(&data) if err != nil { t.Fatal("error decoding response:", err) } if !data.Status[endpoint.ID].Details.Error { t.Fatalf("expected EdgeStackStatusType %d, found %t", payload.Status, data.Status[endpoint.ID].Details.Error) } if data.Status[endpoint.ID].Error != payload.Error { t.Fatalf("expected EdgeStackStatusError %s, found %s", payload.Error, data.Status[endpoint.ID].Error) } if data.Status[endpoint.ID].EndpointID != payload.EndpointID { t.Fatalf("expected EndpointID %d, found %d", payload.EndpointID, data.Status[endpoint.ID].EndpointID) } } func TestUpdateStatusWithInvalidPayload(t *testing.T) { handler, _, teardown := setupHandler(t) defer teardown() endpoint := createEndpoint(t, handler.DataStore) edgeStack := createEdgeStack(t, handler.DataStore, endpoint.ID) // Update edge stack status statusError := portainer.EdgeStackStatusError statusOk := portainer.EdgeStackStatusOk cases := []struct { Name string Payload updateStatusPayload ExpectedErrorMessage string ExpectedStatusCode int }{ { "Update with nil Status", updateStatusPayload{ Error: "test-error", Status: nil, EndpointID: endpoint.ID, }, "Invalid status", 400, }, { "Update with error status and empty error message", updateStatusPayload{ Error: "", Status: &statusError, EndpointID: endpoint.ID, }, "Error message is mandatory when status is error", 400, }, { "Update with missing EndpointID", updateStatusPayload{ Error: "", Status: &statusOk, EndpointID: 0, }, "Invalid EnvironmentID", 400, }, } for _, tc := range cases { t.Run(tc.Name, func(t *testing.T) { jsonPayload, err := json.Marshal(tc.Payload) if err != nil { t.Fatal("request error:", err) } r := bytes.NewBuffer(jsonPayload) req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("/edge_stacks/%d/status", edgeStack.ID), r) if err != nil { t.Fatal("request error:", err) } req.Header.Set(portainer.PortainerAgentEdgeIDHeader, endpoint.EdgeID) rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != tc.ExpectedStatusCode { t.Fatalf("expected a %d response, found: %d", tc.ExpectedStatusCode, rec.Code) } }) } }