package router import ( "context" "testing" "time" ) func TestMemoryDirectorySameOwnerRenewalPreservesLeaseToken(t *testing.T) { ctx := context.Background() directory := NewMemoryDirectory() now := time.Unix(100, 0).UTC() first, err := directory.EnsureOwner(ctx, "room-1", "node-a", now, 10*time.Second) if err != nil { t.Fatalf("first EnsureOwner failed: %v", err) } renewed, err := directory.EnsureOwner(ctx, "room-1", "node-a", now.Add(time.Second), 10*time.Second) if err != nil { t.Fatalf("renew EnsureOwner failed: %v", err) } if renewed.LeaseToken != first.LeaseToken { // 同节点续租不能换 token,否则 Room Cell 命令进入 mailbox 后会被后台续租误伤。 t.Fatalf("same owner renewal rotated token: first=%s renewed=%s", first.LeaseToken, renewed.LeaseToken) } if !renewed.ExpiresAt.After(first.ExpiresAt) { t.Fatalf("same owner renewal did not extend expiry: first=%s renewed=%s", first.ExpiresAt, renewed.ExpiresAt) } ok, err := directory.VerifyOwner(ctx, "room-1", "node-a", first.LeaseToken, now.Add(2*time.Second)) if err != nil { t.Fatalf("VerifyOwner failed: %v", err) } if !ok { t.Fatal("original token should remain valid after same owner renewal") } } func TestMemoryDirectoryExpiredLeaseCreatesNewToken(t *testing.T) { ctx := context.Background() directory := NewMemoryDirectory() now := time.Unix(100, 0).UTC() first, err := directory.EnsureOwner(ctx, "room-1", "node-a", now, time.Second) if err != nil { t.Fatalf("first EnsureOwner failed: %v", err) } taken, err := directory.EnsureOwner(ctx, "room-1", "node-b", now.Add(2*time.Second), 10*time.Second) if err != nil { t.Fatalf("takeover EnsureOwner failed: %v", err) } if taken.NodeID != "node-b" { t.Fatalf("expired lease should be taken by node-b, got %+v", taken) } if taken.LeaseToken == first.LeaseToken { // 过期接管代表新的执行权实例,必须换 token 来挡住旧 owner 的迟到提交。 t.Fatal("expired lease takeover must create a new token") } }