Files
browser/platform/model/resources_test.go
T

176 lines
7.5 KiB
Go

package model
import (
"reflect"
"testing"
"browser.local/platform/domain"
)
func TestTableNames(t *testing.T) {
tests := map[string]string{
User{}.TableName(): "users",
AIProvider{}.TableName(): "ai_providers",
GamePlugin{}.TableName(): "game_plugins",
ServerInstance{}.TableName(): "server_instances",
RunEndpoint{}.TableName(): "run_endpoints",
Job{}.TableName(): "jobs",
Artifact{}.TableName(): "artifacts",
LogStream{}.TableName(): "log_streams",
PluginLifecycleInstallation{}.TableName(): "plugin_lifecycle_installations",
AIConfigDiff{}.TableName(): "ai_config_diffs",
}
for got, want := range tests {
if got != want {
t.Fatalf("expected table name %q, got %q", want, got)
}
}
}
func TestGamePluginModelRoundTripCopiesSlices(t *testing.T) {
source := domain.GamePlugin{
ID: "server.scum",
Name: "SCUM",
Version: "1.0.0",
ServerType: "scum",
ManifestRef: "artifact://manifest",
CreateFormSchemaRef: "artifact://schema",
RequiredRunCapabilities: []string{"process.start", "logs.read"},
DeclaredPermissions: []string{"server.logs.read"},
SupportedOS: []string{"linux"},
Pages: []domain.GamePluginPage{
{Key: "logs", Title: "Logs", Path: "/logs", Permissions: []string{"server.logs.read"}},
},
Tags: []string{"survival"},
AIPurposes: []string{"logs.diagnose"},
ProductionLifecycle: domain.GamePluginProductionLifecycle{
Operations: []string{"install", "upgrade", "rollback"},
DependencyPolicy: "required",
},
RuntimeProfiles: domain.GamePluginRuntimeProfiles{LifecycleProfiles: []domain.RuntimeLifecycleProfile{{Key: "local", Mode: "local-process", Capabilities: []string{"process.start"}}}},
Permissions: domain.PluginPermissions{
Jobs: true,
Logs: true,
},
Status: domain.GamePluginStatusInstalled,
}
row := GamePluginFromDomain(source)
roundTrip := row.ToDomain()
roundTrip.RequiredRunCapabilities[0] = "files.read"
roundTrip.DeclaredPermissions[0] = "ai.invoke"
roundTrip.SupportedOS[0] = "darwin"
roundTrip.Pages[0].Permissions[0] = "ai.invoke"
roundTrip.Tags[0] = "mutated"
roundTrip.AIPurposes[0] = "config.suggest"
roundTrip.ProductionLifecycle.Operations[0] = "retire"
roundTrip.RuntimeProfiles.LifecycleProfiles[0].Capabilities[0] = "process.stop"
if source.RequiredRunCapabilities[0] != "process.start" {
t.Fatalf("expected source plugin capabilities to remain unchanged, got %+v", source.RequiredRunCapabilities)
}
if row.RequiredRunCapabilities[0] != "process.start" {
t.Fatalf("expected model plugin capabilities to remain unchanged, got %+v", row.RequiredRunCapabilities)
}
if source.DeclaredPermissions[0] != "server.logs.read" || source.Pages[0].Permissions[0] != "server.logs.read" || source.Tags[0] != "survival" || source.AIPurposes[0] != "logs.diagnose" {
t.Fatalf("expected source plugin registry metadata to remain unchanged, got %+v", source)
}
if row.DeclaredPermissions[0] != "server.logs.read" || row.Pages[0].Permissions[0] != "server.logs.read" || row.Tags[0] != "survival" || row.AIPurposes[0] != "logs.diagnose" {
t.Fatalf("expected model plugin registry metadata to remain unchanged, got %+v", row)
}
if source.ProductionLifecycle.Operations[0] != "install" || row.ProductionLifecycle.Operations[0] != "install" {
t.Fatalf("expected production lifecycle declaration to round-trip without aliasing, source=%+v row=%+v", source.ProductionLifecycle, row.ProductionLifecycle)
}
if source.RuntimeProfiles.LifecycleProfiles[0].Capabilities[0] != "process.start" || row.RuntimeProfiles.LifecycleProfiles[0].Capabilities[0] != "process.start" {
t.Fatalf("expected runtime profiles to round-trip without aliasing, source=%+v row=%+v", source.RuntimeProfiles, row.RuntimeProfiles)
}
}
func TestJobExecutionInputModelRoundTripPreservesLifecycleMetadata(t *testing.T) {
source := domain.JobExecutionInput{
WorkspaceScope: "server-workspace",
PluginID: "game.scum",
LifecycleOperation: "upgrade",
TargetVersion: "2.0.0",
Inputs: map[string]string{"templateKey": "players.by-id", "playerId": "steam-123"},
Deployment: &domain.ServerDeploymentDefinition{
Mode: domain.ServerDeploymentModeGuided,
ProfileKey: "run-local",
RuntimeBindings: map[string]string{"installRoot": "D:\\scumserver"},
CreateInputs: map[string]string{"gamePort": "27000", "maxPlayers": "128"},
ServerRoot: "D:\\scumserver",
WorkingDirectory: "D:\\scumserver",
InstallCommand: "install.cmd",
StartCommand: "start.cmd",
Shell: domain.ServerCommandShellCmd,
Revision: 3,
},
ServerDeploymentPlan: &domain.ServerDeploymentPlan{
SchemaVersion: "1",
Operation: "install",
PluginID: "game.scum",
Prerequisites: []domain.RuntimeServerPrerequisite{{Key: "steamcmd", Kind: "tool"}},
},
}
row := executionInputFromDomain(source)
source.Inputs["playerId"] = "source-mutated"
if row.Inputs["playerId"] != "steam-123" {
t.Fatalf("expected model execution inputs to be isolated from source mutation, row=%+v", row.Inputs)
}
source.Deployment.CreateInputs["maxPlayers"] = "64"
if row.Deployment == nil || row.Deployment.CreateInputs["maxPlayers"] != "128" {
t.Fatalf("expected model deployment inputs to be isolated from source mutation, row=%+v", row.Deployment)
}
source.Inputs["playerId"] = "steam-123"
source.Deployment.CreateInputs["maxPlayers"] = "128"
row.Inputs["playerId"] = "row-mutated"
if source.Inputs["playerId"] != "steam-123" {
t.Fatalf("expected source execution inputs to be isolated from model mutation, source=%+v", source.Inputs)
}
row.Deployment.CreateInputs["maxPlayers"] = "32"
if source.Deployment.CreateInputs["maxPlayers"] != "128" {
t.Fatalf("expected source deployment inputs to be isolated from model mutation, source=%+v", source.Deployment)
}
row.Inputs["playerId"] = "steam-123"
row.Deployment.CreateInputs["maxPlayers"] = "128"
roundTrip := row.ToDomain()
if !reflect.DeepEqual(roundTrip, source) {
t.Fatalf("expected lifecycle execution metadata to round-trip, got %+v", roundTrip)
}
roundTrip.Inputs["playerId"] = "mutated"
roundTrip.Deployment.CreateInputs["maxPlayers"] = "16"
if source.Inputs["playerId"] != "steam-123" || row.Inputs["playerId"] != "steam-123" || source.Deployment.CreateInputs["maxPlayers"] != "128" || row.Deployment.CreateInputs["maxPlayers"] != "128" {
t.Fatalf("expected execution inputs to round-trip without aliasing, source=%+v row=%+v", source, row)
}
}
func TestAIProviderModelUsesKeyReference(t *testing.T) {
source := domain.AIProvider{
ID: "ai.openai",
Name: "OpenAI",
Kind: domain.AIProviderKindOpenAI,
BaseURL: "https://api.openai.com/v1",
APIKeyRef: "secret://providers/openai",
Models: []string{"gpt-4.1"},
DefaultModel: "gpt-4.1",
RelayMode: domain.AIRelayModeDirect,
TimeoutMS: 30000,
Status: domain.AIProviderStatusActive,
RedactionPolicy: "default",
}
row := AIProviderFromDomain(source)
if row.APIKeyRef != source.APIKeyRef {
t.Fatalf("expected API key reference %q, got %q", source.APIKeyRef, row.APIKeyRef)
}
roundTrip := row.ToDomain()
roundTrip.Models[0] = "mutated"
if row.Models[0] != "gpt-4.1" {
t.Fatalf("expected model provider models to remain unchanged, got %+v", row.Models)
}
}