mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-28 03:20:11 +00:00
ADA: Add normalizeCommandStatus helper with unit tests
Extract command status normalization logic from HandleCommandAck into a dedicated helper function. This improves testability and makes the status alias handling explicit and documented. The function accepts client-provided status strings and maps them to internal status constants: - acknowledged: "", "ack", "acknowledged" - completed: "success", "completed", "complete" - failed: "fail", "failed", "error" Adds 25 table-driven test cases covering all aliases, case insensitivity, whitespace handling, and invalid inputs.
This commit is contained in:
parent
28eaad8bac
commit
cd9a2651a2
2 changed files with 89 additions and 9 deletions
|
|
@ -2,6 +2,7 @@ package api
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -25,6 +26,30 @@ type dockerCommandAckRequest struct {
|
|||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// errInvalidCommandStatus is returned when an unrecognized command status is provided.
|
||||
var errInvalidCommandStatus = errors.New("invalid command status")
|
||||
|
||||
// normalizeCommandStatus converts a client-provided status string into a canonical
|
||||
// internal status constant. It accepts multiple aliases for each status:
|
||||
// - acknowledged: "", "ack", "acknowledged"
|
||||
// - completed: "success", "completed", "complete"
|
||||
// - failed: "fail", "failed", "error"
|
||||
//
|
||||
// Returns errInvalidCommandStatus for unrecognized values.
|
||||
func normalizeCommandStatus(status string) (string, error) {
|
||||
status = strings.ToLower(strings.TrimSpace(status))
|
||||
switch status {
|
||||
case "", "ack", "acknowledged":
|
||||
return monitoring.DockerCommandStatusAcknowledged, nil
|
||||
case "success", "completed", "complete":
|
||||
return monitoring.DockerCommandStatusCompleted, nil
|
||||
case "fail", "failed", "error":
|
||||
return monitoring.DockerCommandStatusFailed, nil
|
||||
default:
|
||||
return "", errInvalidCommandStatus
|
||||
}
|
||||
}
|
||||
|
||||
// NewDockerAgentHandlers constructs a new Docker agent handler group.
|
||||
func NewDockerAgentHandlers(m *monitoring.Monitor, hub *websocket.Hub) *DockerAgentHandlers {
|
||||
return &DockerAgentHandlers{monitor: m, wsHub: hub}
|
||||
|
|
@ -154,15 +179,8 @@ func (h *DockerAgentHandlers) HandleCommandAck(w http.ResponseWriter, r *http.Re
|
|||
return
|
||||
}
|
||||
|
||||
status := strings.ToLower(strings.TrimSpace(req.Status))
|
||||
switch status {
|
||||
case "", "ack", "acknowledged":
|
||||
status = monitoring.DockerCommandStatusAcknowledged
|
||||
case "success", "completed", "complete":
|
||||
status = monitoring.DockerCommandStatusCompleted
|
||||
case "fail", "failed", "error":
|
||||
status = monitoring.DockerCommandStatusFailed
|
||||
default:
|
||||
status, err := normalizeCommandStatus(req.Status)
|
||||
if err != nil {
|
||||
writeErrorResponse(w, http.StatusBadRequest, "invalid_status", "Invalid command status", nil)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
62
internal/api/docker_agents_test.go
Normal file
62
internal/api/docker_agents_test.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rcourtman/pulse-go-rewrite/internal/monitoring"
|
||||
)
|
||||
|
||||
func TestNormalizeCommandStatus(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
wantError bool
|
||||
}{
|
||||
// Acknowledged status variants
|
||||
{name: "empty string maps to acknowledged", input: "", want: monitoring.DockerCommandStatusAcknowledged},
|
||||
{name: "ack maps to acknowledged", input: "ack", want: monitoring.DockerCommandStatusAcknowledged},
|
||||
{name: "acknowledged maps to acknowledged", input: "acknowledged", want: monitoring.DockerCommandStatusAcknowledged},
|
||||
{name: "ACK uppercase maps to acknowledged", input: "ACK", want: monitoring.DockerCommandStatusAcknowledged},
|
||||
{name: "Acknowledged mixed case maps to acknowledged", input: "Acknowledged", want: monitoring.DockerCommandStatusAcknowledged},
|
||||
|
||||
// Completed status variants
|
||||
{name: "success maps to completed", input: "success", want: monitoring.DockerCommandStatusCompleted},
|
||||
{name: "completed maps to completed", input: "completed", want: monitoring.DockerCommandStatusCompleted},
|
||||
{name: "complete maps to completed", input: "complete", want: monitoring.DockerCommandStatusCompleted},
|
||||
{name: "SUCCESS uppercase maps to completed", input: "SUCCESS", want: monitoring.DockerCommandStatusCompleted},
|
||||
{name: "Completed mixed case maps to completed", input: "Completed", want: monitoring.DockerCommandStatusCompleted},
|
||||
|
||||
// Failed status variants
|
||||
{name: "fail maps to failed", input: "fail", want: monitoring.DockerCommandStatusFailed},
|
||||
{name: "failed maps to failed", input: "failed", want: monitoring.DockerCommandStatusFailed},
|
||||
{name: "error maps to failed", input: "error", want: monitoring.DockerCommandStatusFailed},
|
||||
{name: "FAILED uppercase maps to failed", input: "FAILED", want: monitoring.DockerCommandStatusFailed},
|
||||
{name: "Error mixed case maps to failed", input: "Error", want: monitoring.DockerCommandStatusFailed},
|
||||
|
||||
// Whitespace handling
|
||||
{name: "whitespace around ack is trimmed", input: " ack ", want: monitoring.DockerCommandStatusAcknowledged},
|
||||
{name: "tab and newline around success is trimmed", input: "\tsuccess\n", want: monitoring.DockerCommandStatusCompleted},
|
||||
{name: "spaces only maps to acknowledged", input: " ", want: monitoring.DockerCommandStatusAcknowledged},
|
||||
|
||||
// Invalid inputs
|
||||
{name: "unknown status returns error", input: "unknown", wantError: true},
|
||||
{name: "pending returns error", input: "pending", wantError: true},
|
||||
{name: "queued returns error", input: "queued", wantError: true},
|
||||
{name: "random string returns error", input: "foobar", wantError: true},
|
||||
{name: "partial match returns error", input: "acked", wantError: true},
|
||||
{name: "partial match fail returns error", input: "failure", wantError: true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := normalizeCommandStatus(tt.input)
|
||||
if (err != nil) != tt.wantError {
|
||||
t.Fatalf("normalizeCommandStatus(%q) error = %v, wantError %v", tt.input, err, tt.wantError)
|
||||
}
|
||||
if !tt.wantError && got != tt.want {
|
||||
t.Fatalf("normalizeCommandStatus(%q) = %q, want %q", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue