notify/session_runtime_snapshot_test.go

583 lines
23 KiB
Go
Raw Normal View History

package notify
import (
"b612.me/stario"
"context"
"errors"
"math"
"net"
"testing"
"time"
)
func TestGetClientRuntimeSnapshotDefaults(t *testing.T) {
client := NewClient()
snapshot, err := GetClientRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.OwnerState, "idle"; got != want {
t.Fatalf("OwnerState mismatch: got %q want %q", got, want)
}
if snapshot.Alive {
t.Fatalf("Alive mismatch: got %v want false", snapshot.Alive)
}
if snapshot.SessionEpoch != 0 {
t.Fatalf("SessionEpoch mismatch: got %d want 0", snapshot.SessionEpoch)
}
if snapshot.TransportAttached {
t.Fatalf("TransportAttached mismatch: got %v want false", snapshot.TransportAttached)
}
if snapshot.HasRuntimeQueue {
t.Fatalf("HasRuntimeQueue mismatch: got %v want false", snapshot.HasRuntimeQueue)
}
if !snapshot.HasRuntimeStopCtx {
t.Fatalf("HasRuntimeStopCtx mismatch: got %v want true", snapshot.HasRuntimeStopCtx)
}
if snapshot.ConnectSource != "" || snapshot.ConnectNetwork != "" || snapshot.ConnectAddress != "" || snapshot.CanReconnect {
t.Fatalf("unexpected default connect source snapshot: %+v", snapshot)
}
if snapshot.Retry != (ConnectionRetrySnapshot{}) {
t.Fatalf("Retry snapshot mismatch: %+v", snapshot.Retry)
}
}
func TestGetServerRuntimeSnapshotDefaults(t *testing.T) {
server := NewServer()
snapshot, err := GetServerRuntimeSnapshot(server)
if err != nil {
t.Fatalf("GetServerRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.OwnerState, "idle"; got != want {
t.Fatalf("OwnerState mismatch: got %q want %q", got, want)
}
if snapshot.Alive {
t.Fatalf("Alive mismatch: got %v want false", snapshot.Alive)
}
if snapshot.ClientCount != 0 {
t.Fatalf("ClientCount mismatch: got %d want 0", snapshot.ClientCount)
}
if snapshot.DetachedClientCount != 0 {
t.Fatalf("DetachedClientCount mismatch: got %d want 0", snapshot.DetachedClientCount)
}
if snapshot.DetachedReattachableClientCount != 0 {
t.Fatalf("DetachedReattachableClientCount mismatch: got %d want 0", snapshot.DetachedReattachableClientCount)
}
if snapshot.DetachedExpiredClientCount != 0 {
t.Fatalf("DetachedExpiredClientCount mismatch: got %d want 0", snapshot.DetachedExpiredClientCount)
}
if snapshot.DetachedClientKeepSec != 0 {
t.Fatalf("DetachedClientKeepSec mismatch: got %d want 0", snapshot.DetachedClientKeepSec)
}
if snapshot.TransportAttached {
t.Fatalf("TransportAttached mismatch: got %v want false", snapshot.TransportAttached)
}
if snapshot.HasRuntimeQueue {
t.Fatalf("HasRuntimeQueue mismatch: got %v want false", snapshot.HasRuntimeQueue)
}
if !snapshot.HasRuntimeStopCtx {
t.Fatalf("HasRuntimeStopCtx mismatch: got %v want true", snapshot.HasRuntimeStopCtx)
}
if snapshot.Retry != (ConnectionRetrySnapshot{}) {
t.Fatalf("Retry snapshot mismatch: %+v", snapshot.Retry)
}
}
func TestGetRuntimeSnapshotRejectsNil(t *testing.T) {
if _, err := GetClientRuntimeSnapshot(nil); !errors.Is(err, errClientRuntimeSnapshotNil) {
t.Fatalf("GetClientRuntimeSnapshot nil error = %v, want %v", err, errClientRuntimeSnapshotNil)
}
if _, err := GetServerRuntimeSnapshot(nil); !errors.Is(err, errServerRuntimeSnapshotNil) {
t.Fatalf("GetServerRuntimeSnapshot nil error = %v, want %v", err, errServerRuntimeSnapshotNil)
}
if _, err := GetClientConnRuntimeSnapshot(nil); !errors.Is(err, errClientConnRuntimeSnapshotNil) {
t.Fatalf("GetClientConnRuntimeSnapshot nil error = %v, want %v", err, errClientConnRuntimeSnapshotNil)
}
if _, err := GetServerDetachedClientRuntimeSnapshots(nil); !errors.Is(err, errServerDetachedClientRuntimeSnapshotNil) {
t.Fatalf("GetServerDetachedClientRuntimeSnapshots nil error = %v, want %v", err, errServerDetachedClientRuntimeSnapshotNil)
}
}
func TestGetRuntimeSnapshotExposesDetachedTransport(t *testing.T) {
client := NewClient().(*ClientCommon)
clientStopCtx, clientStopFn := context.WithCancel(context.Background())
defer clientStopFn()
clientQueue := stario.NewQueueCtx(clientStopCtx, 4, math.MaxUint32)
clientConnLeft, clientConnRight := net.Pipe()
defer clientConnLeft.Close()
defer clientConnRight.Close()
client.setClientSessionRuntime(&clientSessionRuntime{
conn: clientConnLeft,
stopCtx: clientStopCtx,
stopFn: clientStopFn,
queue: clientQueue,
epoch: 1,
})
client.markSessionStarted()
client.clearClientSessionRuntimeTransport()
clientSnapshot, err := GetClientRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientRuntimeSnapshot failed: %v", err)
}
if clientSnapshot.TransportAttached {
t.Fatalf("client TransportAttached mismatch: got %v want false", clientSnapshot.TransportAttached)
}
if clientSnapshot.HasRuntimeConn {
t.Fatalf("client HasRuntimeConn mismatch: got %v want false", clientSnapshot.HasRuntimeConn)
}
if !clientSnapshot.HasRuntimeQueue {
t.Fatalf("client HasRuntimeQueue mismatch: got %v want true", clientSnapshot.HasRuntimeQueue)
}
if !clientSnapshot.HasRuntimeStopCtx {
t.Fatalf("client HasRuntimeStopCtx mismatch: got %v want true", clientSnapshot.HasRuntimeStopCtx)
}
server := NewServer().(*ServerCommon)
server.markSessionStarted()
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
queue := stario.NewQueueCtx(stopCtx, 4, math.MaxUint32)
server.setServerSessionRuntime(&serverSessionRuntime{
stopCtx: stopCtx,
stopFn: stopFn,
queue: queue,
listener: &stubListener{},
})
server.clearServerSessionRuntimeTransport()
serverSnapshot, err := GetServerRuntimeSnapshot(server)
if err != nil {
t.Fatalf("GetServerRuntimeSnapshot failed: %v", err)
}
if serverSnapshot.TransportAttached {
t.Fatalf("server TransportAttached mismatch: got %v want false", serverSnapshot.TransportAttached)
}
if serverSnapshot.HasRuntimeListener || serverSnapshot.HasRuntimeUDPListener {
t.Fatalf("server runtime listener flags mismatch: %+v", serverSnapshot)
}
if !serverSnapshot.HasRuntimeQueue {
t.Fatalf("server HasRuntimeQueue mismatch: got %v want true", serverSnapshot.HasRuntimeQueue)
}
if !serverSnapshot.HasRuntimeStopCtx {
t.Fatalf("server HasRuntimeStopCtx mismatch: got %v want true", serverSnapshot.HasRuntimeStopCtx)
}
}
func TestGetServerRuntimeSnapshotCountsDetachedBoundPeers(t *testing.T) {
server := NewServer().(*ServerCommon)
server.SetDetachedClientKeepSec(15)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
queue := stario.NewQueueCtx(stopCtx, 4, math.MaxUint32)
server.setServerSessionRuntime(&serverSessionRuntime{
stopCtx: stopCtx,
stopFn: stopFn,
queue: queue,
})
server.markSessionStarted()
boundAttachedLeft, boundAttachedRight := net.Pipe()
defer boundAttachedRight.Close()
boundAttached, _, _ := newRegisteredServerClientForTest(t, server, "bound-attached", boundAttachedLeft, stopCtx, stopFn)
boundAttached.markClientConnIdentityBound()
boundAttached.markClientConnStreamTransport()
boundDetachedLeft, boundDetachedRight := net.Pipe()
defer boundDetachedRight.Close()
boundDetached, _, _ := newRegisteredServerClientForTest(t, server, "bound-detached", boundDetachedLeft, stopCtx, stopFn)
boundDetached.markClientConnIdentityBound()
boundDetached.markClientConnStreamTransport()
boundDetached.markClientConnTransportDetached("read error", errors.New("boom"))
boundDetached.clearClientConnSessionRuntimeTransport()
unboundDetachedLeft, unboundDetachedRight := net.Pipe()
defer unboundDetachedRight.Close()
unboundDetached, _, _ := newRegisteredServerClientForTest(t, server, "unbound-detached", unboundDetachedLeft, stopCtx, stopFn)
unboundDetached.markClientConnStreamTransport()
unboundDetached.markClientConnTransportDetached("read error", errors.New("boom"))
unboundDetached.clearClientConnSessionRuntimeTransport()
snapshot, err := GetServerRuntimeSnapshot(server)
if err != nil {
t.Fatalf("GetServerRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.ClientCount, 3; got != want {
t.Fatalf("ClientCount mismatch: got %d want %d", got, want)
}
if got, want := snapshot.DetachedClientCount, 1; got != want {
t.Fatalf("DetachedClientCount mismatch: got %d want %d", got, want)
}
if got, want := snapshot.DetachedReattachableClientCount, 1; got != want {
t.Fatalf("DetachedReattachableClientCount mismatch: got %d want %d", got, want)
}
if got, want := snapshot.DetachedExpiredClientCount, 0; got != want {
t.Fatalf("DetachedExpiredClientCount mismatch: got %d want %d", got, want)
}
if got, want := snapshot.DetachedClientKeepSec, int64(15); got != want {
t.Fatalf("DetachedClientKeepSec mismatch: got %d want %d", got, want)
}
}
func TestGetClientConnRuntimeSnapshotExposesDetachState(t *testing.T) {
server := NewServer().(*ServerCommon)
server.SetDetachedClientKeepSec(15)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
left, right := net.Pipe()
defer right.Close()
client, _, _ := newRegisteredServerClientForTest(t, server, "peer-runtime", left, stopCtx, stopFn)
client.markClientConnIdentityBound()
client.markClientConnStreamTransport()
client.setClientConnLastHeartbeatUnix(time.Now().Unix())
client.markClientConnTransportDetached("read error", errors.New("boom"))
client.clearClientConnSessionRuntimeTransport()
snapshot, err := GetClientConnRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientConnRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.ClientID, "peer-runtime"; got != want {
t.Fatalf("ClientID mismatch: got %q want %q", got, want)
}
if !snapshot.Alive {
t.Fatalf("Alive mismatch: got %v want true", snapshot.Alive)
}
if !snapshot.IdentityBound {
t.Fatal("IdentityBound mismatch: got false want true")
}
if !snapshot.UsesStreamTransport {
t.Fatal("UsesStreamTransport mismatch: got false want true")
}
if snapshot.TransportAttached {
t.Fatalf("TransportAttached mismatch: got %v want false", snapshot.TransportAttached)
}
if snapshot.HasRuntimeConn {
t.Fatalf("HasRuntimeConn mismatch: got %v want false", snapshot.HasRuntimeConn)
}
if got, want := snapshot.TransportGeneration, uint64(1); got != want {
t.Fatalf("TransportGeneration mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportDetachReason, "read error"; got != want {
t.Fatalf("TransportDetachReason mismatch: got %q want %q", got, want)
}
if got, want := snapshot.TransportDetachKind, clientConnTransportDetachKindReadError; got != want {
t.Fatalf("TransportDetachKind mismatch: got %q want %q", got, want)
}
if got, want := snapshot.TransportDetachGeneration, uint64(1); got != want {
t.Fatalf("TransportDetachGeneration mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportDetachError, "boom"; got != want {
t.Fatalf("TransportDetachError mismatch: got %q want %q", got, want)
}
if got, want := snapshot.TransportAttachCount, uint64(1); got != want {
t.Fatalf("TransportAttachCount mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportDetachCount, uint64(1); got != want {
t.Fatalf("TransportDetachCount mismatch: got %d want %d", got, want)
}
if snapshot.LastTransportAttachAt.IsZero() {
t.Fatal("LastTransportAttachAt should be recorded")
}
if got, want := snapshot.DetachedClientKeepSec, int64(15); got != want {
t.Fatalf("DetachedClientKeepSec mismatch: got %d want %d", got, want)
}
if snapshot.TransportDetachedAt.IsZero() {
t.Fatal("TransportDetachedAt should be recorded")
}
if !snapshot.TransportDetachHasExpiry {
t.Fatal("TransportDetachHasExpiry mismatch: got false want true")
}
if got, want := snapshot.TransportDetachExpiry, snapshot.TransportDetachedAt.Add(15*time.Second); !got.Equal(want) {
t.Fatalf("TransportDetachExpiry mismatch: got %v want %v", got, want)
}
if snapshot.TransportDetachExpired {
t.Fatal("TransportDetachExpired mismatch: got true want false")
}
if snapshot.TransportDetachRemaining <= 0 || snapshot.TransportDetachRemaining > 15*time.Second {
t.Fatalf("TransportDetachRemaining mismatch: got %v want within (0,15s]", snapshot.TransportDetachRemaining)
}
if !snapshot.ReattachEligible {
t.Fatal("ReattachEligible mismatch: got false want true")
}
if snapshot.LastHeartbeatAt.IsZero() {
t.Fatal("LastHeartbeatAt should be recorded")
}
}
func TestGetServerDetachedClientRuntimeSnapshotsFiltersAndSorts(t *testing.T) {
server := NewServer().(*ServerCommon)
server.SetDetachedClientKeepSec(12)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
queue := stario.NewQueueCtx(stopCtx, 4, math.MaxUint32)
server.setServerSessionRuntime(&serverSessionRuntime{
stopCtx: stopCtx,
stopFn: stopFn,
queue: queue,
})
server.markSessionStarted()
detachedBLeft, detachedBRight := net.Pipe()
defer detachedBRight.Close()
detachedB, _, _ := newRegisteredServerClientForTest(t, server, "peer-b", detachedBLeft, stopCtx, stopFn)
detachedB.markClientConnIdentityBound()
detachedB.markClientConnStreamTransport()
detachedB.markClientConnTransportDetached("read error", errors.New("boom-b"))
detachedB.clearClientConnSessionRuntimeTransport()
detachedALeft, detachedARight := net.Pipe()
defer detachedARight.Close()
detachedA, _, _ := newRegisteredServerClientForTest(t, server, "peer-a", detachedALeft, stopCtx, stopFn)
detachedA.markClientConnIdentityBound()
detachedA.markClientConnStreamTransport()
detachedA.markClientConnTransportDetached("heartbeat timeout", nil)
detachedA.clearClientConnSessionRuntimeTransport()
attachedLeft, attachedRight := net.Pipe()
defer attachedRight.Close()
attached, _, _ := newRegisteredServerClientForTest(t, server, "peer-c", attachedLeft, stopCtx, stopFn)
attached.markClientConnIdentityBound()
attached.markClientConnStreamTransport()
unboundLeft, unboundRight := net.Pipe()
defer unboundRight.Close()
unbound, _, _ := newRegisteredServerClientForTest(t, server, "peer-d", unboundLeft, stopCtx, stopFn)
unbound.markClientConnStreamTransport()
unbound.markClientConnTransportDetached("read error", errors.New("boom-d"))
unbound.clearClientConnSessionRuntimeTransport()
snapshots, err := GetServerDetachedClientRuntimeSnapshots(server)
if err != nil {
t.Fatalf("GetServerDetachedClientRuntimeSnapshots failed: %v", err)
}
if got, want := len(snapshots), 2; got != want {
t.Fatalf("detached snapshot count mismatch: got %d want %d", got, want)
}
if got, want := snapshots[0].ClientID, "peer-a"; got != want {
t.Fatalf("first detached snapshot client mismatch: got %q want %q", got, want)
}
if got, want := snapshots[1].ClientID, "peer-b"; got != want {
t.Fatalf("second detached snapshot client mismatch: got %q want %q", got, want)
}
for _, snapshot := range snapshots {
if snapshot.TransportAttached {
t.Fatalf("detached snapshot should report transport detached: %+v", snapshot)
}
if !snapshot.IdentityBound || !snapshot.UsesStreamTransport {
t.Fatalf("detached snapshot identity/transport flags mismatch: %+v", snapshot)
}
if got, want := snapshot.DetachedClientKeepSec, int64(12); got != want {
t.Fatalf("detached snapshot keep seconds mismatch: got %d want %d", got, want)
}
if snapshot.TransportDetachedAt.IsZero() {
t.Fatalf("detached snapshot should record detached time: %+v", snapshot)
}
if !snapshot.ReattachEligible {
t.Fatalf("detached snapshot should be reattach eligible within keep window: %+v", snapshot)
}
if snapshot.TransportDetachExpired {
t.Fatalf("detached snapshot should not be expired yet: %+v", snapshot)
}
}
}
func TestGetServerRuntimeSnapshotCountsExpiredDetachedPeers(t *testing.T) {
server := NewServer().(*ServerCommon)
server.SetDetachedClientKeepSec(5)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
queue := stario.NewQueueCtx(stopCtx, 4, math.MaxUint32)
server.setServerSessionRuntime(&serverSessionRuntime{
stopCtx: stopCtx,
stopFn: stopFn,
queue: queue,
})
server.markSessionStarted()
activeLeft, activeRight := net.Pipe()
defer activeRight.Close()
active, _, _ := newRegisteredServerClientForTest(t, server, "peer-active", activeLeft, stopCtx, stopFn)
active.markClientConnIdentityBound()
active.markClientConnStreamTransport()
active.markClientConnTransportDetached("read error", errors.New("boom"))
active.clearClientConnSessionRuntimeTransport()
expiredLeft, expiredRight := net.Pipe()
defer expiredRight.Close()
expired, _, _ := newRegisteredServerClientForTest(t, server, "peer-expired-server", expiredLeft, stopCtx, stopFn)
expired.markClientConnIdentityBound()
expired.markClientConnStreamTransport()
expired.setClientConnTransportDetachState(&clientConnTransportDetachState{
Reason: "heartbeat timeout",
At: time.Now().Add(-10 * time.Second),
})
expired.clearClientConnSessionRuntimeTransport()
snapshot, err := GetServerRuntimeSnapshot(server)
if err != nil {
t.Fatalf("GetServerRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.DetachedClientCount, 2; got != want {
t.Fatalf("DetachedClientCount mismatch: got %d want %d", got, want)
}
if got, want := snapshot.DetachedReattachableClientCount, 1; got != want {
t.Fatalf("DetachedReattachableClientCount mismatch: got %d want %d", got, want)
}
if got, want := snapshot.DetachedExpiredClientCount, 1; got != want {
t.Fatalf("DetachedExpiredClientCount mismatch: got %d want %d", got, want)
}
}
func TestGetClientConnRuntimeSnapshotMarksExpiredDetachWindow(t *testing.T) {
server := NewServer().(*ServerCommon)
server.SetDetachedClientKeepSec(5)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
left, right := net.Pipe()
defer right.Close()
client, _, _ := newRegisteredServerClientForTest(t, server, "peer-expired", left, stopCtx, stopFn)
client.markClientConnIdentityBound()
client.markClientConnStreamTransport()
client.setClientConnTransportDetachState(&clientConnTransportDetachState{
Reason: "heartbeat timeout",
At: time.Now().Add(-10 * time.Second),
})
client.clearClientConnSessionRuntimeTransport()
snapshot, err := GetClientConnRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientConnRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.TransportDetachKind, clientConnTransportDetachKindHeartbeatTimeout; got != want {
t.Fatalf("TransportDetachKind mismatch: got %q want %q", got, want)
}
if got, want := snapshot.TransportGeneration, uint64(1); got != want {
t.Fatalf("TransportGeneration mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportDetachGeneration, uint64(1); got != want {
t.Fatalf("TransportDetachGeneration mismatch: got %d want %d", got, want)
}
if !snapshot.TransportDetachHasExpiry {
t.Fatal("TransportDetachHasExpiry mismatch: got false want true")
}
if !snapshot.TransportDetachExpired {
t.Fatal("TransportDetachExpired mismatch: got false want true")
}
if got := snapshot.TransportDetachRemaining; got != 0 {
t.Fatalf("TransportDetachRemaining mismatch: got %v want 0", got)
}
if snapshot.ReattachEligible {
t.Fatal("ReattachEligible mismatch: got true want false")
}
}
func TestGetClientConnRuntimeSnapshotKeepsUnlimitedDetachReattachable(t *testing.T) {
server := NewServer().(*ServerCommon)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
left, right := net.Pipe()
defer right.Close()
client, _, _ := newRegisteredServerClientForTest(t, server, "peer-unlimited", left, stopCtx, stopFn)
client.markClientConnIdentityBound()
client.markClientConnStreamTransport()
client.markClientConnTransportDetached("custom detach", errors.New("boom"))
client.clearClientConnSessionRuntimeTransport()
snapshot, err := GetClientConnRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientConnRuntimeSnapshot failed: %v", err)
}
if snapshot.TransportDetachHasExpiry {
t.Fatal("TransportDetachHasExpiry mismatch: got true want false")
}
if got, want := snapshot.TransportGeneration, uint64(1); got != want {
t.Fatalf("TransportGeneration mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportDetachGeneration, uint64(1); got != want {
t.Fatalf("TransportDetachGeneration mismatch: got %d want %d", got, want)
}
if !snapshot.TransportDetachExpiry.IsZero() {
t.Fatalf("TransportDetachExpiry mismatch: got %v want zero", snapshot.TransportDetachExpiry)
}
if snapshot.TransportDetachExpired {
t.Fatal("TransportDetachExpired mismatch: got true want false")
}
if got := snapshot.TransportDetachRemaining; got != 0 {
t.Fatalf("TransportDetachRemaining mismatch: got %v want 0", got)
}
if got, want := snapshot.TransportDetachKind, clientConnTransportDetachKindOther; got != want {
t.Fatalf("TransportDetachKind mismatch: got %q want %q", got, want)
}
if !snapshot.ReattachEligible {
t.Fatal("ReattachEligible mismatch: got false want true")
}
}
func TestGetClientConnRuntimeSnapshotIncrementsTransportGenerationOnReattach(t *testing.T) {
server := NewServer().(*ServerCommon)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
firstLeft, firstRight := net.Pipe()
defer firstRight.Close()
client, _, _ := newRegisteredServerClientForTest(t, server, "peer-reattach-generation", firstLeft, stopCtx, stopFn)
client.markClientConnIdentityBound()
initial, err := GetClientConnRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientConnRuntimeSnapshot initial failed: %v", err)
}
if got, want := initial.TransportGeneration, uint64(1); got != want {
t.Fatalf("initial TransportGeneration mismatch: got %d want %d", got, want)
}
if got := initial.TransportDetachGeneration; got != 0 {
t.Fatalf("initial TransportDetachGeneration mismatch: got %d want 0", got)
}
server.detachClientSessionTransport(client, "read error", errors.New("boom"))
detached, err := GetClientConnRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientConnRuntimeSnapshot detached failed: %v", err)
}
if got, want := detached.TransportGeneration, uint64(1); got != want {
t.Fatalf("detached TransportGeneration mismatch: got %d want %d", got, want)
}
if got, want := detached.TransportDetachGeneration, uint64(1); got != want {
t.Fatalf("detached TransportDetachGeneration mismatch: got %d want %d", got, want)
}
secondLeft, secondRight := net.Pipe()
defer secondRight.Close()
if err := server.attachAcceptedLogicalTransport(client.LogicalConn(), nil, secondLeft); err != nil {
t.Fatalf("attachAcceptedLogicalTransport failed: %v", err)
}
reattached, err := GetClientConnRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientConnRuntimeSnapshot reattached failed: %v", err)
}
if !reattached.TransportAttached {
t.Fatalf("reattached TransportAttached mismatch: got %v want true", reattached.TransportAttached)
}
if got, want := reattached.TransportGeneration, uint64(2); got != want {
t.Fatalf("reattached TransportGeneration mismatch: got %d want %d", got, want)
}
if got := reattached.TransportDetachGeneration; got != 0 {
t.Fatalf("reattached TransportDetachGeneration mismatch: got %d want 0", got)
}
if got, want := reattached.TransportAttachCount, uint64(2); got != want {
t.Fatalf("reattached TransportAttachCount mismatch: got %d want %d", got, want)
}
if got, want := reattached.TransportDetachCount, uint64(1); got != want {
t.Fatalf("reattached TransportDetachCount mismatch: got %d want %d", got, want)
}
if reattached.ReattachEligible {
t.Fatal("reattached ReattachEligible mismatch: got true want false")
}
}