lab.nexedi.com/kirr/go123@v0.0.0-20240207185015-8299741fa871/xnet/internal/virtnettest/vnettest.go (about)

     1  // Copyright (C) 2017-2020  Nexedi SA and Contributors.
     2  //                          Kirill Smelkov <kirr@nexedi.com>
     3  //
     4  // This program is free software: you can Use, Study, Modify and Redistribute
     5  // it under the terms of the GNU General Public License version 3, or (at your
     6  // option) any later version, as published by the Free Software Foundation.
     7  //
     8  // You can also Link and Combine this program with other software covered by
     9  // the terms of any of the Free Software licenses or any of the Open Source
    10  // Initiative approved licenses and Convey the resulting work. Corresponding
    11  // source of such a combination shall include the source code for all other
    12  // software used.
    13  //
    14  // This program is distributed WITHOUT ANY WARRANTY; without even the implied
    15  // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    16  //
    17  // See COPYING file for full licensing terms.
    18  // See https://www.nexedi.com/licensing for rationale and options.
    19  
    20  // Package virtnettest provides basic tests to be run on virtnet network implementations.
    21  package virtnettest
    22  
    23  import (
    24  	"context"
    25  	"io"
    26  	"net"
    27  	"testing"
    28  
    29  	"golang.org/x/sync/errgroup"
    30  
    31  	"lab.nexedi.com/kirr/go123/exc"
    32  	"lab.nexedi.com/kirr/go123/internal/xtesting"
    33  	"lab.nexedi.com/kirr/go123/xnet"
    34  	"lab.nexedi.com/kirr/go123/xnet/virtnet"
    35  )
    36  
    37  
    38  type mklistener interface {
    39  	Listen(context.Context, string) (xnet.Listener, error)
    40  }
    41  
    42  func xlisten(ctx context.Context, n mklistener, laddr string) xnet.Listener {
    43  	l, err := n.Listen(ctx, laddr)
    44  	exc.Raiseif(err)
    45  	return l
    46  }
    47  
    48  func xaccept(ctx context.Context, l xnet.Listener) net.Conn {
    49  	c, err := l.Accept(ctx)
    50  	exc.Raiseif(err)
    51  	return c
    52  }
    53  
    54  type dialer interface {
    55  	Dial(context.Context, string) (net.Conn, error)
    56  }
    57  
    58  func xdial(n dialer, addr string) net.Conn {
    59  	c, err := n.Dial(context.Background(), addr)
    60  	exc.Raiseif(err)
    61  	return c
    62  }
    63  
    64  func xread(r io.Reader) string {
    65  	buf := make([]byte, 4096)
    66  	n, err := r.Read(buf)
    67  	exc.Raiseif(err)
    68  	return string(buf[:n])
    69  }
    70  
    71  func xwrite(w io.Writer, data string) {
    72  	_, err := w.Write([]byte(data))
    73  	exc.Raiseif(err)
    74  }
    75  
    76  func xwait(w interface { Wait() error }) {
    77  	err := w.Wait()
    78  	exc.Raiseif(err)
    79  }
    80  
    81  // TestBasic runs basic tests on a virtnet network implementation.
    82  func TestBasic(t *testing.T, subnet *virtnet.SubNetwork) {
    83  	X := exc.Raiseif
    84  	ctx := context.Background()
    85  	assert := xtesting.Assert(t)
    86  
    87  	defer func() {
    88  		err := subnet.Close()
    89  		X(err)
    90  	}()
    91  
    92  	xaddr := func(addr string) *virtnet.Addr {
    93  		a, err := virtnet.ParseAddr(subnet.Network(), addr)
    94  		X(err)
    95  		return a
    96  	}
    97  
    98  	hα, err := subnet.NewHost(ctx, "α")
    99  	X(err)
   100  
   101  	hβ, err := subnet.NewHost(ctx, "β")
   102  	X(err)
   103  
   104  	assert.Eq(hα.Network(), subnet.Network())
   105  	assert.Eq(hβ.Network(), subnet.Network())
   106  	assert.Eq(hα.Name(), "α")
   107  	assert.Eq(hβ.Name(), "β")
   108  
   109  	_, err = hα.Dial(ctx, ":0")
   110  	assert.Eq(err, &net.OpError{Op: "dial", Net: subnet.Network(), Source: xaddr("α:1"), Addr: xaddr("α:0"), Err: virtnet.ErrConnRefused})
   111  
   112  	l1, err := hα.Listen(ctx, "")
   113  	X(err)
   114  	assert.Eq(l1.Addr(), xaddr("α:1"))
   115  
   116  	// zero port always stays unused even after autobind
   117  	_, err = hα.Dial(ctx, ":0")
   118  	assert.Eq(err, &net.OpError{Op: "dial", Net: subnet.Network(), Source: xaddr("α:2"), Addr: xaddr("α:0"), Err: virtnet.ErrConnRefused})
   119  
   120  	wg := &errgroup.Group{}
   121  	wg.Go(exc.Funcx(func() {
   122  		c1s := xaccept(ctx, l1)
   123  		assert.Eq(c1s.LocalAddr(), xaddr("α:2"))
   124  		assert.Eq(c1s.RemoteAddr(), xaddr("β:1"))
   125  
   126  		assert.Eq(xread(c1s), "ping")		// XXX for !pipe could read less
   127  		xwrite(c1s, "pong")
   128  
   129  		c2s := xaccept(ctx, l1)
   130  		assert.Eq(c2s.LocalAddr(), xaddr("α:3"))
   131  		assert.Eq(c2s.RemoteAddr(), xaddr("β:2"))
   132  
   133  		assert.Eq(xread(c2s), "hello")
   134  		xwrite(c2s, "world")
   135  	}))
   136  
   137  	c1c := xdial(hβ, "α:1")
   138  	assert.Eq(c1c.LocalAddr(), xaddr("β:1"))
   139  	assert.Eq(c1c.RemoteAddr(), xaddr("α:2"))
   140  
   141  	xwrite(c1c, "ping")
   142  	assert.Eq(xread(c1c), "pong")
   143  
   144  	c2c := xdial(hβ, "α:1")
   145  	assert.Eq(c2c.LocalAddr(), xaddr("β:2"))
   146  	assert.Eq(c2c.RemoteAddr(), xaddr("α:3"))
   147  
   148  	xwrite(c2c, "hello")
   149  	assert.Eq(xread(c2c), "world")
   150  
   151  	xwait(wg)
   152  
   153  	l2 := xlisten(ctx, hα, ":0") // autobind again
   154  	assert.Eq(l2.Addr(), xaddr("α:4"))
   155  }