Files
2026-05-16 00:10:04 +03:00

117 lines
3.4 KiB
Go

package fabricproto
import (
"bytes"
"context"
"errors"
"io"
"testing"
)
func TestTransportLoopRunsFramesAndWritesResponses(t *testing.T) {
var input bytes.Buffer
writeTestFrame(t, &input, Frame{Type: FrameOpenStream, TrafficClass: TrafficClassInteractive, StreamID: 7})
writeTestFrame(t, &input, Frame{Type: FrameData, TrafficClass: TrafficClassInteractive, StreamID: 7, Sequence: 3, Payload: []byte("input")})
writeTestFrame(t, &input, Frame{Type: FramePing, Sequence: 4, Payload: []byte("probe")})
var output bytes.Buffer
var events []SessionEventType
loop := TransportLoop{
Session: NewSession(SessionConfig{}),
OnEvent: func(event SessionEvent) ([]Frame, error) {
events = append(events, event.Type)
return nil, nil
},
}
if err := loop.Run(context.Background(), &input, &output); err != nil {
t.Fatalf("run loop: %v", err)
}
if len(events) != 3 || events[0] != SessionEventStreamOpened || events[1] != SessionEventData || events[2] != SessionEventPing {
t.Fatalf("events = %+v", events)
}
ack := readTestFrame(t, &output)
if ack.Type != FrameAck || ack.StreamID != 7 || ack.Sequence != 3 {
t.Fatalf("ack = %+v", ack)
}
pong := readTestFrame(t, &output)
if pong.Type != FramePong || pong.Sequence != 4 || string(pong.Payload) != "probe" {
t.Fatalf("pong = %+v", pong)
}
if _, err := ReadFrame(&output, DefaultMaxPayload); !errors.Is(err, io.EOF) {
t.Fatalf("extra response err = %v, want EOF", err)
}
}
func TestTransportLoopEventHandlerCanEmitFrames(t *testing.T) {
var output bytes.Buffer
loop := TransportLoop{
Session: NewSession(SessionConfig{}),
OnEvent: func(event SessionEvent) ([]Frame, error) {
if event.Type != SessionEventHello {
return nil, nil
}
return []Frame{{Type: FrameSessionReady, Payload: []byte("ready")}}, nil
},
}
if err := loop.Handle(context.Background(), Frame{Type: FrameHello, Payload: []byte("hello")}, &output); err != nil {
t.Fatalf("handle hello: %v", err)
}
ready := readTestFrame(t, &output)
if ready.Type != FrameSessionReady || string(ready.Payload) != "ready" {
t.Fatalf("ready = %+v", ready)
}
}
func TestTransportLoopPropagatesHandlerError(t *testing.T) {
wantErr := errors.New("handler failed")
loop := TransportLoop{
Session: NewSession(SessionConfig{}),
OnEvent: func(SessionEvent) ([]Frame, error) {
return nil, wantErr
},
}
err := loop.Handle(context.Background(), Frame{Type: FrameHello}, io.Discard)
if !errors.Is(err, wantErr) {
t.Fatalf("err = %v, want %v", err, wantErr)
}
}
func TestTransportLoopRequiresSession(t *testing.T) {
err := (TransportLoop{}).Handle(context.Background(), Frame{Type: FrameHello}, io.Discard)
if !errors.Is(err, ErrSessionNotConfigured) {
t.Fatalf("err = %v, want %v", err, ErrSessionNotConfigured)
}
}
func TestWriteFrameDetectsShortWrite(t *testing.T) {
err := WriteFrame(shortWriter{}, Frame{Type: FrameHello})
if !errors.Is(err, io.ErrShortWrite) {
t.Fatalf("err = %v, want %v", err, io.ErrShortWrite)
}
}
type shortWriter struct{}
func (shortWriter) Write([]byte) (int, error) {
return 0, nil
}
func writeTestFrame(t *testing.T, w io.Writer, frame Frame) {
t.Helper()
if err := WriteFrame(w, frame); err != nil {
t.Fatalf("write frame %+v: %v", frame, err)
}
}
func readTestFrame(t *testing.T, r io.Reader) Frame {
t.Helper()
frame, err := ReadFrame(r, DefaultMaxPayload)
if err != nil {
t.Fatalf("read frame: %v", err)
}
return frame
}