refactor(schema): 迁移 043 schema 收敛——42→19 张表,统一迁移 runner
- 迁移 043 一次到位:runtime_instance/environment_binding 并入 browser_env(账号即环境)、 credential_reference 并入 social_account、work_source/metric_plan 并入 creator_work、 sync 租约并入 creator_collection_checkpoint(kind='sync')、audit_event 瘦列、 creator_settings 去转写列、TRUNCATE 账号域(竞品采集数据无损保留) - 统一迁移 runner:environment.Open 串起 001 账号基座 + hub 链 + 038 creator 版本回填 (v+1000) + creator 1017-1042 + 043;account/creator Open 不再迁移 - 三域 store SQL 全量适配:CreateBoundEnv 就绪门禁、SetRuntimeCleanupPending fence 语义(未知代 MissingRuntimeID 允许登记并释放活跃实例)、metric_plan 列并入 work、 checkpoint sync 租约、deletion 链路重写 - api 适配:envView 去 runtime_instance_id、audit filter 去任务列、browser_env 单表查询 - 测试:迁移 043 形态探针、迁移不可变映射新路径、legacy 迁移重放子测试重写、 fence/出口生命周期/单来源 upsert 语义覆盖;CREATORHUB_POSTGRES_TEST_URL 全绿, environment 70%/creator 67.5% 覆盖率,tsc 通过
This commit is contained in:
@@ -80,7 +80,7 @@ func TestResumeBlockReasonIsStable(t *testing.T) {
|
||||
"direct exit": {account, hub.EnvironmentContext{}, true, "account_conflict"},
|
||||
"unhealthy exit": {account, hub.EnvironmentContext{Exit: hub.NetworkExit{ID: "exit-a", HealthStatus: "unhealthy"}}, true, "network_exit_unhealthy"},
|
||||
"cleanup pending": {account, hub.EnvironmentContext{Exit: healthy.Exit, RuntimeCleanupPending: true}, true, "runtime_stop_pending"},
|
||||
"runtime active": {account, hub.EnvironmentContext{Exit: healthy.Exit, RuntimeInstanceID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, true, "runtime_active"},
|
||||
"runtime active": {account, hub.EnvironmentContext{Exit: healthy.Exit, RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, true, "runtime_active"},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if got := resumeBlockReason(test.account, test.env, test.found); got != test.want {
|
||||
@@ -293,7 +293,7 @@ func (s *memoryStore) CreateBoundEnv(ctx context.Context, env hub.Env, accountID
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
bound := hub.EnvironmentContext{Env: env, AccountID: accountID, AccountStatus: "active", AuthorizationStatus: "authorized",
|
||||
BindingID: accountID, BindingVersion: 1, Exit: s.exits[exitID]}
|
||||
BindingVersion: 1, Exit: s.exits[exitID]}
|
||||
s.bindings[env.Alias] = bound
|
||||
return bound, true, nil
|
||||
}
|
||||
@@ -311,7 +311,7 @@ func (s *memoryStore) GetEnvironmentContext(_ context.Context, alias string) (hu
|
||||
return hub.EnvironmentContext{}, hub.ErrNotFound
|
||||
}
|
||||
return hub.EnvironmentContext{Env: env, AccountID: alias, AccountStatus: "active", AuthorizationStatus: "authorized",
|
||||
BindingID: alias, BindingVersion: 1, Exit: s.exits["exit-1"]}, nil
|
||||
BindingVersion: 1, Exit: s.exits["exit-1"]}, nil
|
||||
}
|
||||
func (s *memoryStore) GetEnvironmentContextForAccount(ctx context.Context, accountID string) (hub.EnvironmentContext, error) {
|
||||
s.mu.Lock()
|
||||
@@ -341,14 +341,14 @@ func (s *memoryStore) RebindEnvironment(_ context.Context, alias, exitID, runtim
|
||||
defer s.mu.Unlock()
|
||||
bound, ok := s.bindings[alias]
|
||||
if !ok {
|
||||
bound = hub.EnvironmentContext{Env: s.envs[alias], AccountID: alias, BindingID: alias, BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
bound = hub.EnvironmentContext{Env: s.envs[alias], AccountID: alias, BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
}
|
||||
if bound.BindingVersion != expectedBindingVersion || bound.RuntimeCleanupPending {
|
||||
return hub.EnvironmentContext{}, hub.ErrConflict
|
||||
}
|
||||
bound.RuntimeInstanceID, bound.RuntimeID, bound.RuntimeNetworkID = "", "", ""
|
||||
bound.RuntimeID, bound.RuntimeNetworkID = "", ""
|
||||
if runtimeID != "" {
|
||||
bound.RuntimeInstanceID, bound.RuntimeID = "runtime-instance", runtimeID
|
||||
bound.RuntimeID = runtimeID
|
||||
if len(networkIDs) == 1 {
|
||||
bound.RuntimeNetworkID = networkIDs[0]
|
||||
}
|
||||
@@ -365,7 +365,7 @@ func (s *memoryStore) ActivateRuntime(_ context.Context, alias, runtimeID string
|
||||
}
|
||||
bound, ok := s.bindings[alias]
|
||||
if !ok {
|
||||
bound = hub.EnvironmentContext{Env: s.envs[alias], AccountID: alias, BindingID: alias, BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
bound = hub.EnvironmentContext{Env: s.envs[alias], AccountID: alias, BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
}
|
||||
if bound.AccountStatus == "" {
|
||||
bound.AccountStatus, bound.AuthorizationStatus = "active", "authorized"
|
||||
@@ -374,7 +374,7 @@ func (s *memoryStore) ActivateRuntime(_ context.Context, alias, runtimeID string
|
||||
bound.BindingVersion != bindingVersion || bound.Exit.ID != exitID || bound.RuntimeCleanupPending {
|
||||
return hub.EnvironmentContext{}, hub.ErrConflict
|
||||
}
|
||||
bound.RuntimeInstanceID, bound.RuntimeID = "runtime-instance", runtimeID
|
||||
bound.RuntimeID = runtimeID
|
||||
bound.RuntimeNetworkID = networkIDs[0]
|
||||
s.bindings[alias] = bound
|
||||
return bound, nil
|
||||
@@ -388,16 +388,16 @@ func (s *memoryStore) ReleaseRuntime(_ context.Context, environment hub.Environm
|
||||
bound, ok := s.bindings[environment.Alias]
|
||||
if !ok {
|
||||
bound = hub.EnvironmentContext{Env: s.envs[environment.Alias], AccountID: environment.Alias,
|
||||
BindingID: environment.Alias, BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
}
|
||||
if environment.RuntimeInstanceID == "" {
|
||||
if environment.RuntimeID == "" {
|
||||
return nil
|
||||
}
|
||||
if bound.BindingID != environment.BindingID || bound.BindingVersion != environment.BindingVersion ||
|
||||
bound.RuntimeInstanceID != environment.RuntimeInstanceID {
|
||||
if bound.Alias != environment.Alias || bound.BindingVersion != environment.BindingVersion ||
|
||||
bound.RuntimeID != environment.RuntimeID {
|
||||
return hub.ErrConflict
|
||||
}
|
||||
bound.RuntimeInstanceID, bound.RuntimeID, bound.RuntimeNetworkID = "", "", ""
|
||||
bound.RuntimeID, bound.RuntimeNetworkID = "", ""
|
||||
s.bindings[environment.Alias] = bound
|
||||
return nil
|
||||
}
|
||||
@@ -416,31 +416,30 @@ func (s *memoryStore) SetRuntimeCleanupPending(_ context.Context, environment hu
|
||||
bound, ok := s.bindings[environment.Alias]
|
||||
if !ok {
|
||||
bound = hub.EnvironmentContext{Env: s.envs[environment.Alias], AccountID: environment.Alias,
|
||||
BindingID: environment.Alias, BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
BindingVersion: 1, Exit: s.exits["exit-1"]}
|
||||
}
|
||||
if bound.BindingID != environment.BindingID || bound.BindingVersion != environment.BindingVersion {
|
||||
if bound.Alias != environment.Alias || bound.BindingVersion != environment.BindingVersion {
|
||||
return hub.ErrConflict
|
||||
}
|
||||
if bound.RuntimeCleanupPending {
|
||||
if bound.RuntimeCleanupBindingVersion != environment.RuntimeCleanupBindingVersion ||
|
||||
bound.RuntimeCleanupInstanceID != environment.RuntimeCleanupInstanceID ||
|
||||
bound.RuntimeCleanupRuntimeID != environment.RuntimeCleanupRuntimeID ||
|
||||
bound.RuntimeCleanupNetworkID != environment.RuntimeCleanupNetworkID {
|
||||
return hub.ErrConflict
|
||||
}
|
||||
} else if pending && bound.RuntimeInstanceID != environment.RuntimeCleanupInstanceID {
|
||||
} else if pending && bound.RuntimeID != "" && bound.RuntimeID != environment.RuntimeCleanupRuntimeID &&
|
||||
environment.RuntimeCleanupRuntimeID != hub.MissingRuntimeID {
|
||||
return hub.ErrConflict
|
||||
}
|
||||
bound.RuntimeCleanupPending = pending
|
||||
if pending {
|
||||
bound.RuntimeCleanupBindingVersion = environment.RuntimeCleanupBindingVersion
|
||||
bound.RuntimeCleanupInstanceID = environment.RuntimeCleanupInstanceID
|
||||
bound.RuntimeCleanupRuntimeID = environment.RuntimeCleanupRuntimeID
|
||||
bound.RuntimeCleanupNetworkID = environment.RuntimeCleanupNetworkID
|
||||
bound.RuntimeInstanceID, bound.RuntimeID, bound.RuntimeNetworkID = "", "", ""
|
||||
bound.RuntimeID, bound.RuntimeNetworkID = "", ""
|
||||
} else {
|
||||
bound.RuntimeCleanupBindingVersion = 0
|
||||
bound.RuntimeCleanupInstanceID, bound.RuntimeCleanupRuntimeID, bound.RuntimeCleanupNetworkID = "", "", ""
|
||||
bound.RuntimeCleanupRuntimeID, bound.RuntimeCleanupNetworkID = "", ""
|
||||
}
|
||||
s.bindings[environment.Alias] = bound
|
||||
return s.cleanupPendingErr
|
||||
@@ -964,7 +963,7 @@ func TestExitFailuresStopCreateBeforeGateway(t *testing.T) {
|
||||
t.Fatalf("exit failure must stop before any gateway start/create call: %#v", gateway.recorded())
|
||||
}
|
||||
bound, err := store.GetEnvironmentContext(context.Background(), "account-a")
|
||||
if err != nil || bound.RuntimeInstanceID != "" || store.exits["exit-1"].HealthStatus != "unhealthy" {
|
||||
if err != nil || bound.RuntimeID != "" || store.exits["exit-1"].HealthStatus != "unhealthy" {
|
||||
t.Fatalf("failed create must retain only the stable inactive binding: %#v err=%v", bound, err)
|
||||
}
|
||||
if len(store.actions) != 2 || store.actions[1].Outcome != "failed" || store.actions[1].ReasonCode != test.reason {
|
||||
@@ -1029,8 +1028,8 @@ func TestReconcileGatewayCreateDoesNotReuseOldNetworkGeneration(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Gateway: "gw-1"}
|
||||
environment := hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "active",
|
||||
AuthorizationStatus: "authorized", BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeInstanceID: "runtime-instance-c1", RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}
|
||||
AuthorizationStatus: "authorized", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}
|
||||
store.bindings[environment.Alias] = environment
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", NetworkID: "native-99999999999999999999999999999999", ProxyReady: true,
|
||||
@@ -1064,17 +1063,17 @@ func TestValidCreatedRuntimeGeneration(t *testing.T) {
|
||||
{name: "active invalid network", created: runtimeStatus{ID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", NetworkID: "network n1"}, running: true},
|
||||
{name: "active replacement network", created: runtimeStatus{ID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", NetworkID: "native-88888888888888888888888888888888"}, running: true},
|
||||
{name: "active existing matching generation", created: runtimeStatus{ID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", NetworkID: "native-99999999999999999999999999999999"}, running: true, want: true,
|
||||
environment: hub.EnvironmentContext{RuntimeInstanceID: "runtime-instance-c1", RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}},
|
||||
environment: hub.EnvironmentContext{RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}},
|
||||
{name: "active existing successor container", created: runtimeStatus{ID: "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", NetworkID: "native-99999999999999999999999999999999"}, running: true,
|
||||
environment: hub.EnvironmentContext{RuntimeInstanceID: "runtime-instance-c1", RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}},
|
||||
environment: hub.EnvironmentContext{RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}},
|
||||
{name: "active legacy lease without network", created: runtimeStatus{ID: "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", NetworkID: "native-88888888888888888888888888888888"}, running: true,
|
||||
environment: hub.EnvironmentContext{RuntimeInstanceID: "runtime-instance-c1", RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}},
|
||||
environment: hub.EnvironmentContext{RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}},
|
||||
{name: "stopped empty network", created: runtimeStatus{ID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}, want: true},
|
||||
{name: "stopped invalid network", created: runtimeStatus{ID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", NetworkID: "network n1"}},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
current := environment
|
||||
if test.environment.RuntimeInstanceID != "" {
|
||||
if test.environment.RuntimeID != "" {
|
||||
current = test.environment
|
||||
}
|
||||
if got := validCreatedRuntime(test.created, current, test.running); got != test.want {
|
||||
@@ -1107,9 +1106,7 @@ func TestActivationConflictKeepsTheGenerationWonByTheHeartbeat(t *testing.T) {
|
||||
AccountID: "account-a",
|
||||
AccountStatus: "active",
|
||||
AuthorizationStatus: "authorized",
|
||||
BindingID: "account-a",
|
||||
BindingVersion: 1,
|
||||
RuntimeInstanceID: "runtime-instance-c1",
|
||||
RuntimeID: candidateID,
|
||||
RuntimeNetworkID: candidateNetwork,
|
||||
Exit: store.exits["exit-1"],
|
||||
@@ -1121,7 +1118,7 @@ func TestActivationConflictKeepsTheGenerationWonByTheHeartbeat(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("activation race was reported as failure: %v", err)
|
||||
}
|
||||
if got.RuntimeID != candidateID || got.RuntimeNetworkID != candidateNetwork || got.RuntimeInstanceID == "" {
|
||||
if got.RuntimeID != candidateID || got.RuntimeNetworkID != candidateNetwork || got.RuntimeID == "" {
|
||||
t.Fatalf("heartbeat winner was not returned: %#v", got)
|
||||
}
|
||||
}
|
||||
@@ -1130,8 +1127,8 @@ func TestLegacyActiveRuntimeWithoutNetworkGenerationDoesNotTouchSuccessor(t *tes
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Gateway: "gw-1"}
|
||||
environment := hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "active",
|
||||
AuthorizationStatus: "authorized", BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeInstanceID: "runtime-instance-c1", RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}
|
||||
AuthorizationStatus: "authorized", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}
|
||||
store.bindings[environment.Alias] = environment
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", NetworkID: "native-88888888888888888888888888888888", ProxyReady: true,
|
||||
@@ -1378,7 +1375,7 @@ func TestListRestoresProxyAfterGatewayRestartBeforeHeartbeat(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "店铺一号", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 3, Exit: store.exits["exit-1"],
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 3, Exit: store.exits["exit-1"],
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Alias: "account-a", State: "running", BindingVersion: 3, NetworkExitID: "exit-1", NetworkID: "native-cccccccccccccccccccccccccccccccc", ProxyReady: false,
|
||||
@@ -1404,7 +1401,7 @@ func TestListRestoresProxyAfterGatewayRestartBeforeHeartbeat(t *testing.T) {
|
||||
func TestGatewayRestartRebuildsWhenOriginalProxyPortCannotBeRestored(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "店铺一号", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 2, Exit: store.exits["exit-1"]}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 2, Exit: store.exits["exit-1"]}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", failProxy: true, runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", BindingVersion: 2, NetworkExitID: "exit-1", NetworkID: "native-66666666666666666666666666666666",
|
||||
}}}
|
||||
@@ -1613,7 +1610,7 @@ func installCleanupTransitionFailure(t *testing.T, ctx context.Context, db *sql.
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := db.ExecContext(ctx, `
|
||||
CREATE TRIGGER fail_cleanup_transition BEFORE UPDATE OF runtime_cleanup_pending ON environment_binding
|
||||
CREATE TRIGGER fail_cleanup_transition BEFORE UPDATE OF runtime_cleanup_pending ON browser_env
|
||||
FOR EACH ROW EXECUTE FUNCTION fail_cleanup_transition()`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1621,7 +1618,7 @@ func installCleanupTransitionFailure(t *testing.T, ctx context.Context, db *sql.
|
||||
|
||||
func dropCleanupTransitionFailure(t *testing.T, ctx context.Context, db *sql.DB) {
|
||||
t.Helper()
|
||||
if _, err := db.ExecContext(ctx, `DROP TRIGGER fail_cleanup_transition ON environment_binding`); err != nil {
|
||||
if _, err := db.ExecContext(ctx, `DROP TRIGGER fail_cleanup_transition ON browser_env`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := db.ExecContext(ctx, `DROP FUNCTION fail_cleanup_transition()`); err != nil {
|
||||
@@ -1675,8 +1672,8 @@ func TestPostgresCleanupPendingPersistsAndReconciles(t *testing.T) {
|
||||
after.Exit.ID != fixture.bound.Exit.ID || after.RuntimeID != "" {
|
||||
t.Fatalf("PostgreSQL did not persist cleanup pending atomically: %#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM environment_binding WHERE browser_env_alias = 'account-a' AND runtime_cleanup_pending`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_cleanup_pending`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
|
||||
if err := reconcileRuntimeLeases(ctx, fixture.store, fakeExitProbe{}, func(hub.NetworkExitAccess) (string, error) { return "", nil }); err != nil {
|
||||
t.Fatalf("reconcile did not confirm cleanup: %v", err)
|
||||
@@ -1713,8 +1710,8 @@ func TestRestoreAndDiscardPreserveGenerationWhenCleanupMarkFails(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 2,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 2,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
}
|
||||
store.cleanupPendingErr = errors.New("cleanup state unavailable")
|
||||
store.cleanupPendingErrAfterMutation = !test.commitKnown
|
||||
@@ -1768,8 +1765,8 @@ func TestRestoreAndDiscardPreserveGenerationWhenCleanupMarkFails(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
}
|
||||
store.cleanupPendingErr = errors.New("cleanup state unavailable")
|
||||
store.cleanupPendingErrAfterMutation = !test.commitKnown
|
||||
@@ -1824,8 +1821,8 @@ func TestExistingCreateStopsOnGatewayUnknownAndRetriesReuse(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", disconnectList: gatewayReconcileAttempts, runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", ProxyReady: true, BindingVersion: 1, NetworkExitID: "exit-1", NetworkID: "native-66666666666666666666666666666666",
|
||||
@@ -1874,8 +1871,8 @@ func TestRemoveGatewayRuntimePreservesKnownNetworkGeneration(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Gateway: "gw-1"}
|
||||
environment := hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "active",
|
||||
AuthorizationStatus: "authorized", BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeInstanceID: "runtime-instance", RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}
|
||||
AuthorizationStatus: "authorized", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", RuntimeNetworkID: "native-99999999999999999999999999999999"}
|
||||
store.bindings["account-a"] = environment
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{ID: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Alias: "account-a",
|
||||
State: "running", BindingVersion: 1, NetworkExitID: "exit-1", NetworkID: test.observedNetwork, ProxyReady: true}}}
|
||||
@@ -1901,8 +1898,8 @@ func TestGatewayLookupFailurePreservesLease(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
environment := hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
}
|
||||
store.bindings[environment.Alias] = environment
|
||||
store.gatewayFn = func(string) (hub.Gateway, error) { return hub.Gateway{}, errors.New("gateway lookup unavailable") }
|
||||
@@ -1952,7 +1949,7 @@ func TestPostgresCleanupPendingTransactionRollbacks(t *testing.T) {
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID != "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" || len(fixture.gateway.runtimes) != 1 {
|
||||
t.Fatalf("PostgreSQL rollback did not preserve the active generation: after=%#v runtimes=%#v err=%v", after, fixture.gateway.runtimes, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 1)
|
||||
|
||||
dropCleanupTransitionFailure(t, ctx, fixture.db)
|
||||
fixture.gateway.cleanupPending = 2
|
||||
@@ -1964,7 +1961,7 @@ func TestPostgresCleanupPendingTransactionRollbacks(t *testing.T) {
|
||||
if err != nil || !after.RuntimeCleanupPending || after.RuntimeID != "" || len(fixture.gateway.runtimes) != 0 {
|
||||
t.Fatalf("202 retry was not durable: after=%#v runtimes=%#v err=%v", after, fixture.gateway.runtimes, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
})
|
||||
|
||||
t.Run("clear rollback remains pending and lifecycle retry recovers", func(t *testing.T) {
|
||||
@@ -1994,7 +1991,7 @@ func TestPostgresCleanupPendingTransactionRollbacks(t *testing.T) {
|
||||
if err != nil || !after.RuntimeCleanupPending || after.RuntimeID != "" || len(fixture.gateway.runtimes) != 0 {
|
||||
t.Fatalf("clear rollback was not durably pending: after=%#v runtimes=%#v err=%v", after, fixture.gateway.runtimes, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
|
||||
dropCleanupTransitionFailure(t, ctx, fixture.db)
|
||||
setFixtureAccountStatus(t, fixture.databaseURL, "active")
|
||||
@@ -2024,9 +2021,9 @@ func TestPostgresLegacyCleanupPendingRequiresManualReconcile(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
fixture := newPostgresRebindFixture(t, databaseURL)
|
||||
if _, err := fixture.db.ExecContext(ctx, `
|
||||
UPDATE environment_binding SET runtime_cleanup_pending = true,
|
||||
runtime_cleanup_binding_version = NULL, runtime_cleanup_instance_id = NULL, runtime_cleanup_runtime_id = NULL
|
||||
WHERE id = $1`, fixture.bound.BindingID); err != nil {
|
||||
UPDATE browser_env SET runtime_cleanup_pending = true,
|
||||
runtime_cleanup_binding_version = NULL, runtime_cleanup_runtime_id = NULL
|
||||
WHERE alias = $1`, fixture.bound.Alias); err != nil {
|
||||
t.Fatalf("write legacy pending state: %v", err)
|
||||
}
|
||||
environment, err := fixture.store.GetEnvironmentContext(ctx, fixture.bound.Alias)
|
||||
@@ -2068,7 +2065,7 @@ func TestPostgresCleanupMissingContainerReleasesKnownLease(t *testing.T) {
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID != "" {
|
||||
t.Fatalf("known PostgreSQL lease did not converge: %#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
requests := fixture.gateway.recorded()
|
||||
if len(requests) == 0 || requests[len(requests)-1].method != http.MethodDelete ||
|
||||
requests[len(requests)-1].body["runtime_id"] != "known-container" {
|
||||
@@ -2117,12 +2114,12 @@ func TestPostgresCleanupCallChainsPreserveGeneration(t *testing.T) {
|
||||
if err != nil || !after.RuntimeCleanupPending || after.RuntimeID != "" {
|
||||
t.Fatalf("restore commit-unknown lost pending state: after=%#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
} else {
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID != "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" {
|
||||
t.Fatalf("restore rollback changed the old generation: after=%#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 1)
|
||||
}
|
||||
if len(fixture.gateway.runtimes) != 1 {
|
||||
t.Fatalf("restore cleanup failure touched the container: runtimes=%#v requests=%#v", fixture.gateway.runtimes, fixture.gateway.recorded())
|
||||
@@ -2162,7 +2159,7 @@ func TestPostgresCleanupCallChainsPreserveGeneration(t *testing.T) {
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID == "" || len(runtimes) != 1 || !runtimeMatchesBinding(runtimes[0], after) {
|
||||
t.Fatalf("restore retry ended inconsistently: after=%#v runtimes=%#v err=%v", after, runtimes, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 1)
|
||||
})
|
||||
|
||||
t.Run("create restore "+test.name, func(t *testing.T) {
|
||||
@@ -2196,12 +2193,12 @@ func TestPostgresCleanupCallChainsPreserveGeneration(t *testing.T) {
|
||||
if err != nil || !after.RuntimeCleanupPending || after.RuntimeID != "" {
|
||||
t.Fatalf("create restore commit-unknown lost pending state: after=%#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
} else {
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID != "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" {
|
||||
t.Fatalf("create restore rollback changed the old generation: after=%#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 1)
|
||||
}
|
||||
if len(fixture.gateway.runtimes) != 1 {
|
||||
t.Fatalf("create restore cleanup failure touched the container: runtimes=%#v requests=%#v", fixture.gateway.runtimes, fixture.gateway.recorded())
|
||||
@@ -2237,7 +2234,7 @@ func TestPostgresCleanupCallChainsPreserveGeneration(t *testing.T) {
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID == "" || len(runtimes) != 1 || !runtimeMatchesBinding(runtimes[0], after) {
|
||||
t.Fatalf("create restore retry ended inconsistently: after=%#v runtimes=%#v err=%v", after, runtimes, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 1)
|
||||
})
|
||||
|
||||
t.Run("discard "+test.name, func(t *testing.T) {
|
||||
@@ -2270,12 +2267,12 @@ func TestPostgresCleanupCallChainsPreserveGeneration(t *testing.T) {
|
||||
if err != nil || !after.RuntimeCleanupPending || after.RuntimeID != "" {
|
||||
t.Fatalf("discard commit-unknown lost pending state: after=%#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
} else {
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID != "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" {
|
||||
t.Fatalf("discard rollback changed the old generation: after=%#v err=%v", after, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 1)
|
||||
}
|
||||
if len(fixture.gateway.runtimes) != 1 {
|
||||
t.Fatalf("discard cleanup failure touched the container: runtimes=%#v requests=%#v", fixture.gateway.runtimes, fixture.gateway.recorded())
|
||||
@@ -2310,7 +2307,7 @@ func TestPostgresCleanupCallChainsPreserveGeneration(t *testing.T) {
|
||||
t.Fatalf("discard retry retained a running container: %#v", fixture.gateway.runtimes)
|
||||
}
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 0)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2352,7 +2349,7 @@ func TestPostgresGatewayUnknownDoesNotAffectListAndStillBlocksCreate(t *testing.
|
||||
if err != nil || after.RuntimeCleanupPending || after.RuntimeID != "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" || len(fixture.gateway.runtimes) != 1 {
|
||||
t.Fatalf("browser list changed the generation: after=%#v runtimes=%#v err=%v", after, fixture.gateway.runtimes, err)
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, 1)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, 1)
|
||||
requests := fixture.gateway.recorded()
|
||||
if len(requests) != 1 || requests[0].method != http.MethodGet || requests[0].path != "/v1/browsers" {
|
||||
t.Fatalf("browser list did not perform the expected live gateway status read: %#v", requests)
|
||||
@@ -2495,7 +2492,7 @@ func TestPostgresStrictGatewayValidationBlocksLifecycleUntilRetry(t *testing.T)
|
||||
if test.active {
|
||||
activeCount = 1
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, activeCount)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, activeCount)
|
||||
if test.action != "" {
|
||||
var outcome, reason string
|
||||
if err := fixture.db.QueryRowContext(ctx, `
|
||||
@@ -2531,7 +2528,7 @@ func TestPostgresStrictGatewayValidationBlocksLifecycleUntilRetry(t *testing.T)
|
||||
if test.action == "rebind" {
|
||||
activeAfter = 0
|
||||
}
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM runtime_instance WHERE binding_id = 'account-a' AND released_at IS NULL`, activeAfter)
|
||||
assertControlPlaneDatabaseCount(t, fixture.db, `SELECT count(*) FROM browser_env WHERE alias = 'account-a' AND runtime_id IS NOT NULL`, activeAfter)
|
||||
if test.action != "" {
|
||||
var outcome, reason string
|
||||
if err := fixture.db.QueryRowContext(ctx, `
|
||||
@@ -2648,19 +2645,18 @@ func TestPostgresReconcileFinishedAuditUsesActivatedRuntime(t *testing.T) {
|
||||
t.Fatalf("reconcile failed: %v", err)
|
||||
}
|
||||
after, err := fixture.store.GetEnvironmentContext(context.Background(), "account-a")
|
||||
if err != nil || after.RuntimeInstanceID == "" || after.RuntimeID != "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {
|
||||
if err != nil || after.RuntimeID == "" || after.RuntimeID != "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {
|
||||
t.Fatalf("reconcile did not activate replacement runtime: %#v err=%v", after, err)
|
||||
}
|
||||
var auditedRuntime string
|
||||
var auditedBinding int64
|
||||
if err := fixture.db.QueryRow(`
|
||||
SELECT runtime_instance_id, binding_version FROM audit_event
|
||||
SELECT binding_version FROM audit_event
|
||||
WHERE event_type = 'environment_action_finished' AND action = 'reconcile'
|
||||
ORDER BY id DESC LIMIT 1`).Scan(&auditedRuntime, &auditedBinding); err != nil {
|
||||
ORDER BY id DESC LIMIT 1`).Scan(&auditedBinding); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if auditedRuntime != after.RuntimeInstanceID || auditedBinding != after.BindingVersion {
|
||||
t.Fatalf("finished audit retained stale runtime: runtime=%q binding=%d current=%#v", auditedRuntime, auditedBinding, after)
|
||||
if auditedBinding != after.BindingVersion {
|
||||
t.Fatalf("finished audit retained stale binding: binding=%d current=%#v", auditedBinding, after)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2710,7 +2706,7 @@ func TestPostgresNonRunnableReconcileAuditsRuntimeRelease(t *testing.T) {
|
||||
t.Fatalf("reconcile error=%v, releaseFailure=%v", err, releaseFailure)
|
||||
}
|
||||
after, err := fixture.store.GetEnvironmentContext(ctx, "account-a")
|
||||
if err != nil || (after.RuntimeInstanceID != "") == !releaseFailure {
|
||||
if err != nil || (after.RuntimeID != "") == !releaseFailure {
|
||||
t.Fatalf("runtime lease after reconcile: %#v err=%v", after, err)
|
||||
}
|
||||
|
||||
@@ -2771,7 +2767,7 @@ func TestStartRejectsPausedOrRevokedAccountBeforeGatewayCall(t *testing.T) {
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: test.status,
|
||||
AuthorizationStatus: test.authorization, BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
AuthorizationStatus: test.authorization, BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token"}
|
||||
app := newTestApp(t, store, gateway)
|
||||
@@ -2794,8 +2790,8 @@ func TestReconcileStopsRuntimeForPausedOrRevokedAccount(t *testing.T) {
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "paused", AuthorizationStatus: authorization,
|
||||
BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeInstanceID: "old-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", ProxyReady: true, BindingVersion: 1, NetworkExitID: "exit-1",
|
||||
@@ -2831,7 +2827,7 @@ func TestActivationConflictCleanupIsGenerationSafe(t *testing.T) {
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
environment := hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "paused", AuthorizationStatus: "authorized",
|
||||
BindingID: "account-a", BindingVersion: 2, Exit: store.exits["exit-1"],
|
||||
BindingVersion: 2, Exit: store.exits["exit-1"],
|
||||
}
|
||||
store.bindings[environment.Alias] = environment
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
@@ -2866,7 +2862,7 @@ func TestExplicitStopRejectsStaleBindingBeforeGatewaySideEffect(t *testing.T) {
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "active", AuthorizationStatus: "authorized",
|
||||
BindingID: "account-a", BindingVersion: 2, Exit: store.exits["exit-1"], RuntimeInstanceID: "new-instance", RuntimeID: "new-container",
|
||||
BindingVersion: 2, Exit: store.exits["exit-1"], RuntimeID: "new-container",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "new-container", Alias: "account-a", State: "running", ProxyReady: true, BindingVersion: 2, NetworkExitID: "exit-1",
|
||||
@@ -2875,7 +2871,7 @@ func TestExplicitStopRejectsStaleBindingBeforeGatewaySideEffect(t *testing.T) {
|
||||
defer server.Close()
|
||||
store.gateways["gw-1"] = hub.Gateway{Name: "gw-1", Endpoint: server.URL, Token: gateway.token}
|
||||
stale := store.bindings["account-a"]
|
||||
stale.BindingVersion, stale.RuntimeInstanceID, stale.RuntimeID = 1, "old-instance", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
|
||||
stale.BindingVersion, stale.RuntimeID, stale.RuntimeID = 1, "old-instance", "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
|
||||
|
||||
if err := stopEnvironmentRuntime(context.Background(), store, stale); !errors.Is(err, hub.ErrConflict) {
|
||||
t.Fatalf("stale explicit stop was not rejected: %v", err)
|
||||
@@ -2891,7 +2887,7 @@ func TestReconcileFinishedAuditUsesRebuiltRuntime(t *testing.T) {
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "active", AuthorizationStatus: "authorized",
|
||||
BindingID: "account-a", BindingVersion: 2, Exit: store.exits["exit-2"], RuntimeInstanceID: "old-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
BindingVersion: 2, Exit: store.exits["exit-2"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", ProxyReady: true, BindingVersion: 2, NetworkExitID: "exit-1", NetworkID: "native-66666666666666666666666666666666",
|
||||
@@ -2901,8 +2897,10 @@ func TestReconcileFinishedAuditUsesRebuiltRuntime(t *testing.T) {
|
||||
if err := reconcileRuntimeLeases(context.Background(), store, fakeExitProbe{}, func(hub.NetworkExitAccess) (string, error) { return "", nil }); err != nil {
|
||||
t.Fatalf("reconcile failed: %v", err)
|
||||
}
|
||||
// 真库审计已无 runtime_instance_id,改断言内存 binding 的重建 runtime 代际(fake 网关固定创建 ID)
|
||||
if len(store.actions) != 2 || store.actions[1].Outcome != "succeeded" ||
|
||||
store.actions[1].RuntimeInstanceID != "runtime-instance" || store.actions[1].BindingVersion != 2 || store.actions[1].NetworkExitID != "exit-2" {
|
||||
store.bindings["account-a"].RuntimeID != "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ||
|
||||
store.actions[1].BindingVersion != 2 || store.actions[1].NetworkExitID != "exit-2" {
|
||||
t.Fatalf("finished audit used stale runtime context: %#v", store.actions)
|
||||
}
|
||||
}
|
||||
@@ -2912,7 +2910,7 @@ func TestReconcileContextRefreshFailureClearsAllAuditCorrelation(t *testing.T) {
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", AccountStatus: "active", AuthorizationStatus: "authorized",
|
||||
BindingID: "account-a", BindingVersion: 2, Exit: store.exits["exit-1"], RuntimeInstanceID: "old-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
BindingVersion: 2, Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", ProxyReady: true, BindingVersion: 2, NetworkExitID: "stale-exit", NetworkID: "native-66666666666666666666666666666666",
|
||||
@@ -2926,7 +2924,7 @@ func TestReconcileContextRefreshFailureClearsAllAuditCorrelation(t *testing.T) {
|
||||
t.Fatal("context refresh failure unexpectedly succeeded")
|
||||
}
|
||||
finished := store.actions[len(store.actions)-1]
|
||||
if finished.RuntimeInstanceID != "" || finished.BindingVersion != 0 || finished.NetworkExitID != "" {
|
||||
if finished.BindingVersion != 0 || finished.NetworkExitID != "" {
|
||||
t.Fatalf("failed context refresh retained partial stale correlation: %#v", finished)
|
||||
}
|
||||
}
|
||||
@@ -2945,7 +2943,7 @@ func TestStoppedReconcileReportsRuntimeReleaseFailure(t *testing.T) {
|
||||
defer gatewayServer.Close()
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"], RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}
|
||||
store.releaseErr = errors.New("database unavailable")
|
||||
store.gateways["gw-1"] = hub.Gateway{Name: "gw-1", Endpoint: gatewayServer.URL, Token: "unit-test-gateway-token"}
|
||||
app := fiber.New()
|
||||
@@ -2964,8 +2962,8 @@ func TestReconcileAuditsRuntimeReleaseFailure(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
store.releaseErr = errors.New("database unavailable")
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
@@ -2987,8 +2985,8 @@ func TestRebindRebuildsRunningContainerWithLatestBinding(t *testing.T) {
|
||||
store.exits["exit-2"] = hub.NetworkExit{ID: "exit-2", Protocol: "http", Host: "proxy.example", Port: 8080, HealthStatus: "healthy", Version: 1}
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", ProxyReady: true,
|
||||
@@ -3016,8 +3014,8 @@ func TestSameExitRebindStillRebuildsRunningContainer(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "expired-runtime", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", ProxyReady: true,
|
||||
@@ -3045,8 +3043,8 @@ func TestRuntimeReuseRechecksHealthAndDiscardsFailedExit(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", ProxyReady: true,
|
||||
@@ -3071,8 +3069,8 @@ func TestReconcileDeleteFailureReleasesLeaseAndAuditsUnknown(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 2,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "stale-container", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 2,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "stale-container", RuntimeNetworkID: "native-66666666666666666666666666666666",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", failDelete: 1, runtimes: []runtimeStatus{{
|
||||
ID: "stale-container", Alias: "account-a", State: "running", BindingVersion: 2, NetworkExitID: "stale-exit", NetworkID: "native-66666666666666666666666666666666", ProxyReady: true,
|
||||
@@ -3098,8 +3096,8 @@ func TestDisableExitImmediatelyDiscardsRuntime(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", ProxyReady: true,
|
||||
@@ -3129,7 +3127,7 @@ func TestDisableExitWaitsForInFlightBrowserLifecycle(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"],
|
||||
}
|
||||
gatewayServer := httptest.NewServer(gateway.handler(t))
|
||||
defer gatewayServer.Close()
|
||||
@@ -3206,8 +3204,8 @@ func TestDisableExitPropagatesUnknownGatewayReadAndPreservesLease(t *testing.T)
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
store.gateways["gw-1"] = hub.Gateway{Name: "gw-1", Endpoint: gatewayServer.URL, Token: "unit-test-gateway-token"}
|
||||
app := fiber.New()
|
||||
@@ -3233,8 +3231,8 @@ func TestDirectBindingIsListable(t *testing.T) {
|
||||
Seed: 1, ProxyServer: "http://legacy:secret@proxy.example:8080", DisableNonProxiedUDP: true,
|
||||
}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
RuntimeInstanceID: "4444444444444444444444444444444444444444444444444444444444444444", RuntimeID: "direct-container", RuntimeNetworkID: "direct-network",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
RuntimeID: "direct-container", RuntimeNetworkID: "direct-network",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "direct-container", Alias: "account-a", State: "running", BindingVersion: 1, NetworkID: "direct-network", ProxyReady: true,
|
||||
@@ -3258,13 +3256,13 @@ func TestRebindDeleteFailureKeepsOriginalBinding(t *testing.T) {
|
||||
targetID string
|
||||
}{
|
||||
{name: "running binding", binding: hub.EnvironmentContext{
|
||||
AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: hub.NetworkExit{ID: "exit-1", Protocol: "socks5", Host: "127.0.0.1", Port: 1080, HealthStatus: "healthy"},
|
||||
RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: hub.NetworkExit{ID: "exit-1", Protocol: "socks5", Host: "127.0.0.1", Port: 1080, HealthStatus: "healthy"},
|
||||
RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
}, targetID: "exit-2"},
|
||||
{name: "legacy NULL binding", binding: hub.EnvironmentContext{
|
||||
AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
RuntimeInstanceID: "5555555555555555555555555555555555555555555555555555555555555555", RuntimeID: "legacy-container",
|
||||
AccountID: "account-a", BindingVersion: 1,
|
||||
RuntimeID: "legacy-container",
|
||||
}, targetID: "exit-1"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -3312,8 +3310,8 @@ func TestRebindNetworkCleanupPendingBlocksUntilConfirmed(t *testing.T) {
|
||||
store.exits["exit-2"] = hub.NetworkExit{ID: "exit-2", Protocol: "http", Host: "proxy.example", Port: 8080, HealthStatus: "healthy", Version: 1}
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", cleanupPending: test.cleanupPending,
|
||||
disconnectDelete: test.disconnectDelete, disconnectListAfterDelete: test.disconnectListAfterDelete,
|
||||
@@ -3362,7 +3360,7 @@ func TestCleanupPendingBlocksEveryLifecyclePath(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
RuntimeCleanupPending: true, RuntimeCleanupBindingVersion: 1,
|
||||
RuntimeCleanupRuntimeID: missingRuntimeID, RuntimeCleanupNetworkID: "native-66666666666666666666666666666666", Exit: store.exits["exit-1"],
|
||||
}
|
||||
@@ -3391,8 +3389,7 @@ func TestRebindPreparesRunningRuntimeBeforeDelete(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.exits["exit-2"] = hub.NetworkExit{ID: "exit-2", Protocol: "http", Host: "proxy.example", Port: 8080, HealthStatus: "healthy", Version: 1}
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a",
|
||||
BindingVersion: 1, Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", ProxyReady: true,
|
||||
}}}
|
||||
@@ -3411,8 +3408,7 @@ func TestRebindCandidateUnknownCreateLeavesGenerationPending(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.exits["exit-2"] = hub.NetworkExit{ID: "exit-2", Protocol: "http", Host: "proxy.example", Port: 8080, HealthStatus: "healthy", Version: 1}
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a",
|
||||
BindingVersion: 1, Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"], RuntimeID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", failCreate: 1, runtimes: []runtimeStatus{{
|
||||
ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1", ProxyReady: true,
|
||||
}}}
|
||||
@@ -3450,8 +3446,8 @@ func TestExistingEnvironmentCleanupNeverReturnsReusedSuccess(t *testing.T) {
|
||||
}
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "店铺一号", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 2024, Platform: "windows", Timezone: "Asia/Shanghai"}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeInstanceID: "runtime-instance", RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1,
|
||||
Exit: store.exits["exit-1"], RuntimeID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{
|
||||
ID: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Alias: "account-a", State: "running", BindingVersion: 1, NetworkExitID: "exit-1",
|
||||
@@ -3479,7 +3475,7 @@ func TestStartRebuildsStoppedContainerAfterRebind(t *testing.T) {
|
||||
store := newMemoryStore()
|
||||
store.exits["exit-2"] = hub.NetworkExit{ID: "exit-2", Protocol: "http", Host: "proxy-2.example", Port: 8080, HealthStatus: "healthy", Version: 1}
|
||||
store.envs["account-a"] = hub.Env{Alias: "account-a", Name: "甲", Gateway: "gw-1", Fingerprint: hub.Fingerprint{Seed: 1}}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"]}
|
||||
store.bindings["account-a"] = hub.EnvironmentContext{Env: store.envs["account-a"], AccountID: "account-a", BindingVersion: 1, Exit: store.exits["exit-1"]}
|
||||
gateway := &fakeGateway{token: "unit-test-gateway-token", runtimes: []runtimeStatus{{ID: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", Alias: "account-a", State: "exited", BindingVersion: 1}}}
|
||||
app := newTestApp(t, store, gateway)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user