feat(scum): add bounded vehicle spawn adapter

This commit is contained in:
npc0-hue
2026-07-29 16:04:26 +08:00
parent 7ae4dbf0b2
commit daa0f330a4
24 changed files with 314 additions and 23 deletions
@@ -2,6 +2,7 @@ package companion
import (
"context"
"errors"
"testing"
"time"
)
@@ -24,6 +25,20 @@ type notificationPortFixture struct {
accepted bool
}
// nonProductionVehicleSpawnPortFixture is an isolated test double. It has no
// network, socket, credential, or raw-command entry point; it can observe only
// the Companion's private typed request and return a bounded receipt.
type nonProductionVehicleSpawnPortFixture struct {
requests []ue4SSVehicleSpawn
receipt UE4SSVehicleSpawnReceipt
err error
}
func (fixture *nonProductionVehicleSpawnPortFixture) SpawnVehicle(_ context.Context, request ue4SSVehicleSpawn) (UE4SSVehicleSpawnReceipt, error) {
fixture.requests = append(fixture.requests, request)
return fixture.receipt, fixture.err
}
func (fixture *notificationPortFixture) SendPlayerNotification(_ context.Context, notification ue4SSPlayerNotification) (UE4SSNotificationReceipt, error) {
fixture.deliveries = append(fixture.deliveries, notification)
return UE4SSNotificationReceipt{Accepted: fixture.accepted}, nil
@@ -97,3 +112,64 @@ func TestNotificationFailureIsCachedWithoutInvokingRewardDelivery(t *testing.T)
t.Fatalf("duplicate notification attempted transport %d times", len(port.deliveries))
}
}
func TestVersionedVehicleSpawnUsesFixedTemplateAndPrivateAuditOnly(t *testing.T) {
port := &nonProductionVehicleSpawnPortFixture{receipt: UE4SSVehicleSpawnReceipt{Outcome: UE4SSVehicleSpawnAccepted}}
adapter := VersionedAdapter{BoundServerID: "server-1", ServerVersion: "0.9.700.90357", UE4SSBuild: UE4SSReferenceBuild, UE4SSReferenceRevision: UE4SSReferenceRevision, VehicleSpawn: port}
result, err := adapter.SpawnVehicle(context.Background(), map[string]any{"vehicleCode": "BPC_Laika_C"})
if err != nil || result["outcome"] != "succeeded" || len(port.requests) != 1 {
t.Fatalf("fixed vehicle spawn was not delivered: result=%+v err=%v requests=%+v", result, err, port.requests)
}
request := port.requests[0]
if request.ServerID != "server-1" || request.VehicleCode != "BPC_Laika_C" || request.protectedAuditCommand != "#spawnvehicle BPC_Laika_C" {
t.Fatalf("vehicle spawn did not use the fixed template: %+v", request)
}
if result["command"] != nil || result["rcon"] != nil || result["audit"] != nil || result["outcome"] == request.protectedAuditCommand {
t.Fatalf("vehicle spawn leaked protected transport details: %+v", result)
}
}
func TestVersionedVehicleSpawnFailsClosedAndClassifiesBoundedReceipts(t *testing.T) {
port := &nonProductionVehicleSpawnPortFixture{receipt: UE4SSVehicleSpawnReceipt{Outcome: UE4SSVehicleSpawnRejected}}
adapter := VersionedAdapter{BoundServerID: "server-1", ServerVersion: "0.9.700.90357", UE4SSBuild: UE4SSReferenceBuild, UE4SSReferenceRevision: UE4SSReferenceRevision, VehicleSpawn: port}
for name, testCase := range map[string]struct {
outcome string
receipt UE4SSVehicleSpawnReceipt
err error
}{
"failed": {outcome: "failed", receipt: UE4SSVehicleSpawnReceipt{Outcome: UE4SSVehicleSpawnRejected}},
"unknown": {outcome: "unknown", receipt: UE4SSVehicleSpawnReceipt{Outcome: UE4SSVehicleSpawnUnknown}},
"unknown-transport": {outcome: "unknown", receipt: UE4SSVehicleSpawnReceipt{}, err: errors.New("isolated transport timeout")},
} {
port.receipt, port.err = testCase.receipt, testCase.err
result, err := adapter.SpawnVehicle(context.Background(), map[string]any{"vehicleCode": "BPC_WolfsWagen_C"})
if err != nil || result["outcome"] != testCase.outcome {
t.Fatalf("receipt %s was not safely classified: result=%+v err=%v", name, result, err)
}
}
before := len(port.requests)
if _, err := adapter.SpawnVehicle(context.Background(), map[string]any{"vehicleCode": "#spawnvehicle BPC_Laika_C"}); err == nil || len(port.requests) != before {
t.Fatal("raw command text must not reach the vehicle transport")
}
adapter.UE4SSBuild = "3.0.2"
if _, err := adapter.SpawnVehicle(context.Background(), map[string]any{"vehicleCode": "BPC_Laika_C"}); err == nil || len(port.requests) != before {
t.Fatal("unpinned UE4SS build must not reach the vehicle transport")
}
}
func TestVehicleSpawnUnknownOutcomeIsCachedWithoutRetry(t *testing.T) {
stamp := time.Now().UTC()
port := &nonProductionVehicleSpawnPortFixture{receipt: UE4SSVehicleSpawnReceipt{Outcome: UE4SSVehicleSpawnUnknown}}
adapter := VersionedAdapter{BoundServerID: "server-1", ServerVersion: "0.9.700.90357", UE4SSBuild: UE4SSReferenceBuild, UE4SSReferenceRevision: UE4SSReferenceRevision, VehicleSpawn: port}
registry := NewHandlerRegistry(HandlerAvailability{BoundServerID: "server-1", ServerVersion: "0.9.700.90357", Approved: true, Capabilities: map[string]bool{"vehicle.spawn": true}}, adapter)
command := ClaimedCommand{ID: "vehicle-unknown-1", ProfileKey: ProfileKey, CommandType: "vehicle.spawn", Payload: map[string]any{"vehicleCode": "BPC_Laika_C"}, FencingToken: 1, LeaseExpiresAt: stamp.Add(time.Minute), ExpiresAt: stamp.Add(time.Minute)}
for range 2 {
result, err := registry.Execute(context.Background(), command)
if err != nil || result.Payload["outcome"] != "unknown" {
t.Fatalf("unknown vehicle outcome was not retained: result=%+v err=%v", result, err)
}
}
if len(port.requests) != 1 {
t.Fatalf("unknown vehicle outcome retried transport %d times", len(port.requests))
}
}