Files
browser/plugins/examples/scum-server-plugin/companion/orchestration_test.go
T

214 lines
11 KiB
Go

package companion
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"time"
)
func TestRunOneShotSmokeProcessesOnlySafeDiagnosticsAndUploadsIsolatedHealth(t *testing.T) {
stamp := time.Date(2026, 7, 20, 9, 10, 11, 123456789, time.UTC)
config := loadTestConfig(t)
sessionExpiry := stamp.Add(15 * time.Minute)
step := 0
transport := roundTripFunc(func(request *http.Request) (*http.Response, error) {
switch step {
case 0:
assertPlatformRequest(t, request, registerPath)
step++
return jsonHTTPResponse(http.StatusOK, registerResponse{Accepted: true, InstallationID: config.Component.InstallationID, SessionToken: "component-session-smoke", ExpiresAt: sessionExpiry, HeartbeatEverySeconds: 30, ServerTime: stamp}), nil
case 1:
assertPlatformRequest(t, request, heartbeatPath)
var body heartbeatRequest
decodeRequest(t, request, &body)
if body.SessionToken != "component-session-smoke" || body.HealthReason != "one-shot smoke ready" {
t.Fatalf("unexpected smoke heartbeat: %+v", body)
}
step++
return jsonHTTPResponse(http.StatusOK, heartbeatResponse{Accepted: true, InstallationID: config.Component.InstallationID, Status: "online", Health: "healthy", NextHeartbeatSeconds: 30, SessionExpiresAt: sessionExpiry, ServerTime: stamp}), nil
case 2:
assertPlatformRequest(t, request, claimPath)
var body claimRequest
decodeRequest(t, request, &body)
if body.SessionToken != "component-session-smoke" || body.Limit != 1 {
t.Fatalf("unexpected smoke claim: %+v", body)
}
step++
return jsonHTTPResponse(http.StatusOK, claimResponse{Items: []ClaimedCommand{{ID: "diagnostics-1", ProfileKey: ProfileKey, CommandType: companionDiagnosticsCommandType, Payload: map[string]any{"includeWindowState": true, "maxEntries": 3}, FencingToken: 17, LeaseExpiresAt: stamp.Add(time.Minute), ExpiresAt: stamp.Add(5 * time.Minute)}}, Count: 1}), nil
case 3:
assertPlatformRequest(t, request, "/api/v1/game-client-bridge/companion/commands/diagnostics-1/ack")
var body ackRequest
decodeRequest(t, request, &body)
if body.SessionToken != "component-session-smoke" || body.FencingToken != 17 {
t.Fatalf("unexpected smoke ack: %+v", body)
}
step++
return jsonHTTPResponse(http.StatusOK, CommandAck{CommandID: "diagnostics-1", State: "claimed", FencingToken: 17, AcknowledgedAt: stamp}), nil
case 4:
assertPlatformRequest(t, request, "/api/v1/game-client-bridge/companion/commands/diagnostics-1/result")
var body resultRequest
decodeRequest(t, request, &body)
if body.SessionToken != "component-session-smoke" || body.FencingToken != 17 || body.Status != "succeeded" || body.Summary != "companion diagnostics available" {
t.Fatalf("unexpected smoke result: %+v", body)
}
if body.Payload["status"] != "online" || body.Payload["version"] != config.Component.Version || body.Payload["lastHeartbeatAt"] != stamp.Format(time.RFC3339Nano) {
t.Fatalf("unexpected bounded diagnostics payload: %+v", body.Payload)
}
serialized, _ := json.Marshal(body)
if strings.Contains(string(serialized), testProof) {
t.Fatalf("result exposed proof: %s", serialized)
}
step++
return jsonHTTPResponse(http.StatusOK, map[string]any{"commandId": "diagnostics-1", "state": "succeeded", "result": map[string]any{"status": "succeeded", "summary": "companion diagnostics available", "completedAt": stamp}, "updatedAt": stamp, "completedAt": stamp}), nil
case 5:
assertPlatformRequest(t, request, snapshotPath)
var body snapshotRequest
decodeRequest(t, request, &body)
if body.SessionToken != "component-session-smoke" || body.Type != companionHealthSnapshotType || body.SchemaVersion != companionHealthSchemaVersion || body.StreamKey != "smoke-fixture-stream-nonce-0001" || body.Sequence != 1 {
t.Fatalf("unexpected isolated smoke snapshot identity: %+v", body)
}
if !body.ObservedAt.Equal(stamp) || body.KeepForSeconds != 604800 || body.MaxRecords != 1000 || body.Payload["status"] != "online" || body.Payload["observedAt"] != stamp.Format(time.RFC3339Nano) {
t.Fatalf("unexpected typed health snapshot: %+v", body)
}
step++
return jsonHTTPResponse(http.StatusAccepted, AcceptedSnapshot{SnapshotID: "health-snapshot-1", ProfileKey: ProfileKey, Type: body.Type, SchemaVersion: body.SchemaVersion, StreamKey: body.StreamKey, Sequence: body.Sequence, AcceptedAt: stamp, ExpiresAt: stamp.Add(7 * 24 * time.Hour)}), nil
default:
return nil, fmt.Errorf("unexpected smoke transport: %s", request.URL.Path)
}
})
client := newTestClient(t, config, transport, stamp)
result, err := RunOneShotSmoke(context.Background(), client, SmokeOptions{IsolatedNonProduction: true, StreamSuffix: func() (string, error) { return "fixture-stream-nonce-0001", nil }})
if err != nil {
t.Fatalf("run one-shot smoke: %v", err)
}
if result.ClaimedCount != 1 || result.CompletedCount != 1 || result.UnsupportedCount != 0 || result.SnapshotID != "health-snapshot-1" {
t.Fatalf("unexpected safe smoke result: %+v", result)
}
if len(result.CompletedCommandIDs) != 1 || result.CompletedCommandIDs[0] != "diagnostics-1" || len(result.UnsupportedCommandIDs) != 0 {
t.Fatalf("unexpected smoke IDs: %+v", result)
}
assertSafeSmokeOutput(t, result)
if step != 6 {
t.Fatalf("expected diagnostics ack/result plus snapshot, got %d requests", step)
}
}
func TestRunOneShotSmokeLeavesUnsupportedCommandUnackedAndUnexecuted(t *testing.T) {
stamp := time.Date(2026, 7, 20, 10, 0, 0, 0, time.UTC)
config := loadTestConfig(t)
sessionExpiry := stamp.Add(15 * time.Minute)
step := 0
transport := roundTripFunc(func(request *http.Request) (*http.Response, error) {
switch step {
case 0:
step++
return jsonHTTPResponse(http.StatusOK, registerResponse{Accepted: true, InstallationID: config.Component.InstallationID, SessionToken: "component-session-unsupported", ExpiresAt: sessionExpiry, HeartbeatEverySeconds: 30, ServerTime: stamp}), nil
case 1:
step++
return jsonHTTPResponse(http.StatusOK, heartbeatResponse{Accepted: true, InstallationID: config.Component.InstallationID, Status: "online", Health: "healthy", NextHeartbeatSeconds: 30, SessionExpiresAt: sessionExpiry, ServerTime: stamp}), nil
case 2:
step++
return jsonHTTPResponse(http.StatusOK, claimResponse{Items: []ClaimedCommand{{ID: "unsupported-1", ProfileKey: ProfileKey, CommandType: "diagnostic.unsupported", Payload: map[string]any{"message": "must not execute"}, FencingToken: 18, LeaseExpiresAt: stamp.Add(time.Minute), ExpiresAt: stamp.Add(5 * time.Minute)}}, Count: 1}), nil
default:
return nil, fmt.Errorf("unsupported command triggered transport: %s", request.URL.Path)
}
})
client := newTestClient(t, config, transport, stamp)
result, err := RunOneShotSmoke(context.Background(), client, SmokeOptions{IsolatedNonProduction: true, StreamSuffix: func() (string, error) { return "fixture-stream-nonce-0002", nil }})
if err == nil || !strings.Contains(err.Error(), "unsupported") {
t.Fatalf("expected unsupported smoke to stop, result=%+v err=%v", result, err)
}
if result.ClaimedCount != 1 || result.CompletedCount != 0 || result.UnsupportedCount != 1 || len(result.CompletedCommandIDs) != 0 || len(result.UnsupportedCommandIDs) != 1 || result.UnsupportedCommandIDs[0] != "unsupported-1" {
t.Fatalf("unsupported command did not fail safely: %+v", result)
}
assertSafeSmokeOutput(t, result)
if step != 3 {
t.Fatalf("expected no unsupported ack/result requests, got %d steps", step)
}
}
func TestRunOneShotSmokeRejectsNonSingletonClaimBeforeExecution(t *testing.T) {
stamp := time.Date(2026, 7, 20, 10, 30, 0, 0, time.UTC)
for _, test := range []struct {
name string
items []ClaimedCommand
}{
{name: "zero"},
{name: "multiple", items: []ClaimedCommand{{ID: "diagnostics-1"}, {ID: "diagnostics-2"}}},
} {
t.Run(test.name, func(t *testing.T) {
config := loadTestConfig(t)
step := 0
transport := roundTripFunc(func(request *http.Request) (*http.Response, error) {
step++
switch step {
case 1:
return jsonHTTPResponse(http.StatusOK, registerResponse{Accepted: true, InstallationID: config.Component.InstallationID, SessionToken: "component-session-singleton", ExpiresAt: stamp.Add(15 * time.Minute), HeartbeatEverySeconds: 30, ServerTime: stamp}), nil
case 2:
return jsonHTTPResponse(http.StatusOK, heartbeatResponse{Accepted: true, InstallationID: config.Component.InstallationID, Status: "online", Health: "healthy", NextHeartbeatSeconds: 30, SessionExpiresAt: stamp.Add(15 * time.Minute), ServerTime: stamp}), nil
case 3:
return jsonHTTPResponse(http.StatusOK, claimResponse{Items: test.items, Count: len(test.items)}), nil
default:
return nil, fmt.Errorf("non-singleton claim triggered execution: %s", request.URL.Path)
}
})
client := newTestClient(t, config, transport, stamp)
result, err := RunOneShotSmoke(context.Background(), client, SmokeOptions{IsolatedNonProduction: true, StreamSuffix: func() (string, error) { return "fixture-singleton-nonce", nil }})
if err == nil || !strings.Contains(err.Error(), "exactly one") || result.ClaimedCount != len(test.items) || step != 3 {
t.Fatalf("non-singleton claim was not rejected: result=%+v step=%d err=%v", result, step, err)
}
})
}
}
func TestValidateSmokeDiagnosticsCommandRejectsUnsafeClaims(t *testing.T) {
stamp := time.Date(2026, 7, 20, 11, 0, 0, 0, time.UTC)
valid := ClaimedCommand{ID: "diagnostics-1", ProfileKey: ProfileKey, CommandType: companionDiagnosticsCommandType, Payload: map[string]any{"includeWindowState": false, "maxEntries": float64(5)}, FencingToken: 7, LeaseExpiresAt: stamp.Add(time.Minute), ExpiresAt: stamp.Add(2 * time.Minute)}
tests := []struct {
name string
mutate func(*ClaimedCommand)
}{
{name: "profile", mutate: func(command *ClaimedCommand) { command.ProfileKey = "other" }},
{name: "fence", mutate: func(command *ClaimedCommand) { command.FencingToken = 0 }},
{name: "lease", mutate: func(command *ClaimedCommand) { command.LeaseExpiresAt = stamp }},
{name: "expiry", mutate: func(command *ClaimedCommand) { command.ExpiresAt = stamp.Add(-time.Second) }},
{name: "nil payload", mutate: func(command *ClaimedCommand) { command.Payload = nil }},
{name: "unknown payload", mutate: func(command *ClaimedCommand) { command.Payload["message"] = "not allowed" }},
{name: "payload type", mutate: func(command *ClaimedCommand) { command.Payload["maxEntries"] = 2.5 }},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
candidate := valid
candidate.Payload = map[string]any{"includeWindowState": false, "maxEntries": float64(5)}
test.mutate(&candidate)
if err := validateSmokeDiagnosticsCommand(candidate, stamp); err == nil {
t.Fatalf("expected unsafe diagnostics claim to be rejected: %+v", candidate)
}
})
}
}
func TestRunOneShotSmokeRequiresIsolatedNonProductionQueue(t *testing.T) {
result, err := RunOneShotSmoke(context.Background(), &Client{}, SmokeOptions{})
if err == nil || !strings.Contains(err.Error(), "isolated non-production") {
t.Fatalf("expected isolation gate, result=%+v err=%v", result, err)
}
}
func assertSafeSmokeOutput(t *testing.T, result SmokeResult) {
t.Helper()
serialized, err := json.Marshal(result)
if err != nil {
t.Fatalf("marshal smoke result: %v", err)
}
for _, forbidden := range []string{testProof, "component-session", "includeWindowState", "must not execute", "payload"} {
if strings.Contains(string(serialized), forbidden) {
t.Fatalf("smoke output exposed %q: %s", forbidden, serialized)
}
}
}