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 }