Source file src/internal/nettest/packetconn_test.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package nettest_test
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"internal/nettest"
    11  	"io"
    12  	"net"
    13  	"net/netip"
    14  	"os"
    15  	"testing"
    16  	"testing/synctest"
    17  	"time"
    18  )
    19  
    20  func TestPacketConnListenConflict(t *testing.T) {
    21  	synctest.Test(t, func(t *testing.T) {
    22  		addr := net.UDPAddrFromAddrPort(netip.MustParseAddrPort("10.0.0.1:1000"))
    23  		pnet := nettest.NewPacketNet()
    24  		conn, err := pnet.NewConn(addr)
    25  		if err != nil {
    26  			t.Fatalf("with no existing listener, pnet.NewConn(%v) = %v; want success", addr, err)
    27  		}
    28  		_, err = pnet.NewConn(addr)
    29  		if err == nil {
    30  			t.Fatalf("with existing listener, pnet.NewConn(%v) = nil; want error", addr)
    31  		}
    32  		conn.Close()
    33  		_, err = pnet.NewConn(addr)
    34  		if err != nil {
    35  			t.Fatalf("after closing existing listener, pnet.NewConn(%v) = %v; want success", addr, err)
    36  		}
    37  	})
    38  }
    39  
    40  func TestPacketConnReadWrite(t *testing.T) {
    41  	synctest.Test(t, func(t *testing.T) {
    42  		pnet := nettest.NewPacketNet()
    43  		c1 := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
    44  		c2 := mustNewPacketConn(t, pnet, "10.0.0.2:2000")
    45  		c3 := mustNewPacketConn(t, pnet, "10.0.0.3:3000")
    46  
    47  		wantPacketConnWriteTo(t, c1, []byte("1->3"), c3.LocalAddr())
    48  		wantPacketConnWriteTo(t, c2, []byte("2->3"), c3.LocalAddr())
    49  		wantPacketConnWriteTo(t, c3, []byte("3->1"), c1.LocalAddr())
    50  
    51  		wantPacketConnReadBytes(t, c1, []byte("3->1"), c3.LocalAddr())
    52  		wantPacketConnReadBytes(t, c3, []byte("1->3"), c1.LocalAddr())
    53  		wantPacketConnReadBytes(t, c3, []byte("2->3"), c2.LocalAddr())
    54  		wantPacketConnReadBlocked(t, c1)
    55  		wantPacketConnReadBlocked(t, c2)
    56  		wantPacketConnReadBlocked(t, c3)
    57  
    58  		// Write a packet into the void (no listener on this address).
    59  		wantPacketConnWriteTo(t, c1, []byte("1->lost"), net.UDPAddrFromAddrPort(netip.MustParseAddrPort("10.0.0.100:1000")))
    60  	})
    61  }
    62  
    63  func TestPacketConnWriteAddressErrors(t *testing.T) {
    64  	t.Skip("TODO: figure out if these should be errors")
    65  
    66  	synctest.Test(t, func(t *testing.T) {
    67  		pnet := nettest.NewPacketNet()
    68  		c4 := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
    69  		c6 := mustNewPacketConn(t, pnet, "[::1]:1000")
    70  
    71  		wantPacketConnWriteErr(t, c4, c6.LocalAddr(), anyError) // IPv4 -> IPv6
    72  		wantPacketConnWriteErr(t, c6, c4.LocalAddr(), anyError) // IPv6 -> IPv4
    73  
    74  		// Not a *net.UDPAddr.
    75  		wantPacketConnWriteErr(t, c4, net.UDPAddrFromAddrPort(netip.MustParseAddrPort("10.0.0.1:1000")), anyError)
    76  	})
    77  }
    78  
    79  func TestPacketConnClose(t *testing.T) {
    80  	synctest.Test(t, func(t *testing.T) {
    81  		pnet := nettest.NewPacketNet()
    82  		pconn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
    83  
    84  		wantPacketConnWriteTo(t, pconn, []byte("hello"), pconn.LocalAddr())
    85  
    86  		if err := pconn.Close(); err != nil {
    87  			t.Errorf("pconn.Close() = %v, want success", err)
    88  		}
    89  		if err := pconn.Close(); !isOpError(err, net.ErrClosed) {
    90  			t.Errorf("pconn.Close() = %v, want ErrClosed", err)
    91  		}
    92  
    93  		wantPacketConnReadErr(t, pconn, net.ErrClosed)
    94  		wantPacketConnWriteErr(t, pconn, pconn.LocalAddr(), net.ErrClosed)
    95  	})
    96  }
    97  
    98  func TestPacketConnReadDeadline(t *testing.T) {
    99  	for _, setDeadline := range []struct {
   100  		name string
   101  		f    func(*nettest.PacketConn, time.Time) error
   102  	}{{
   103  		name: "SetDeadline",
   104  		f:    (*nettest.PacketConn).SetDeadline,
   105  	}, {
   106  		name: "SetReadDeadline",
   107  		f:    (*nettest.PacketConn).SetReadDeadline,
   108  	}} {
   109  		t.Run(setDeadline.name, func(t *testing.T) {
   110  			testDeadline(t, func() deadlineTest {
   111  				pnet := nettest.NewPacketNet()
   112  				rconn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
   113  				wconn := mustNewPacketConn(t, pnet, "10.0.0.2:2000")
   114  				return deadlineTest{
   115  					what: "ReadFrom()",
   116  					block: func() error {
   117  						_, _, err := rconn.ReadFrom(make([]byte, 1))
   118  						return err
   119  					},
   120  					unblock: func() {
   121  						wconn.WriteTo([]byte("x"), rconn.LocalAddr())
   122  					},
   123  					setDeadline: func(d time.Duration) {
   124  						setDeadline.f(rconn, time.Now().Add(d))
   125  					},
   126  				}
   127  			})
   128  		})
   129  	}
   130  }
   131  
   132  func TestPacketConnWriteDeadline(t *testing.T) {
   133  	synctest.Test(t, func(t *testing.T) {
   134  		pnet := nettest.NewPacketNet()
   135  		rconn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
   136  		wconn := mustNewPacketConn(t, pnet, "10.0.0.2:2000")
   137  
   138  		// This does nothing, even though the deadline has expired.
   139  		wconn.SetWriteDeadline(time.Now().Add(-1 * time.Second))
   140  
   141  		wantPacketConnWriteTo(t, wconn, []byte("data"), rconn.LocalAddr())
   142  		wantPacketConnReadBytes(t, rconn, []byte("data"), wconn.LocalAddr())
   143  	})
   144  }
   145  
   146  func TestPacketConnSetReadError(t *testing.T) {
   147  	synctest.Test(t, func(t *testing.T) {
   148  		wantErr := errors.New("error")
   149  		pnet := nettest.NewPacketNet()
   150  		rconn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
   151  		wconn := mustNewPacketConn(t, pnet, "10.0.0.2:2000")
   152  		rconn.SetReadError(wantErr)
   153  
   154  		// Consume buffer before returning error.
   155  		wantPacketConnWriteTo(t, wconn, []byte("one"), rconn.LocalAddr())
   156  		wantPacketConnReadBytes(t, rconn, []byte("one"), wconn.LocalAddr())
   157  		wantPacketConnReadErr(t, rconn, wantErr)
   158  
   159  		// Write more, suppressing error until buffer drains again.
   160  		wantPacketConnWriteTo(t, wconn, []byte("two"), rconn.LocalAddr())
   161  		wantPacketConnReadBytes(t, rconn, []byte("two"), wconn.LocalAddr())
   162  		wantPacketConnReadErr(t, rconn, wantErr)
   163  
   164  		// Error may be cleared.
   165  		rconn.SetReadError(nil)
   166  		wantPacketConnReadBlocked(t, rconn)
   167  
   168  		// ErrClosed takes precedence over read error.
   169  		rconn.SetReadError(wantErr)
   170  		rconn.Close()
   171  		wantPacketConnReadErr(t, rconn, net.ErrClosed)
   172  	})
   173  }
   174  
   175  func TestPacketConnSetWriteError(t *testing.T) {
   176  	synctest.Test(t, func(t *testing.T) {
   177  		wantErr := errors.New("error")
   178  		pnet := nettest.NewPacketNet()
   179  		rconn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
   180  		wconn := mustNewPacketConn(t, pnet, "10.0.0.2:2000")
   181  		wconn.SetWriteError(wantErr)
   182  
   183  		// Error blocks writes.
   184  		wantPacketConnWriteErr(t, wconn, rconn.LocalAddr(), wantErr)
   185  		wantPacketConnReadBlocked(t, rconn)
   186  
   187  		// Error may be cleared.
   188  		wconn.SetWriteError(nil)
   189  		wantPacketConnWriteTo(t, wconn, []byte("one"), rconn.LocalAddr())
   190  
   191  		// Restoring error does not prevent reading buffered data.
   192  		wconn.SetWriteError(wantErr)
   193  		wantPacketConnWriteErr(t, wconn, rconn.LocalAddr(), wantErr)
   194  		wantPacketConnReadBytes(t, rconn, []byte("one"), wconn.LocalAddr())
   195  
   196  		// Error does not interfere with closing the conn.
   197  		wconn.Close()
   198  		wantPacketConnWriteErr(t, wconn, rconn.LocalAddr(), net.ErrClosed)
   199  	})
   200  }
   201  
   202  func TestPacketConnSetCloseError(t *testing.T) {
   203  	synctest.Test(t, func(t *testing.T) {
   204  		wantErr := errors.New("error")
   205  		pnet := nettest.NewPacketNet()
   206  		rconn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
   207  		wconn := mustNewPacketConn(t, pnet, "10.0.0.2:2000")
   208  		wconn.SetCloseError(wantErr)
   209  
   210  		wantPacketConnWriteTo(t, wconn, []byte("one"), rconn.LocalAddr())
   211  		if err := wconn.Close(); !isOpError(err, wantErr) {
   212  			t.Fatalf("wconn.Close = %v, want OpError{Err: %v}", err, wantErr)
   213  		}
   214  		if err := wconn.Close(); !isOpError(err, net.ErrClosed) {
   215  			t.Fatalf("wconn.Close = %v, want OpError{Err: net.ErrClosed}", err)
   216  		}
   217  		wantPacketConnReadBytes(t, rconn, []byte("one"), wconn.LocalAddr())
   218  	})
   219  }
   220  
   221  func TestPacketConnCanRead(t *testing.T) {
   222  	synctest.Test(t, func(t *testing.T) {
   223  		pnet := nettest.NewPacketNet()
   224  		rconn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
   225  		wconn := mustNewPacketConn(t, pnet, "10.0.0.2:2000")
   226  		if got, want := rconn.CanRead(), false; got != want {
   227  			t.Fatalf("before writing data: rconn.CanRead() = %v, want %v", got, want)
   228  		}
   229  		wconn.WriteTo([]byte("a"), rconn.LocalAddr())
   230  		if got, want := rconn.CanRead(), true; got != want {
   231  			t.Fatalf("after writing data: rconn.CanRead() = %v, want %v", got, want)
   232  		}
   233  		rconn.ReadFrom(make([]byte, 1))
   234  		if got, want := rconn.CanRead(), false; got != want {
   235  			t.Fatalf("after reading data: rconn.CanRead() = %v, want %v", got, want)
   236  		}
   237  	})
   238  }
   239  
   240  func TestPacketConnIsClosed(t *testing.T) {
   241  	synctest.Test(t, func(t *testing.T) {
   242  		pnet := nettest.NewPacketNet()
   243  		conn := mustNewPacketConn(t, pnet, "10.0.0.1:1000")
   244  		if got, want := conn.IsClosed(), false; got != want {
   245  			t.Fatalf("before closing: conn.IsClosed() = %v, want %v", got, want)
   246  		}
   247  		conn.Close()
   248  		if got, want := conn.IsClosed(), true; got != want {
   249  			t.Fatalf("after closing: conn.IsClosed() = %v, want %v", got, want)
   250  		}
   251  	})
   252  }
   253  
   254  func mustNewPacketConn(t *testing.T, pnet *nettest.PacketNet, addr string) *nettest.PacketConn {
   255  	t.Helper()
   256  	c, err := pnet.NewConn(net.UDPAddrFromAddrPort(netip.MustParseAddrPort(addr)))
   257  	if err != nil {
   258  		t.Fatal(err)
   259  	}
   260  	return c
   261  }
   262  
   263  func wantPacketConnWriteTo(t *testing.T, c *nettest.PacketConn, b []byte, dst net.Addr) {
   264  	t.Helper()
   265  	if n, err := c.WriteTo(b, dst); n != len(b) || err != nil {
   266  		t.Fatalf("conn.WriteTo(%q, %v) = %v, %v; want %v, nil", b, dst, n, err, len(b))
   267  	}
   268  }
   269  
   270  func wantPacketConnWriteErr(t *testing.T, c *nettest.PacketConn, dst net.Addr, want error) {
   271  	t.Helper()
   272  	n, err := c.WriteTo(make([]byte, 1), dst)
   273  	if n != 0 || !isOpError(err, want) {
   274  		t.Fatalf("c.WriteTo() = %v, %v; want 0, OpError{Err: %q}", n, err, want)
   275  	}
   276  }
   277  
   278  func wantPacketConnReadBytes(t *testing.T, c *nettest.PacketConn, want []byte, wantAddr net.Addr) {
   279  	t.Helper()
   280  	udpWantAddr, ok := wantAddr.(*net.UDPAddr)
   281  	if !ok {
   282  		t.Fatalf("wantAddr is %T, should be *net.UDPAddr", wantAddr)
   283  	}
   284  	got := make([]byte, len(want)+1)
   285  	n, addr, err := c.ReadFrom(got)
   286  	got = got[:n]
   287  	udpAddr, addrOK := addr.(*net.UDPAddr)
   288  	if n != len(want) || !addrOK || udpAddr.AddrPort() != udpWantAddr.AddrPort() {
   289  		t.Fatalf("conn.ReadFrom() = %v, %v, %v; want %v, %v, nil", n, addr, err, len(want), wantAddr)
   290  	}
   291  	if !bytes.Equal(got, want) {
   292  		t.Fatalf("conn.ReadFrom() read %q, want %q", got, want)
   293  	}
   294  }
   295  
   296  func wantPacketConnReadErr(t *testing.T, c *nettest.PacketConn, want error) {
   297  	t.Helper()
   298  	n, addr, err := c.ReadFrom(make([]byte, 1))
   299  	if want == io.EOF {
   300  		if n != 0 || err != io.EOF {
   301  			t.Fatalf("c.ReadFrom() = %v, %v, %v; want 0, nil, io.EOF", n, addr, err)
   302  		}
   303  	} else {
   304  		if n != 0 || !isOpError(err, want) {
   305  			t.Fatalf("c.ReadFrom() = %v, %v, %v; want 0, nil, OpError{Err: %q}", n, addr, err, want)
   306  		}
   307  	}
   308  }
   309  
   310  func wantPacketConnReadBlocked(t *testing.T, c *nettest.PacketConn) {
   311  	done := false
   312  	go func() {
   313  		n, addr, err := c.ReadFrom(make([]byte, 1))
   314  		if n != 0 || !errors.Is(err, os.ErrDeadlineExceeded) {
   315  			t.Errorf("c.Read() = %v, %v, %v; want 0, nil, ErrDeadlineExceeded", n, addr, err)
   316  		}
   317  		done = true
   318  	}()
   319  	synctest.Wait()
   320  	if done {
   321  		t.Fatalf("ReadFrom unexpectedly returned before setting deadline")
   322  	}
   323  	c.SetReadDeadline(time.Now().Add(-1 * time.Second))
   324  	synctest.Wait()
   325  	c.SetReadDeadline(time.Time{})
   326  	if !done {
   327  		t.Fatalf("ReadFrom unexpectedly did not return after setting deadline")
   328  	}
   329  }
   330  

View as plain text