notify/transport_conn_test.go

213 lines
6.8 KiB
Go
Raw Normal View History

package notify
import (
"context"
"errors"
"math"
"net"
"testing"
"time"
"b612.me/stario"
)
func TestClientConnCurrentTransportConnStreamSnapshot(t *testing.T) {
server := NewServer().(*ServerCommon)
left, right := net.Pipe()
defer left.Close()
defer right.Close()
logical := server.bootstrapAcceptedLogical("transport-stream", nil, left)
if logical == nil {
t.Fatal("bootstrapAcceptedLogical should return logical")
}
transport := logical.CurrentTransportConn()
if transport == nil {
t.Fatal("CurrentTransportConn should expose active stream transport")
}
if transport.LogicalConn() != logical {
t.Fatal("LogicalConn mismatch")
}
if !transport.Attached() {
t.Fatal("Attached mismatch: got false want true")
}
if !transport.HasRuntimeConn() {
t.Fatal("HasRuntimeConn mismatch: got false want true")
}
if !transport.UsesStreamTransport() {
t.Fatal("UsesStreamTransport mismatch: got false want true")
}
if !transport.IsCurrent() {
t.Fatal("IsCurrent mismatch: got false want true")
}
snapshot, err := GetTransportConnRuntimeSnapshot(transport)
if err != nil {
t.Fatalf("GetTransportConnRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.ClientID, logical.ClientID; got != want {
t.Fatalf("ClientID mismatch: got %q want %q", got, want)
}
if !snapshot.Attached || !snapshot.HasRuntimeConn || !snapshot.Current {
t.Fatalf("unexpected transport snapshot: %+v", snapshot)
}
if got, want := snapshot.BindingOwner, "server-transport"; got != want {
t.Fatalf("BindingOwner mismatch: got %q want %q", got, want)
}
if !snapshot.BindingCurrent || !snapshot.LogicalAlive {
t.Fatalf("binding state mismatch: %+v", snapshot)
}
}
func TestClientConnCurrentTransportConnPacketSnapshot(t *testing.T) {
server := NewServer().(*ServerCommon)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
udpListener, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0})
if err != nil {
t.Fatalf("ListenUDP failed: %v", err)
}
defer udpListener.Close()
server.setServerSessionRuntime(&serverSessionRuntime{
stopCtx: stopCtx,
stopFn: stopFn,
udpListener: udpListener,
})
addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:34567")
if err != nil {
t.Fatalf("ResolveUDPAddr failed: %v", err)
}
logical := server.bootstrapAcceptedLogical("transport-packet", addr, nil)
if logical == nil {
t.Fatal("bootstrapAcceptedLogical should return packet logical")
}
transport := logical.CurrentTransportConn()
if transport == nil {
t.Fatal("CurrentTransportConn should expose packet transport route")
}
if got, want := transport.RemoteAddr().String(), addr.String(); got != want {
t.Fatalf("RemoteAddr mismatch: got %q want %q", got, want)
}
if !transport.Attached() {
t.Fatal("Attached mismatch: got false want true")
}
if transport.HasRuntimeConn() {
t.Fatal("packet transport should not expose runtime conn")
}
if transport.TransportGeneration() != 0 {
t.Fatalf("packet transport generation mismatch: got %d want 0", transport.TransportGeneration())
}
}
func TestTransportConnSendRejectsStaleGenerationAfterReattach(t *testing.T) {
server := NewServer().(*ServerCommon)
UseLegacySecurityServer(server)
runtimeCtx, runtimeCancel := context.WithCancel(context.Background())
defer runtimeCancel()
queue := stario.NewQueueCtx(runtimeCtx, 4, math.MaxUint32)
server.setServerSessionRuntime(&serverSessionRuntime{
stopCtx: runtimeCtx,
stopFn: runtimeCancel,
queue: queue,
})
server.markSessionStarted()
defer server.markSessionStopped("test done", nil)
firstLeft, firstRight := net.Pipe()
defer firstRight.Close()
logical, _, _ := newRegisteredServerLogicalForTest(t, server, "transport-send-stale", firstLeft, runtimeCtx, runtimeCancel)
logical.applyClientConnAttachmentProfile(0, 100*time.Millisecond, server.defaultMsgEn, server.defaultMsgDe, server.handshakeRsaKey, server.SecretKey)
firstTransport := logical.CurrentTransportConn()
if firstTransport == nil {
t.Fatal("first transport snapshot should exist")
}
secondLeft, secondRight := net.Pipe()
defer secondRight.Close()
if err := logical.attachClientConnSessionTransport(secondLeft); err != nil {
t.Fatalf("attachClientConnSessionTransport failed: %v", err)
}
secondTransport := logical.CurrentTransportConn()
if secondTransport == nil {
t.Fatal("second transport snapshot should exist after reattach")
}
if firstTransport.IsCurrent() {
t.Fatal("first transport should become stale after reattach")
}
if err := firstTransport.Send("stale", MsgVal("payload")); !errors.Is(err, errTransportDetached) {
t.Fatalf("stale transport send error = %v, want errors.Is(..., %v)", err, errTransportDetached)
}
recvCh := make(chan []byte, 1)
errCh := make(chan error, 1)
go func() {
_ = secondRight.SetReadDeadline(time.Now().Add(time.Second))
reader := stario.NewFrameReader(secondRight, nil)
payload, err := reader.Next()
if err != nil {
errCh <- err
return
}
recvCh <- payload
}()
if err := secondTransport.Send("fresh", MsgVal("payload")); err != nil {
t.Fatalf("fresh transport send failed: %v", err)
}
select {
case err := <-errCh:
t.Fatalf("fresh transport read failed: %v", err)
case got := <-recvCh:
if len(got) == 0 {
t.Fatal("fresh transport should produce framed payload")
}
case <-time.After(time.Second):
t.Fatal("fresh transport send timed out")
}
}
func TestTransportConnRuntimeSnapshotIncludesDetachDiagnostics(t *testing.T) {
server := NewServer().(*ServerCommon)
left, right := net.Pipe()
defer right.Close()
logical := server.bootstrapAcceptedLogical("transport-detach", nil, left)
if logical == nil {
t.Fatal("bootstrapAcceptedLogical should return logical")
}
transport := logical.CurrentTransportConn()
if transport == nil {
t.Fatal("CurrentTransportConn should return active transport")
}
server.detachLogicalSessionTransport(logical, "read error", errors.New("boom"))
snapshot, err := GetTransportConnRuntimeSnapshot(transport)
if err != nil {
t.Fatalf("GetTransportConnRuntimeSnapshot failed: %v", err)
}
if snapshot.Current {
t.Fatalf("snapshot Current should be false after detach: %+v", snapshot)
}
if snapshot.BindingCurrent {
t.Fatalf("snapshot BindingCurrent should be false after detach: %+v", snapshot)
}
if got, want := snapshot.LogicalReason, ""; got != want {
t.Fatalf("snapshot LogicalReason = %q, want %q", got, want)
}
if got, want := snapshot.TransportDetachReason, "read error"; got != want {
t.Fatalf("snapshot TransportDetachReason = %q, want %q", got, want)
}
if got, want := snapshot.TransportDetachKind, clientConnTransportDetachKindReadError; got != want {
t.Fatalf("snapshot TransportDetachKind = %q, want %q", got, want)
}
if got, want := snapshot.TransportDetachError, "boom"; got != want {
t.Fatalf("snapshot TransportDetachError = %q, want %q", got, want)
}
}