Files
go-sip/internal/dispatcher/agent_inbound_session_test.go
T

69 lines
2.9 KiB
Go

package dispatcher
import (
"errors"
"testing"
"time"
agentpb "git.ipao.vip/rogee/go-sip/gen/agent"
"git.ipao.vip/rogee/go-sip/internal/session"
"git.ipao.vip/rogee/go-sip/internal/store"
"google.golang.org/protobuf/proto"
)
type inboundSessionTestClient struct {
agentpb.AgentControlServiceClient
}
func TestInboundAgentFactRequiresCurrentUnexpiredActivatedSession(t *testing.T) {
now := time.Date(2026, 9, 21, 2, 0, 0, 0, time.UTC)
coordinator := NewAgentCoordinator(func() time.Time { return now })
if err := coordinator.Register("agent-a", &inboundSessionTestClient{}); err != nil {
t.Fatal(err)
}
coordinator.sessions["agent-a"] = AgentSession{
AgentID: "agent-a", CellID: "cell-a", BootID: "boot-a", DispatcherEpoch: "epoch-a",
SessionGeneration: 3, ExpiresAtUnixMs: now.Add(time.Minute).UnixMilli(),
}
meta := &agentpb.RequestMeta{
ProtocolVersion: "agent.v1", AgentId: "agent-a", CellId: "cell-a", BootId: "boot-a",
DispatcherEpoch: "epoch-a", SessionGeneration: 3,
}
if err := coordinator.AuthorizeInboundMeta(meta); err != nil {
t.Fatalf("active Agent was refused: %v", err)
}
for _, tc := range []struct {
name string
change func(*agentpb.RequestMeta)
transition bool
}{
{"old boot", func(m *agentpb.RequestMeta) { m.BootId = "boot-old" }, false},
{"old generation", func(m *agentpb.RequestMeta) { m.SessionGeneration = 2 }, true},
{"next generation before activation response", func(m *agentpb.RequestMeta) { m.SessionGeneration = 4 }, true},
{"distant generation", func(m *agentpb.RequestMeta) { m.SessionGeneration = 7 }, false},
{"missing generation", func(m *agentpb.RequestMeta) { m.SessionGeneration = 0 }, false},
{"other cell", func(m *agentpb.RequestMeta) { m.CellId = "cell-other" }, false},
{"other epoch", func(m *agentpb.RequestMeta) { m.DispatcherEpoch = "epoch-other" }, false},
{"unregistered Agent", func(m *agentpb.RequestMeta) { m.AgentId = "agent-other" }, false},
{"old boot and generation", func(m *agentpb.RequestMeta) { m.BootId = "boot-old"; m.SessionGeneration = 2 }, false},
} {
t.Run(tc.name, func(t *testing.T) {
changed := proto.Clone(meta).(*agentpb.RequestMeta)
tc.change(changed)
err := coordinator.AuthorizeInboundMeta(changed)
if !errors.Is(err, store.ErrCommandConflict) || errors.Is(err, session.ErrGenerationTransition) != tc.transition {
t.Fatalf("Agent report refusal classification: got %v, transition=%t", err, tc.transition)
}
})
}
now = now.Add(time.Minute)
if err := coordinator.AuthorizeInboundMeta(meta); !errors.Is(err, store.ErrCommandConflict) {
t.Fatalf("expired Agent report passed: %v", err)
}
stale := proto.Clone(meta).(*agentpb.RequestMeta)
stale.SessionGeneration = 2
if err := coordinator.AuthorizeInboundMeta(stale); errors.Is(err, session.ErrGenerationTransition) {
t.Fatalf("expired Agent session misclassified as a transient cutover: %v", err)
}
}