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
|
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
|
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) {
|
func normalizeRuntimeBinding(plugin domain.GamePlugin, binding domain.RuntimeBinding) (domain.RuntimeBinding, error) {
|
||||||
profile, _ := runtimeLifecycleProfile(plugin.RuntimeProfiles, binding.ProfileKey)
|
profile, ok := runtimeLifecycleProfile(plugin.RuntimeProfiles, binding.ProfileKey)
|
||||||
if profile.Key == "" {
|
if !ok {
|
||||||
return domain.RuntimeBinding{}, validationError("runtime profile is no longer declared")
|
return domain.RuntimeBinding{}, validationError("runtime profile is no longer declared")
|
||||||
}
|
}
|
||||||
|
binding.ProfileKey = profile.Key
|
||||||
required, allowed := runtimeBindingKeys(plugin.RuntimeProfiles, profile)
|
required, allowed := runtimeBindingKeys(plugin.RuntimeProfiles, profile)
|
||||||
for key := range binding.Bindings {
|
for key := range binding.Bindings {
|
||||||
if _, ok := allowed[key]; !ok {
|
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) {
|
func TestRuntimeBindingValidationAndLifecycleGating(t *testing.T) {
|
||||||
svc := newTestCoreService()
|
svc := newTestCoreService()
|
||||||
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
|
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) {
|
func runtimeLifecycleProfileForKey(profiles domain.GamePluginRuntimeProfiles, key string) (domain.RuntimeLifecycleProfile, bool) {
|
||||||
for _, profile := range profiles.LifecycleProfiles {
|
return runtimeLifecycleProfile(profiles, key)
|
||||||
if profile.Key == key {
|
|
||||||
return profile, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return domain.RuntimeLifecycleProfile{}, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func lifecycleDLLExtensionPlans(profiles domain.GamePluginRuntimeProfiles, profile domain.RuntimeLifecycleProfile, endpoint domain.RunEndpoint) ([]domain.RuntimeDLLExtensionPlan, error) {
|
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) {
|
func TestSourceRCONBrokerExpiresWithoutReplay(t *testing.T) {
|
||||||
stamp := fixedTime
|
stamp := fixedTime
|
||||||
broker := newSourceRCONCommandBroker(func() time.Time { return stamp })
|
broker := newSourceRCONCommandBroker(func() time.Time { return stamp })
|
||||||
|
|||||||
Reference in New Issue
Block a user