Files
DDI/server/internal/agenthub/hub_test.go
T
beug.k@beugsiud.deandClaude Opus 5.5 00b9ffb65b feat(server): operating modes, push deployments, rollback, diff, pending changes and SSE
- PATCH /agents/{id} switches the mode and reconnects the agent
- POST /revisions/{n}/deploy creates pending push deployments, sends
  ApplyRevisionCommand with the deployment ID, re-sends open pushes on
  connect and announces them in GetDesiredState; reports with the ID
  complete the deployment
- POST /revisions/{n}/rollback re-renders the stored generator input
  with the next revision number
- GET /revisions/{n}/diff and GET /config/pending with unified diffs
- GET /events streams agent, deployment, revision and pending events

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 20:23:47 +02:00

94 lines
2.3 KiB
Go

// SPDX-License-Identifier: LicenseRef-DDI-Proprietary
package agenthub
import (
"testing"
"git.beugsiud.de/beug.k/DDI/internal/agentpki"
)
func TestHub(t *testing.T) {
h := New()
a := h.Attach("a", "dns", ModeAutoPull)
b := h.Attach("b", "dhcp", ModeManual)
if !h.Connected("a") || !h.Connected("b") || h.Connected("c") {
t.Fatal("connected state")
}
if c := h.Count(); c["dns"] != 1 || c["dhcp"] != 1 {
t.Errorf("count %v", c)
}
if n := h.NotifyRevision(7); n != 1 {
t.Errorf("notified %d", n)
}
cmd := <-a.Commands()
if cmd.GetApplyRevision().GetRevision() != 7 || !agentpki.ValidAgentID(cmd.GetCommandId()) ||
!agentpki.ValidAgentID(cmd.GetApplyRevision().GetDeploymentId()) {
t.Errorf("command %v", cmd)
}
select {
case <-b.Commands():
t.Error("manual agent notified")
default:
}
// A full queue drops commands instead of blocking.
for range queueSize + 3 {
h.NotifyRevision(8)
}
if len(a.cmds) != queueSize {
t.Errorf("queue length %d", len(a.cmds))
}
// A newer stream replaces the old one.
a2 := h.Attach("a", "dns", ModeAutoPull)
if a.Reason() == "" {
t.Error("old stream not closed")
}
h.Detach(a) // stale detach must not remove the new stream
if !h.Connected("a") {
t.Error("stale detach removed the new stream")
}
h.Disconnect("a", "revoked")
if a2.Reason() != "revoked" || h.Connected("a") {
t.Errorf("disconnect: %q", a2.Reason())
}
h.Detach(b)
if h.Connected("b") || len(h.Count()) != 0 {
t.Error("detach")
}
h.Disconnect("unknown", "x") // no-op
}
func TestSend(t *testing.T) {
h := New()
if h.Send("m", ApplyCommand(3, "12")) {
t.Error("sent to an agent without stream")
}
m := h.Attach("m", "dns", ModeManual)
if !h.Send("m", ApplyCommand(3, "12")) {
t.Fatal("not sent")
}
cmd := <-m.Commands()
if cmd.GetApplyRevision().GetRevision() != 3 || cmd.GetApplyRevision().GetDeploymentId() != "12" ||
!agentpki.ValidAgentID(cmd.GetCommandId()) {
t.Errorf("command %v", cmd)
}
for range queueSize {
h.Send("m", ApplyCommand(4, "13"))
}
if h.Send("m", ApplyCommand(5, "14")) {
t.Error("sent to a full queue")
}
// Only streams in auto_pull mode get new revisions.
x := h.Attach("x", "dhcp", ModeAutoPull)
h.SetMode("x", ModeManual)
h.SetMode("unknown", ModeManual) // no-op
if n := h.NotifyRevision(9); n != 0 || len(x.Commands()) != 0 {
t.Errorf("manual stream notified: %d", n)
}
}