package sfudp_test // 100% of AI generated code // not reviewed at all import ( "WhspBrd/sfudp" "bytes" "encoding/binary" "errors" "net" "sync" "testing" "time" ) const testTimeout = 2 * time.Second // --- helpers --- func newPair(t *testing.T) (*sfudp.SFUDPConn, *sfudp.SFUDPConn) { t.Helper() s, err := sfudp.ListenSFUDP("udp", &net.UDPAddr{Port: 0}) if err != nil { t.Fatal(err) } c, err := sfudp.DialSFUDP("udp", nil, s.GetUDP().LocalAddr().(*net.UDPAddr)) if err != nil { s.Close() t.Fatal(err) } _ = s.GetUDP().SetReadDeadline(time.Now().Add(testTimeout)) _ = c.GetUDP().SetReadDeadline(time.Now().Add(testTimeout)) return s, c } func mustWrite(t *testing.T, c *sfudp.SFUDPConn, b []byte) { t.Helper() n, err := c.Write(b) if err != nil { t.Fatal(err) } if n != len(b) { t.Fatalf("short write: %d != %d", n, len(b)) } } func mustRead(t *testing.T, s *sfudp.SFUDPConn, expected []byte) { t.Helper() buf := make([]byte, len(expected)) n, err := s.Read(buf) if err != nil { t.Fatal(err) } if n != len(expected) { t.Fatalf("size mismatch: %d != %d", n, len(expected)) } if !bytes.Equal(buf, expected) { t.Fatal("payload mismatch") } } // --- tests --- func TestMessageSizes(t *testing.T) { s, c := newPair(t) defer s.Close() defer c.Close() tests := []int{ 1, 100, sfudp.MaxPayload - 1, sfudp.MaxPayload, sfudp.MaxPayload + 1, sfudp.MaxPayload*3 + 123, } for _, size := range tests { t.Run("size_"+itoa(size), func(t *testing.T) { msg := make([]byte, size) for i := range msg { msg[i] = byte(i) } mustWrite(t, c, msg) mustRead(t, s, msg) }) } } func TestTooLargeMessage(t *testing.T) { s, c := newPair(t) defer s.Close() defer c.Close() msg := make([]byte, sfudp.MaxPayload*sfudp.MaxFragments+1) _, err := c.Write(msg) if err == nil { t.Fatal("expected error") } } func TestBufferTooSmall(t *testing.T) { s, c := newPair(t) defer s.Close() defer c.Close() msg := make([]byte, sfudp.MaxPayload*2) mustWrite(t, c, msg) small := make([]byte, 10) _, err := s.Read(small) if err == nil { t.Fatal("expected buffer too small error") } } func TestConcurrentWrites(t *testing.T) { s, c := newPair(t) defer s.Close() defer c.Close() const count = 20 var wg sync.WaitGroup for i := 0; i < count; i++ { wg.Add(1) go func(v int) { defer wg.Done() msg := bytes.Repeat([]byte{byte(v)}, sfudp.MaxPayload+50) mustWrite(t, c, msg) }(i) } go func() { wg.Wait() }() for i := 0; i < count; i++ { buf := make([]byte, sfudp.MaxPayload+50) _, err := s.Read(buf) if err != nil { t.Fatal(err) } } } func TestFragmentTimeoutGC(t *testing.T) { s, _ := newPair(t) defer s.Close() raw, err := net.DialUDP("udp", nil, s.GetUDP().LocalAddr().(*net.UDPAddr)) if err != nil { t.Fatal(err) } defer raw.Close() // send incomplete fragment set pkt := make([]byte, sfudp.HeaderSize+10) binary.LittleEndian.PutUint32(pkt[0:4], 999) binary.LittleEndian.PutUint16(pkt[4:6], 0) pkt[6] = 2 _, _ = raw.Write(pkt) time.Sleep(sfudp.FragmentTTL + time.Second) // IMPORTANT: reset deadline after long sleep _ = s.GetUDP().SetReadDeadline(time.Now().Add(testTimeout)) // send valid single fragment valid := []byte("ok") pkt = make([]byte, sfudp.HeaderSize+len(valid)) pkt[6] = 1 copy(pkt[sfudp.HeaderSize:], valid) _, _ = raw.Write(pkt) buf := make([]byte, 10) n, err := s.Read(buf) if err != nil { t.Fatal(err) } if !bytes.Equal(buf[:n], valid) { t.Fatal("unexpected payload") } } func TestInvalidFragmentIgnored(t *testing.T) { s, _ := newPair(t) defer s.Close() raw, err := net.DialUDP("udp", nil, s.GetUDP().LocalAddr().(*net.UDPAddr)) if err != nil { t.Fatal(err) } defer raw.Close() // invalid index >= count pkt := make([]byte, sfudp.HeaderSize+10) binary.LittleEndian.PutUint32(pkt[0:4], 111) binary.LittleEndian.PutUint16(pkt[4:6], 5) pkt[6] = 2 _, _ = raw.Write(pkt) // valid single packet valid := []byte("good") pkt = make([]byte, sfudp.HeaderSize+len(valid)) pkt[6] = 1 copy(pkt[sfudp.HeaderSize:], valid) _, _ = raw.Write(pkt) buf := make([]byte, 16) n, err := s.Read(buf) if err != nil { t.Fatal(err) } if !bytes.Equal(buf[:n], valid) { t.Fatal("invalid fragment was not ignored") } } func TestEmptyWrite(t *testing.T) { s, c := newPair(t) defer s.Close() defer c.Close() n, err := c.Write(nil) if err != nil || n != 0 { t.Fatal("empty write failed") } buf := make([]byte, 16) _, err = s.Read(buf) if err == nil { t.Fatal("expected timeout") } if !errors.Is(err, net.ErrClosed) && !isTimeout(err) { t.Fatal("unexpected error:", err) } } // small int to string helper without fmt func itoa(v int) string { if v == 0 { return "0" } var b [20]byte i := len(b) for v > 0 { i-- b[i] = byte('0' + v%10) v /= 10 } return string(b[i:]) } func isTimeout(err error) bool { nerr, ok := err.(net.Error) return ok && nerr.Timeout() }