66 lines
4.1 KiB
Go
66 lines
4.1 KiB
Go
package httpapi
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"net/http"
|
||
|
|
"net/http/httptest"
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"data-terminal-cloud/internal/device"
|
||
|
|
"data-terminal-cloud/internal/deviceauth"
|
||
|
|
)
|
||
|
|
|
||
|
|
type fakeTelemetrySubmitter struct {
|
||
|
|
response device.TelemetryBatchResponse
|
||
|
|
replayed bool
|
||
|
|
err error
|
||
|
|
calls int
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *fakeTelemetrySubmitter) Submit(context.Context, deviceauth.Identity, string, []byte, device.TelemetryBatchInput) (device.TelemetryBatchResponse, bool, error) {
|
||
|
|
s.calls++
|
||
|
|
return s.response, s.replayed, s.err
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestSubmitDeviceTelemetryAcceptsTypedBatch(t *testing.T) {
|
||
|
|
service := &fakeTelemetrySubmitter{response: device.TelemetryBatchResponse{
|
||
|
|
AcceptedCount: 2, DesiredConfigRevision: 2, Actions: []device.TelemetryAction{{Type: "refresh_config"}},
|
||
|
|
}, replayed: true}
|
||
|
|
body := `{"events":[{"event_key":"status-101","sequence_no":101,"occurred_at":"2026-08-23T12:00:00Z","event_type":"status","status":{"firmware_version":"1.0.1","reported_config_revision":1,"network":{"type":"wifi","rssi":-50},"rtc":{"joined":false,"uplink":false,"downlink":false},"recording_queue":{"pending_segments":2,"failed_segments":1,"last_failure_code":"MEDIA_UPLOAD_TIMEOUT","last_failure_at":"2026-08-23T11:59:58Z"}}},{"event_key":"error-102","sequence_no":102,"occurred_at":"2026-08-23T12:00:01Z","event_type":"error","error":{"code":"RTC_RECONNECTING","severity":"warning"}}]}`
|
||
|
|
request := httptest.NewRequest(http.MethodPost, "/device/v2/telemetry:batch", strings.NewReader(body))
|
||
|
|
request.Header.Set("Idempotency-Key", "telemetry-0123456789abcdef")
|
||
|
|
request = request.WithContext(deviceauth.WithIdentity(request.Context(), deviceauth.Identity{PublicID: "device-1"}))
|
||
|
|
recorder := httptest.NewRecorder()
|
||
|
|
SubmitDeviceTelemetryHandler(service).ServeHTTP(recorder, request)
|
||
|
|
if recorder.Code != http.StatusOK || service.calls != 1 || recorder.Header().Get("Idempotency-Replayed") != "true" || !containsText(recorder.Body.String(), "refresh_config") {
|
||
|
|
t.Fatalf("status=%d calls=%d replay=%q body=%s", recorder.Code, service.calls, recorder.Header().Get("Idempotency-Replayed"), recorder.Body.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestSubmitDeviceTelemetryRejectsMixedPayloadAndSensitiveCommandResult(t *testing.T) {
|
||
|
|
service := &fakeTelemetrySubmitter{}
|
||
|
|
body := `{"events":[{"event_key":"command-1","sequence_no":1,"occurred_at":"2026-08-23T12:00:00Z","event_type":"command_result","error":{"code":"X","severity":"error"},"command_result":{"command_id":"10000000-0000-0000-0000-000000000001","status":"SUCCEEDED","result_summary":{"api_token":"must-not-pass"}}}]}`
|
||
|
|
request := httptest.NewRequest(http.MethodPost, "/device/v2/telemetry:batch", strings.NewReader(body))
|
||
|
|
request.Header.Set("Idempotency-Key", "telemetry-0123456789abcdef")
|
||
|
|
request = request.WithContext(deviceauth.WithIdentity(request.Context(), deviceauth.Identity{PublicID: "device-1"}))
|
||
|
|
recorder := httptest.NewRecorder()
|
||
|
|
SubmitDeviceTelemetryHandler(service).ServeHTTP(recorder, request)
|
||
|
|
if recorder.Code != http.StatusBadRequest || service.calls != 0 {
|
||
|
|
t.Fatalf("status=%d calls=%d body=%s", recorder.Code, service.calls, recorder.Body.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestSubmitDeviceTelemetryReturnsStructuredEventConflict(t *testing.T) {
|
||
|
|
service := &fakeTelemetrySubmitter{err: &device.TelemetryConflictError{Conflicts: []device.TelemetryConflict{{EventKey: "error-1", SequenceNo: 1, Reason: "EVENT_KEY_OR_SEQUENCE_ALREADY_USED"}}}}
|
||
|
|
body := `{"events":[{"event_key":"error-1","sequence_no":1,"occurred_at":"2026-08-23T12:00:00Z","event_type":"error","error":{"code":"RTC_FAILED","severity":"error"}}]}`
|
||
|
|
request := httptest.NewRequest(http.MethodPost, "/device/v2/telemetry:batch", strings.NewReader(body))
|
||
|
|
request.Header.Set("Idempotency-Key", "telemetry-0123456789abcdef")
|
||
|
|
request = request.WithContext(deviceauth.WithIdentity(request.Context(), deviceauth.Identity{PublicID: "device-1"}))
|
||
|
|
recorder := httptest.NewRecorder()
|
||
|
|
SubmitDeviceTelemetryHandler(service).ServeHTTP(recorder, request)
|
||
|
|
if recorder.Code != http.StatusConflict || !containsText(recorder.Body.String(), "TELEMETRY_EVENT_CONFLICT") || !containsText(recorder.Body.String(), "EVENT_KEY_OR_SEQUENCE_ALREADY_USED") {
|
||
|
|
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||
|
|
}
|
||
|
|
}
|