Files
zeekayandHanzo Dev 78ab4f2f83 Declare operations on the group that serves them, and build on Go 1.27
zip's registration is a verb method on the group, so a route that is not a typed
operation says which method it answers with. The security package's own
two-method router goes with it: it existed so both the app and a sub-router could
satisfy one name, and restating a routing surface is what let the two disagree —
the methods it named no longer exist. The app spells itself as a group, which
registers at exactly the paths it did.

The toolchain and the pin move together, because below zip v1.36.50 the JSON
encoder was selected on a build tag: a repo whose go directive rises first writes
a wire that is neither the old release's nor the new one's until the pin catches
up.

metrics_test.go still does not compile, before and after: it compares a metric
registry against a gatherer from a different metrics library, so the two Gather
signatures disagree. That is its own change.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 09:58:39 -07:00

68 lines
2.0 KiB
Go

package client
import (
"context"
"net"
"os"
"path/filepath"
"testing"
"time"
"github.com/zap-proto/zip"
)
// TestPerformZAPCheck drives a REAL zip peer over a real unix socket. The two
// cases pin the probe in both directions, so neither a stuck `true` nor a
// blanket `false` on error survives: a peer that is there answers even though
// it serves no probeOp, and an address with nothing behind it does not.
func TestPerformZAPCheck(t *testing.T) {
dir, err := os.MkdirTemp("", "zp")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = os.RemoveAll(dir) })
sock := filepath.Join(dir, "peer.sock")
// A peer serving ONE op, deliberately not probeOp — the shape every real
// peer has, since nothing in the fleet implements status.probe.
app := zip.New(zip.Config{})
app.Post("/v1/noop", func(_ context.Context, _ *struct{}) (*struct{}, error) {
return nil, nil
}, zip.WithOperationID("noop"))
go func() { _ = app.Listen(sock) }()
t.Cleanup(func() { _ = app.Shutdown() })
for i := 0; ; i++ {
if c, derr := net.Dial("unix", sock); derr == nil {
_ = c.Close()
break
}
if i == 100 {
t.Fatalf("%s never began listening", sock)
}
time.Sleep(20 * time.Millisecond)
}
// A REFUSAL IS AN ANSWER: this peer has no status.probe, so it refuses —
// and the refusal completed a round trip, which is what reachable means.
connected, status, err, d := PerformZAPCheck("zap://"+sock, GetDefaultConfig())
if !connected {
t.Fatalf("a live peer refusing an unknown op must read reachable; got err=%v", err)
}
if status != "SERVING" || err != nil {
t.Fatalf("status=%q err=%v", status, err)
}
if d <= 0 {
t.Fatal("a completed round trip must report a duration")
}
// Nothing behind the address: no round trip, so no evidence, so not connected.
connected, _, err, _ = PerformZAPCheck("zap://"+filepath.Join(dir, "absent.sock"), GetDefaultConfig())
if connected {
t.Fatal("an address with no peer must not read reachable")
}
if err == nil {
t.Fatal("an unreachable peer must report why")
}
}