feat(scum): rebuild plugin-owned management data
This commit is contained in:
@@ -25,6 +25,28 @@ type notificationPortFixture struct {
|
||||
accepted bool
|
||||
}
|
||||
|
||||
type rewardPortFixture struct {
|
||||
grants []RewardGrant
|
||||
receipt DeliveryReceipt
|
||||
err error
|
||||
}
|
||||
|
||||
func (fixture *rewardPortFixture) DeliverReward(_ context.Context, grant RewardGrant) (DeliveryReceipt, error) {
|
||||
fixture.grants = append(fixture.grants, grant)
|
||||
return fixture.receipt, fixture.err
|
||||
}
|
||||
|
||||
type eventPortFixture struct {
|
||||
requests []EventStartRequest
|
||||
receipt EventStartReceipt
|
||||
err error
|
||||
}
|
||||
|
||||
func (fixture *eventPortFixture) StartEvent(_ context.Context, request EventStartRequest) (EventStartReceipt, error) {
|
||||
fixture.requests = append(fixture.requests, request)
|
||||
return fixture.receipt, fixture.err
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -68,6 +90,87 @@ func TestRuntimeAdapterUsesOnlyLogicalConfigValuesAndRedactsDiagnostics(t *testi
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewardDeliveryAcceptsRealSCUMCatalogCodesAndReturnsDeclaredResult(t *testing.T) {
|
||||
port := &rewardPortFixture{receipt: DeliveryReceipt{Outcome: "delivered", DeliveryID: "delivery-1"}}
|
||||
adapter := RuntimeAdapter{Rewards: port}
|
||||
result, err := adapter.DeliverReward(context.Background(), map[string]any{
|
||||
"grantId": "grant-1", "playerId": "76561198000000001",
|
||||
"items": []any{map[string]any{"catalogCode": "BPC_Improvised_Backpack.01", "quantity": float64(2)}},
|
||||
"operations": []any{"#SpawnItem BPC_Improvised_Backpack.01 2"},
|
||||
})
|
||||
if err != nil || result["accepted"] != true || result["status"] != "delivered" || result["deliveryId"] != "delivery-1" {
|
||||
t.Fatalf("reward result did not match the bridge schema: result=%+v err=%v", result, err)
|
||||
}
|
||||
if len(port.grants) != 1 || port.grants[0].Items[0] != (RewardItem{CatalogCode: "BPC_Improvised_Backpack.01", Quantity: 2}) || len(port.grants[0].Operations) != 1 || port.grants[0].Operations[0] != "#SpawnItem BPC_Improvised_Backpack.01 2" {
|
||||
t.Fatalf("reward items or operations did not reach the typed reward port: %+v", port.grants)
|
||||
}
|
||||
before := len(port.grants)
|
||||
if _, err := adapter.DeliverReward(context.Background(), map[string]any{
|
||||
"grantId": "grant-2", "playerId": "76561198000000001",
|
||||
"items": []any{map[string]any{"catalogCode": "#SpawnItem BPC_Bad", "quantity": float64(1)}},
|
||||
"operations": []any{},
|
||||
}); err == nil || len(port.grants) != before {
|
||||
t.Fatal("invalid catalog text reached the typed reward port")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewardDeliverySupportsOperationsWithoutItemsAndRejectsEmptyGrant(t *testing.T) {
|
||||
port := &rewardPortFixture{receipt: DeliveryReceipt{Outcome: "delivered"}}
|
||||
adapter := RuntimeAdapter{BoundServerID: "server-1", Rewards: port}
|
||||
registry := NewHandlerRegistry(HandlerAvailability{BoundServerID: "server-1", Approved: true, Capabilities: map[string]bool{"reward.deliver": true}}, adapter)
|
||||
stamp := time.Now().UTC()
|
||||
result, err := registry.Execute(context.Background(), ClaimedCommand{
|
||||
ID: "reward-operations", ProfileKey: ProfileKey, CommandType: "reward.deliver", FencingToken: 1,
|
||||
LeaseExpiresAt: stamp.Add(time.Minute), ExpiresAt: stamp.Add(time.Minute),
|
||||
Payload: map[string]any{"grantId": "grant-operations", "playerId": "76561198000000001", "items": []any{}, "operations": []any{"#SetFamePoints 250"}},
|
||||
})
|
||||
if err != nil || result.Status != "succeeded" || result.Payload["accepted"] != true || len(port.grants) != 1 || len(port.grants[0].Items) != 0 || len(port.grants[0].Operations) != 1 || port.grants[0].Operations[0] != "#SetFamePoints 250" {
|
||||
t.Fatalf("operation-only reward was not preserved: result=%+v grants=%+v err=%v", result, port.grants, err)
|
||||
}
|
||||
if _, err := adapter.DeliverReward(context.Background(), map[string]any{
|
||||
"grantId": "grant-empty", "playerId": "76561198000000001", "items": []any{}, "operations": []any{},
|
||||
}); err == nil || len(port.grants) != 1 {
|
||||
t.Fatalf("empty reward reached the typed reward port: grants=%+v err=%v", port.grants, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventStartRequiresMatchingClassAndType(t *testing.T) {
|
||||
payload := map[string]any{"eventId": "event-fixed", "eventType": "fixed", "class": float64(2), "title": "Fixed Event", "placard": "Hold the point", "percent": float64(100), "produces": []any{}, "durationSeconds": float64(600)}
|
||||
request, err := eventStartRequest(payload)
|
||||
if err != nil || request.EventType != "fixed" || request.Class != 2 {
|
||||
t.Fatalf("fixed class event was not accepted: request=%+v err=%v", request, err)
|
||||
}
|
||||
payload["class"] = float64(1)
|
||||
if _, err := eventStartRequest(payload); err == nil {
|
||||
t.Fatal("divergent event class and type was accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEventStartHandlerInvokesTypedPortAndReturnsCachedCommandResult(t *testing.T) {
|
||||
stamp := time.Now().UTC()
|
||||
port := &eventPortFixture{receipt: EventStartReceipt{Accepted: true, Status: "started", EventID: "event-1", Message: "range event started"}}
|
||||
adapter := RuntimeAdapter{BoundServerID: "server-1", Events: port}
|
||||
registry := NewHandlerRegistry(HandlerAvailability{BoundServerID: "server-1", Approved: true, Capabilities: map[string]bool{"event.start": true}}, adapter)
|
||||
command := ClaimedCommand{
|
||||
ID: "event-command-1", ProfileKey: ProfileKey, CommandType: "event.start", FencingToken: 1,
|
||||
LeaseExpiresAt: stamp.Add(time.Minute), ExpiresAt: stamp.Add(time.Minute),
|
||||
Payload: map[string]any{"eventId": "event-1", "eventType": "range", "class": float64(1), "title": "Friday Range", "placard": "Event starting", "percent": float64(75), "npc": float64(2), "item": float64(3), "zombie": float64(4), "animal": float64(1), "produces": []any{map[string]any{"tradeGoodsId": "cargo-drop", "percent": float64(80), "value": float64(2), "r": float64(500), "x": float64(1000), "y": float64(2000), "z": float64(300)}}, "durationSeconds": float64(1800), "maxParticipants": float64(40), "announce": true},
|
||||
}
|
||||
for range 2 {
|
||||
result, err := registry.Execute(context.Background(), command)
|
||||
if err != nil || result.Status != "succeeded" || result.Payload["accepted"] != true || result.Payload["status"] != "started" || result.Payload["eventId"] != "event-1" {
|
||||
t.Fatalf("event.start did not return its executable result: result=%+v err=%v", result, err)
|
||||
}
|
||||
}
|
||||
if len(port.requests) != 1 {
|
||||
t.Fatalf("event.start handler did not execute exactly once: %+v", port.requests)
|
||||
}
|
||||
request := port.requests[0]
|
||||
if request.EventID != "event-1" || request.EventType != "range" || request.Class != 1 || request.Title != "Friday Range" || request.Placard != "Event starting" || request.Percent != 75 || request.NPC != 2 || request.Item != 3 || request.Zombie != 4 || request.Animal != 1 || len(request.Produces) != 1 || request.Produces[0].TradeGoodsID != "cargo-drop" || request.DurationSeconds != 1800 || request.MaxParticipants != 40 || !request.Announce {
|
||||
t.Fatalf("event.start payload did not reach the typed event port: %+v", request)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUE4SSNotificationIsTypedAndRedacted(t *testing.T) {
|
||||
port := ¬ificationPortFixture{accepted: true}
|
||||
adapter := RuntimeAdapter{BoundServerID: "server-1", Notification: port}
|
||||
|
||||
Reference in New Issue
Block a user