Fix local run freshness and plugin asset handling

This commit is contained in:
npc0-hue
2026-08-22 19:45:00 +08:00
parent bb5e48b29c
commit ebd616c549
23 changed files with 312 additions and 58 deletions
+30 -4
View File
@@ -1,6 +1,7 @@
package service
import (
"encoding/base64"
"errors"
"strings"
"testing"
@@ -165,6 +166,17 @@ func TestCoreServiceCreateListGetWorkflows(t *testing.T) {
}
func TestCoreServiceRejectsServerCreationOnStaleRunEndpoint(t *testing.T) {
svc := newTestCoreService()
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
svc.now = func() time.Time { return fixedTime.Add(runHeartbeatStaleAfter + time.Second) }
_, err := svc.CreateServerInstance(domain.ServerInstance{ID: "server-stale-run", PluginID: plugin.ID, RunEndpointID: endpoint.ID, Name: "Stale Run Server"})
if err == nil || !strings.Contains(err.Error(), "get run endpoint dependency") || !errors.Is(err, repo.ErrNotFound) {
t.Fatalf("expected stale Run endpoint to be rejected before binding, got %v", err)
}
}
func TestCoreServiceCreateRemoteProgramJobCreatesManagementLogStreams(t *testing.T) {
svc := newTestCoreService()
plugin, endpoint := createPluginAndRunEndpoint(t, svc)
@@ -685,7 +697,7 @@ func TestCoreServiceMetricsAndConfigReadAreRoleScoped(t *testing.T) {
if err != nil {
t.Fatalf("list owner metrics: %v", err)
}
if len(ownerMetrics) != 1 || ownerMetrics[0].ServerInstanceID != instance.ID || !ownerMetrics[0].Online || ownerMetrics[0].CPUPercent != nil || ownerMetrics[0].Source != "run-metrics-pending" {
if len(ownerMetrics) != 1 || ownerMetrics[0].ServerInstanceID != instance.ID || ownerMetrics[0].Online || ownerMetrics[0].CPUPercent != nil || ownerMetrics[0].Source != "run-metrics-pending" {
t.Fatalf("expected pending metrics without fabricated resource values, got %+v", ownerMetrics)
}
@@ -1223,8 +1235,8 @@ func TestCoreServiceRegistersGamePluginManifest(t *testing.T) {
svc := newTestCoreService()
registration := validPluginManifestRegistration()
registration.Manifest.AssetFiles = []domain.PluginAssetFile{{Path: "actions/install.json", Mode: 0o600}, {Path: "bin/install-server", Mode: 0o700}}
registration.AssetFiles = []domain.PluginAssetFile{{Path: "actions/install.json", Content: "{}", Mode: 0o600}, {Path: "bin/install-server", Content: "#!/usr/bin/env sh\n"}}
registration.Manifest.AssetFiles = []domain.PluginAssetFile{{Path: "actions/install.json", Mode: 0o600}, {Path: "bin/install-server", Mode: 0o700}, {Path: "assets/map.bin", Mode: 0o600}}
registration.AssetFiles = []domain.PluginAssetFile{{Path: "actions/install.json", Content: "{}", Mode: 0o600}, {Path: "bin/install-server", Content: "#!/usr/bin/env sh\n"}, {Path: "assets/map.bin", Content: base64.StdEncoding.EncodeToString([]byte{0xff, 0x00, 0x7f}), Encoding: "base64"}}
plugin, err := svc.RegisterGamePluginManifest(registration)
if err != nil {
t.Fatalf("register manifest: %v", err)
@@ -1247,7 +1259,7 @@ func TestCoreServiceRegistersGamePluginManifest(t *testing.T) {
if len(plugin.BridgeActions) != 4 || plugin.BridgeActions[0] != string(domain.PluginBridgeActionServerInstancesRead) {
t.Fatalf("expected bridge actions, got %+v", plugin.BridgeActions)
}
if len(plugin.LifecycleAssets) != 2 || plugin.LifecycleAssets[1].Path != "bin/install-server" || plugin.LifecycleAssets[1].Mode != 0o700 {
if len(plugin.LifecycleAssets) != 3 || plugin.LifecycleAssets[1].Path != "bin/install-server" || plugin.LifecycleAssets[1].Mode != 0o700 || plugin.LifecycleAssets[2].Encoding != "base64" {
t.Fatalf("expected declared lifecycle assets with manifest mode defaults, got %+v", plugin.LifecycleAssets)
}
@@ -1624,6 +1636,12 @@ func TestCoreServiceUpsertsDuplicateGamePluginManifest(t *testing.T) {
if _, err := svc.RegisterGamePluginManifest(registration); err != nil {
t.Fatalf("register first manifest: %v", err)
}
if _, err := svc.CreateServerInstance(domain.ServerInstance{ID: "manifest-refresh-server", PluginID: registration.Manifest.ID, PluginVersion: registration.Manifest.Version, Name: "Manifest refresh server"}); err != nil {
t.Fatalf("create server for manifest refresh: %v", err)
}
if err := svc.store.RuntimeBindings().Create(domain.RuntimeBinding{ID: "runtime-binding-manifest-refresh-server", ServerInstanceID: "manifest-refresh-server", PluginID: registration.Manifest.ID, PluginVersion: registration.Manifest.Version, ProfileKey: "local", Mode: "local-process", Status: domain.RuntimeBindingStatusComplete, CreatedAt: fixedTime, UpdatedAt: fixedTime}); err != nil {
t.Fatalf("create runtime binding for manifest refresh: %v", err)
}
registration.Manifest.Version = "0.1.1"
registration.Manifest.Description = "Development plugin refreshed"
@@ -1639,6 +1657,14 @@ func TestCoreServiceUpsertsDuplicateGamePluginManifest(t *testing.T) {
if err != nil || len(listed) != 1 || listed[0].ID != "game.example" || listed[0].Version != "0.1.1" {
t.Fatalf("expected one refreshed plugin after upsert, listed=%+v err=%v", listed, err)
}
server, err := svc.GetServerInstance("manifest-refresh-server")
if err != nil || server.PluginVersion != "0.1.1" {
t.Fatalf("expected existing server to follow refreshed plugin version, server=%+v err=%v", server, err)
}
binding, err := svc.store.RuntimeBindings().Get("runtime-binding-manifest-refresh-server")
if err != nil || binding.PluginVersion != "0.1.1" {
t.Fatalf("expected runtime binding to follow refreshed plugin version, binding=%+v err=%v", binding, err)
}
}
func TestCoreServiceRejectsUnsafeGamePluginManifest(t *testing.T) {