chore: establish local platform baseline
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"data-terminal-cloud/internal/device"
|
||||
"data-terminal-cloud/internal/deviceauth"
|
||||
)
|
||||
|
||||
type fakeDeviceCommandService struct {
|
||||
items []device.Command
|
||||
pullErr error
|
||||
ackErr error
|
||||
pulledID deviceauth.Identity
|
||||
pulledLimit int
|
||||
ackedID deviceauth.Identity
|
||||
ackedRef string
|
||||
ackedInput device.CommandAcknowledgement
|
||||
}
|
||||
|
||||
func (f *fakeDeviceCommandService) PullCommands(_ context.Context, id deviceauth.Identity, limit int) ([]device.Command, error) {
|
||||
f.pulledID, f.pulledLimit = id, limit
|
||||
return f.items, f.pullErr
|
||||
}
|
||||
|
||||
func (f *fakeDeviceCommandService) AcknowledgeCommand(_ context.Context, id deviceauth.Identity, ref string, input device.CommandAcknowledgement) (device.Command, error) {
|
||||
f.ackedID, f.ackedRef, f.ackedInput = id, ref, input
|
||||
if f.ackErr != nil {
|
||||
return device.Command{}, f.ackErr
|
||||
}
|
||||
return device.Command{ID: ref, Type: "reboot", Status: input.Status, Payload: json.RawMessage(`{}`), ExpiresAt: time.Now().UTC()}, nil
|
||||
}
|
||||
|
||||
func deviceCommandRequest(method, target, body string, authenticated bool) *http.Request {
|
||||
request := httptest.NewRequest(method, target, strings.NewReader(body))
|
||||
if body != "" {
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
if authenticated {
|
||||
request = request.WithContext(deviceauth.WithIdentity(request.Context(), deviceauth.Identity{ID: "internal-device", PublicID: "device-1", TenantID: "tenant-1"}))
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
func TestPullDeviceCommandsAuthenticationSuccessAndFailure(t *testing.T) {
|
||||
service := &fakeDeviceCommandService{items: []device.Command{{ID: "command-1", Type: "apply_config", Status: "PENDING", Payload: json.RawMessage(`{}`)}}}
|
||||
handler := PullDeviceCommandsHandler(service)
|
||||
recorder := httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, deviceCommandRequest(http.MethodGet, "/device/v2/commands?limit=7", "", false))
|
||||
if recorder.Code != http.StatusUnauthorized || !strings.Contains(recorder.Body.String(), "DEVICE_AUTHENTICATION_FAILED") {
|
||||
t.Fatalf("unauthenticated status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, deviceCommandRequest(http.MethodGet, "/device/v2/commands?limit=7", "", true))
|
||||
if recorder.Code != http.StatusOK || !strings.Contains(recorder.Body.String(), "command-1") || service.pulledLimit != 7 || service.pulledID.PublicID != "device-1" {
|
||||
t.Fatalf("success status=%d body=%s service=%+v", recorder.Code, recorder.Body.String(), service)
|
||||
}
|
||||
|
||||
service.pullErr = errors.New("database unavailable")
|
||||
recorder = httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, deviceCommandRequest(http.MethodGet, "/device/v2/commands", "", true))
|
||||
if recorder.Code != http.StatusServiceUnavailable || !strings.Contains(recorder.Body.String(), "DEVICE_COMMANDS_UNAVAILABLE") || !strings.Contains(recorder.Body.String(), `"retryable":true`) {
|
||||
t.Fatalf("failure status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcknowledgeDeviceCommandValidationSuccessAndConflict(t *testing.T) {
|
||||
service := &fakeDeviceCommandService{}
|
||||
handler := AcknowledgeDeviceCommandHandler(service)
|
||||
recorder := httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, deviceCommandRequest(http.MethodPost, "/device/v2/commands/command-1/ack", `{"status":"SUCCEEDED"}`, false))
|
||||
if recorder.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("unauthenticated status=%d", recorder.Code)
|
||||
}
|
||||
|
||||
request := deviceCommandRequest(http.MethodPost, "/device/v2/commands/command-1/ack", `{"status":"unknown"}`, true)
|
||||
request.SetPathValue("id", "command-1")
|
||||
recorder = httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest || !strings.Contains(recorder.Body.String(), "VALIDATION_FAILED") {
|
||||
t.Fatalf("validation status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
|
||||
request = deviceCommandRequest(http.MethodPost, "/device/v2/commands/command-1/ack", `{"status":" succeeded "}`, true)
|
||||
request.SetPathValue("id", "command-1")
|
||||
recorder = httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusOK || service.ackedRef != "command-1" || service.ackedInput.Status != "SUCCEEDED" || service.ackedInput.ResultSummary == nil {
|
||||
t.Fatalf("success status=%d body=%s input=%+v", recorder.Code, recorder.Body.String(), service.ackedInput)
|
||||
}
|
||||
|
||||
service.ackErr = errors.New("state conflict")
|
||||
request = deviceCommandRequest(http.MethodPost, "/device/v2/commands/command-1/ack", `{"status":"FAILED","result_summary":{"result_code":"SIM_FAIL"}}`, true)
|
||||
request.SetPathValue("id", "command-1")
|
||||
recorder = httptest.NewRecorder()
|
||||
handler.ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusConflict || !strings.Contains(recorder.Body.String(), "DEVICE_COMMAND_STATE_CONFLICT") || service.ackedInput.ResultSummary["result_code"] != "SIM_FAIL" {
|
||||
t.Fatalf("conflict status=%d body=%s input=%+v", recorder.Code, recorder.Body.String(), service.ackedInput)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user