//go:build linux package transport import ( "net" "reflect" "testing" "omnisocketgo/cmd/internal/latencylog" "omnisocketgo/cmd/internal/protocol" ) func TestLinuxTimestampingRecordsKernelEvents(t *testing.T) { tests := []struct { name string msg protocol.Message }{ { name: "text", msg: protocol.Message{ Type: protocol.MessageTypeText, ID: 41, From: "peer-a", To: "peer-b", Body: []byte("hello over tcp"), }, }, { name: "file", msg: protocol.Message{ Type: protocol.MessageTypeFile, ID: 42, From: "peer-a", To: "peer-b", FileName: "payload.bin", Body: []byte{0x00, 0x01, 0x02, 0xff}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { clientConn, serverConn := newTCPPair(t) senderLogger := &recordingLogger{} receiverLogger := &recordingLogger{} sender, err := NewTCPConn( clientConn, WithLogger(senderLogger, latencylog.NodeRolePeer, "peer-a"), ) if err != nil { t.Fatalf("NewTCPConn(sender) error = %v", err) } receiver, err := NewTCPConn( serverConn, WithLogger(receiverLogger, latencylog.NodeRolePeer, "peer-b"), ) if err != nil { t.Fatalf("NewTCPConn(receiver) error = %v", err) } t.Cleanup(func() { _ = sender.Close() _ = receiver.Close() }) sendErr := make(chan error, 1) go func() { sendErr <- sender.Send(tt.msg) }() got, err := receiver.Receive() if err != nil { t.Fatalf("Receive() error = %v", err) } if err := <-sendErr; err != nil { t.Fatalf("Send() error = %v", err) } if !reflect.DeepEqual(got, tt.msg) { t.Fatalf("message mismatch: got %+v want %+v", got, tt.msg) } assertHasEvent(t, senderLogger.Events(), latencylog.EventATXSched, tt.msg.ID) assertHasEvent(t, senderLogger.Events(), latencylog.EventATXSoftware, tt.msg.ID) assertHasEvent(t, receiverLogger.Events(), latencylog.EventBRXSoftware, tt.msg.ID) }) } } func newTCPPair(t *testing.T) (net.Conn, net.Conn) { t.Helper() listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("net.Listen() error = %v", err) } type acceptResult struct { conn net.Conn err error } accepted := make(chan acceptResult, 1) go func() { conn, acceptErr := listener.Accept() accepted <- acceptResult{conn: conn, err: acceptErr} }() clientConn, err := net.Dial("tcp", listener.Addr().String()) if err != nil { _ = listener.Close() t.Fatalf("net.Dial() error = %v", err) } result := <-accepted if err := listener.Close(); err != nil { t.Fatalf("listener.Close() error = %v", err) } if result.err != nil { _ = clientConn.Close() t.Fatalf("listener.Accept() error = %v", result.err) } return clientConn, result.conn } func assertHasEvent(t *testing.T, events []latencylog.Event, wantEvent string, wantMessageID uint64) { t.Helper() for _, event := range events { if event.Event == wantEvent && event.MessageID == wantMessageID { if event.TsUnixNano <= 0 { t.Fatalf("event %s timestamp must be positive: %+v", wantEvent, event) } return } } t.Fatalf("missing event %s for message %d in %+v", wantEvent, wantMessageID, events) }