fix legacy SCUM RCON runtime profile resolution
This commit is contained in:
@@ -102,6 +102,23 @@ func runtimeLifecycleProfile(profiles domain.GamePluginRuntimeProfiles, key stri
|
||||
return profile, true
|
||||
}
|
||||
}
|
||||
// Older persisted bindings used "local" for the only local-process profile.
|
||||
// Infer that legacy key only when the plugin has one unambiguous candidate.
|
||||
if key != "local" {
|
||||
return domain.RuntimeLifecycleProfile{}, false
|
||||
}
|
||||
var candidate domain.RuntimeLifecycleProfile
|
||||
count := 0
|
||||
for _, profile := range profiles.LifecycleProfiles {
|
||||
if profile.Mode != "local-process" {
|
||||
continue
|
||||
}
|
||||
candidate = profile
|
||||
count++
|
||||
}
|
||||
if count == 1 {
|
||||
return candidate, true
|
||||
}
|
||||
return domain.RuntimeLifecycleProfile{}, false
|
||||
}
|
||||
|
||||
@@ -152,10 +169,11 @@ func runtimeBindingKeys(profiles domain.GamePluginRuntimeProfiles, profile domai
|
||||
}
|
||||
|
||||
func normalizeRuntimeBinding(plugin domain.GamePlugin, binding domain.RuntimeBinding) (domain.RuntimeBinding, error) {
|
||||
profile, _ := runtimeLifecycleProfile(plugin.RuntimeProfiles, binding.ProfileKey)
|
||||
if profile.Key == "" {
|
||||
profile, ok := runtimeLifecycleProfile(plugin.RuntimeProfiles, binding.ProfileKey)
|
||||
if !ok {
|
||||
return domain.RuntimeBinding{}, validationError("runtime profile is no longer declared")
|
||||
}
|
||||
binding.ProfileKey = profile.Key
|
||||
required, allowed := runtimeBindingKeys(plugin.RuntimeProfiles, profile)
|
||||
for key := range binding.Bindings {
|
||||
if _, ok := allowed[key]; !ok {
|
||||
|
||||
@@ -41,6 +41,29 @@ func TestRegisteredRuntimeProfilesSurviveFileStoreReload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLegacyLocalRuntimeBindingCanonicalizesToUnambiguousLocalProcessProfile(t *testing.T) {
|
||||
plugin := domain.GamePlugin{RuntimeProfiles: domain.GamePluginRuntimeProfiles{
|
||||
LifecycleProfiles: []domain.RuntimeLifecycleProfile{{Key: "run-local", Mode: "local-process"}},
|
||||
}}
|
||||
binding, err := normalizeRuntimeBinding(plugin, domain.RuntimeBinding{ID: "binding-legacy", ServerInstanceID: "server-legacy", PluginID: "plugin-legacy", PluginVersion: "1.0.0", ProfileKey: "local", Bindings: map[string]string{}, CreatedAt: fixedTime, UpdatedAt: fixedTime})
|
||||
if err != nil {
|
||||
t.Fatalf("normalize legacy runtime binding: %v", err)
|
||||
}
|
||||
if binding.ProfileKey != "run-local" || binding.Mode != "local-process" {
|
||||
t.Fatalf("expected canonical local-process profile, got %+v", binding)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLegacyLocalRuntimeBindingDoesNotGuessAmbiguousProfiles(t *testing.T) {
|
||||
profiles := domain.GamePluginRuntimeProfiles{LifecycleProfiles: []domain.RuntimeLifecycleProfile{
|
||||
{Key: "run-local", Mode: "local-process"},
|
||||
{Key: "run-local-alt", Mode: "local-process"},
|
||||
}}
|
||||
if _, ok := runtimeLifecycleProfile(profiles, "local"); ok {
|
||||
t.Fatal("expected ambiguous legacy local profile lookup to fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntimeBindingValidationAndLifecycleGating(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
|
||||
|
||||
@@ -441,12 +441,7 @@ func runtimeProfileActionRef(actions domain.PluginLifecycleActions, action domai
|
||||
}
|
||||
|
||||
func runtimeLifecycleProfileForKey(profiles domain.GamePluginRuntimeProfiles, key string) (domain.RuntimeLifecycleProfile, bool) {
|
||||
for _, profile := range profiles.LifecycleProfiles {
|
||||
if profile.Key == key {
|
||||
return profile, true
|
||||
}
|
||||
}
|
||||
return domain.RuntimeLifecycleProfile{}, false
|
||||
return runtimeLifecycleProfile(profiles, key)
|
||||
}
|
||||
|
||||
func lifecycleDLLExtensionPlans(profiles domain.GamePluginRuntimeProfiles, profile domain.RuntimeLifecycleProfile, endpoint domain.RunEndpoint) ([]domain.RuntimeDLLExtensionPlan, error) {
|
||||
|
||||
@@ -106,6 +106,26 @@ func TestSourceRCONDispatchRejectsUnsafeOrIncompatibleState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceRCONDispatchCanonicalizesLegacyLocalBinding(t *testing.T) {
|
||||
svc, _, _, instance := newSourceRCONFixture(t)
|
||||
plugin, err := svc.store.GamePlugins().Get(instance.PluginID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plugin.RuntimeProfiles.LifecycleProfiles[0].Key = "run-local"
|
||||
if err := svc.store.GamePlugins().Update(plugin); err != nil {
|
||||
t.Fatalf("update runtime profile key: %v", err)
|
||||
}
|
||||
|
||||
resolution, err := svc.resolveSourceRCONDispatch(instance)
|
||||
if err != nil {
|
||||
t.Fatalf("resolve RCON dispatch with legacy binding: %v", err)
|
||||
}
|
||||
if resolution.binding.ProfileKey != "run-local" {
|
||||
t.Fatalf("expected legacy binding to be canonicalized, got %q", resolution.binding.ProfileKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceRCONBrokerExpiresWithoutReplay(t *testing.T) {
|
||||
stamp := fixedTime
|
||||
broker := newSourceRCONCommandBroker(func() time.Time { return stamp })
|
||||
|
||||
Reference in New Issue
Block a user