feat(garmin): log every wrapper subprocess call as structured JSON
This commit is contained in:
@@ -2,13 +2,17 @@ package garmin
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"geniusrun/backend/internal/applog"
|
||||
)
|
||||
|
||||
// wireResponsePayload is what a fake wrapper handler returns for one
|
||||
@@ -91,7 +95,7 @@ func TestSubprocessClient_RoundTrip_DetectsIDMismatch(t *testing.T) {
|
||||
scanner.Buffer(make([]byte, 0, 64*1024), maxWrapperLineBytes)
|
||||
c := &subprocessClient{started: true, enc: json.NewEncoder(reqW), scanner: scanner}
|
||||
|
||||
_, err := c.roundTrip("authenticate", nil)
|
||||
_, err := c.roundTrip(context.Background(), "authenticate", nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "id mismatch") {
|
||||
t.Fatalf("roundTrip error = %v, want an id mismatch error", err)
|
||||
}
|
||||
@@ -113,7 +117,7 @@ func TestSubprocessClient_RoundTrip_SubprocessClosedIsError(t *testing.T) {
|
||||
scanner.Buffer(make([]byte, 0, 64*1024), maxWrapperLineBytes)
|
||||
c := &subprocessClient{started: true, enc: json.NewEncoder(reqW), scanner: scanner}
|
||||
|
||||
_, err := c.roundTrip("authenticate", nil)
|
||||
_, err := c.roundTrip(context.Background(), "authenticate", nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "closed") {
|
||||
t.Fatalf("roundTrip error = %v, want a subprocess-closed error", err)
|
||||
}
|
||||
@@ -124,7 +128,7 @@ func TestSubprocessClient_RoundTrip_WrapperErrorPropagates(t *testing.T) {
|
||||
return fakeError("boom")
|
||||
})
|
||||
|
||||
_, err := c.roundTrip("authenticate", nil)
|
||||
_, err := c.roundTrip(context.Background(), "authenticate", nil)
|
||||
if err == nil || !strings.Contains(err.Error(), "boom") {
|
||||
t.Fatalf("roundTrip error = %v, want it to mention %q", err, "boom")
|
||||
}
|
||||
@@ -394,3 +398,60 @@ func TestSubprocessClient_GetWorkoutByID_ParsesSegments(t *testing.T) {
|
||||
t.Fatalf("workout = %+v", workout)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubprocessClient_RoundTrip_LogsCallWithResultPreview(t *testing.T) {
|
||||
c := newFakeWrapperClient(t, func(cmd string, params json.RawMessage) wireResponsePayload {
|
||||
return fakeResult(authResultWire{Status: "mfa_required", Message: "MFA required."})
|
||||
})
|
||||
|
||||
var buf bytes.Buffer
|
||||
logger := slog.New(slog.NewJSONHandler(&buf, nil))
|
||||
ctx := applog.WithLogger(context.Background(), logger)
|
||||
|
||||
if _, err := c.Authenticate(ctx); err != nil {
|
||||
t.Fatalf("Authenticate: %v", err)
|
||||
}
|
||||
|
||||
var entry map[string]any
|
||||
if err := json.Unmarshal(buf.Bytes(), &entry); err != nil {
|
||||
t.Fatalf("log output is not valid JSON: %v (%q)", err, buf.String())
|
||||
}
|
||||
if entry["msg"] != "garmin wrapper call" {
|
||||
t.Errorf("msg = %v, want \"garmin wrapper call\"", entry["msg"])
|
||||
}
|
||||
if entry["cmd"] != "authenticate" {
|
||||
t.Errorf("cmd = %v, want authenticate", entry["cmd"])
|
||||
}
|
||||
preview, _ := entry["result_preview"].(string)
|
||||
if !strings.Contains(preview, "mfa_required") {
|
||||
t.Errorf("result_preview = %q, want it to contain mfa_required", preview)
|
||||
}
|
||||
if _, hasError := entry["error"]; hasError {
|
||||
t.Errorf("expected no error field on a successful call, got %v", entry["error"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubprocessClient_RoundTrip_LogsErrorAtWarnLevel(t *testing.T) {
|
||||
c := newFakeWrapperClient(t, func(cmd string, params json.RawMessage) wireResponsePayload {
|
||||
return fakeError("boom")
|
||||
})
|
||||
|
||||
var buf bytes.Buffer
|
||||
logger := slog.New(slog.NewJSONHandler(&buf, nil))
|
||||
ctx := applog.WithLogger(context.Background(), logger)
|
||||
|
||||
if _, err := c.Authenticate(ctx); err == nil {
|
||||
t.Fatal("expected Authenticate to return an error")
|
||||
}
|
||||
|
||||
var entry map[string]any
|
||||
if err := json.Unmarshal(buf.Bytes(), &entry); err != nil {
|
||||
t.Fatalf("log output is not valid JSON: %v (%q)", err, buf.String())
|
||||
}
|
||||
if entry["level"] != "WARN" {
|
||||
t.Errorf("level = %v, want WARN for a failed call", entry["level"])
|
||||
}
|
||||
if errMsg, _ := entry["error"].(string); !strings.Contains(errMsg, "boom") {
|
||||
t.Errorf("error field = %q, want it to mention \"boom\"", errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user