diff --git a/go/xcommon/pipenet/pipenet.go b/go/xcommon/pipenet/pipenet.go
index 2433865927d3a8a8f47ab98242d55fad81952d8a..94faa10d8cc2edcc77145b4f85f4b51796647b8b 100644
--- a/go/xcommon/pipenet/pipenet.go
+++ b/go/xcommon/pipenet/pipenet.go
@@ -19,8 +19,8 @@
 //
 // TODO describe addressing scheme
 //
-// it is useful for testing networked applications interaction in 1 process
-// without going to OS networking stack. XXX
+// it might be handy for testing interaction in networked applications in 1
+// process without going to OS networking stack.
 package pipenet
 
 import (
@@ -52,7 +52,7 @@ type Addr struct {
 // Network implements synchronous in-memory network of pipes
 // It can be worked with the same way a regular TCP network is handled with Dial/Listen/Accept/...
 //
-// Network must be created with New
+// Network must be created with New	XXX is it really ok to have global state ?
 type Network struct {
 	// name of this network under "pipe" namespace -> e.g. ""
 	// full network name will be reported as "pipe"+Name		XXX -> just full name ?
@@ -226,8 +226,8 @@ func (l *listener) Accept() (net.Conn, error) {
 
 		n.mu.Unlock()
 
-		resp <- pc
-		return ps, nil
+		resp <- e.pipev[0]
+		return e.pipev[1], nil
 	}
 }
 
@@ -346,14 +346,14 @@ func New(name string) *Network {
 // lookupNet lookups Network by name
 // name is full network name, e.g. "pipe"
 func lookupNet(name string) (*Network, error) {
-	if !strings.HasPrefix(NetPrefix, name) {
+	if !strings.HasPrefix(name, NetPrefix) {
 		return nil, errBadNetwork
 	}
 
 	netMu.Lock()
 	defer netMu.Unlock()
 
-	n := networks[strings.TrimPrefix(NetPrefix, name)]
+	n := networks[strings.TrimPrefix(name, NetPrefix)]
 	if n == nil {
 		return nil, errNetNotFound
 	}
diff --git a/go/xcommon/pipenet/pipenet_test.go b/go/xcommon/pipenet/pipenet_test.go
index c7d5c37103dfd1da8f89b6d13ae66b9c7fcaa554..79edfa62b8b5079f16a6ab314e2a530fd3158ca6 100644
--- a/go/xcommon/pipenet/pipenet_test.go
+++ b/go/xcommon/pipenet/pipenet_test.go
@@ -17,4 +17,113 @@
 
 package pipenet
 
-// TODO
+import (
+	"fmt"
+	"io"
+	"net"
+	"reflect"
+	"testing"
+
+	"golang.org/x/sync/errgroup"
+
+	"lab.nexedi.com/kirr/go123/exc"
+)
+
+// we assume net.Pipe works ok; here we only test Listen/Accept/Dial routing
+// XXX tests are ugly, non-robust and small coverage
+
+func xlisten(network, laddr string) net.Listener {
+	l, err := Listen(network, laddr)
+	exc.Raiseif(err)
+	return l
+}
+
+func xaccept(l net.Listener) net.Conn {
+	c, err := l.Accept()
+	exc.Raiseif(err)
+	return c
+}
+
+func xdial(network, addr string) net.Conn {
+	c, err := Dial(network, addr)
+	exc.Raiseif(err)
+	return c
+}
+
+func xread(r io.Reader) string {
+	buf := make([]byte, 4096)
+	n, err := r.Read(buf)
+	exc.Raiseif(err)
+	return string(buf[:n])
+}
+
+func xwrite(w io.Writer, data string) {
+	_, err := w.Write([]byte(data))
+	exc.Raiseif(err)
+}
+
+func xwait(w interface { Wait() error }) {
+	err := w.Wait()
+	exc.Raiseif(err)
+}
+
+func assertEq(t *testing.T, a, b interface{}) {
+	if !reflect.DeepEqual(a, b) {
+		fmt.Printf("not equal:\nhave: %v\nwant: %v\n", a, b)
+		t.Errorf("not equal:\nhave: %v\nwant: %v", a, b)
+		exc.Raise(0)
+	}
+}
+
+
+func TestPipeNet(t *testing.T) {
+	New("伪")
+
+	_, err := Dial("伪", "0")
+	assertEq(t, err, &net.OpError{Op: "dial", Net: "伪", Addr: &Addr{"伪", "0"}, Err: errBadNetwork})
+
+	_, err = Dial("pipe伪", "0")
+	assertEq(t, err, &net.OpError{Op: "dial", Net: "pipe伪", Addr: &Addr{"pipe伪", "0"}, Err: errConnRefused})
+
+	l1 := xlisten("pipe伪", "")
+	assertEq(t, l1.Addr(), &Addr{"pipe伪", "0"})
+
+	// XXX -> use workGroup (in connection_test.go)
+	wg := &errgroup.Group{}
+	wg.Go(func() error {
+		return exc.Runx(func() {
+			c1s := xaccept(l1)
+			assertEq(t, c1s.LocalAddr(), &Addr{"pipe伪", "1s"})
+			assertEq(t, c1s.RemoteAddr(), &Addr{"pipe伪", "1c"})
+
+			assertEq(t, xread(c1s), "ping")
+			xwrite(c1s, "pong")
+
+			c2s := xaccept(l1)
+			assertEq(t, c2s.LocalAddr(), &Addr{"pipe伪", "2s"})
+			assertEq(t, c2s.RemoteAddr(), &Addr{"pipe伪", "2c"})
+
+			assertEq(t, xread(c2s), "hello")
+			xwrite(c2s, "world")
+		})
+	})
+
+	c1c := xdial("pipe伪", "0")
+	assertEq(t, c1c.LocalAddr(), &Addr{"pipe伪", "1c"})
+	assertEq(t, c1c.RemoteAddr(), &Addr{"pipe伪", "1s"})
+
+	xwrite(c1c, "ping")
+	assertEq(t, xread(c1c), "pong")
+
+	c2c := xdial("pipe伪", "0")
+	assertEq(t, c2c.LocalAddr(), &Addr{"pipe伪", "2c"})
+	assertEq(t, c2c.RemoteAddr(), &Addr{"pipe伪", "2s"})
+
+	xwrite(c2c, "hello")
+	assertEq(t, xread(c2c), "world")
+
+	xwait(wg)
+
+	l2 := xlisten("pipe伪", "")
+	assertEq(t, l2.Addr(), &Addr{"pipe伪", "3"})
+}