1package memberlist 2 3import ( 4 "fmt" 5 "net" 6 "strconv" 7 "time" 8) 9 10// MockNetwork is used as a factory that produces MockTransport instances which 11// are uniquely addressed and wired up to talk to each other. 12type MockNetwork struct { 13 transports map[string]*MockTransport 14 port int 15} 16 17// NewTransport returns a new MockTransport with a unique address, wired up to 18// talk to the other transports in the MockNetwork. 19func (n *MockNetwork) NewTransport() *MockTransport { 20 n.port += 1 21 addr := fmt.Sprintf("127.0.0.1:%d", n.port) 22 transport := &MockTransport{ 23 net: n, 24 addr: &MockAddress{addr}, 25 packetCh: make(chan *Packet), 26 streamCh: make(chan net.Conn), 27 } 28 29 if n.transports == nil { 30 n.transports = make(map[string]*MockTransport) 31 } 32 n.transports[addr] = transport 33 return transport 34} 35 36// MockAddress is a wrapper which adds the net.Addr interface to our mock 37// address scheme. 38type MockAddress struct { 39 addr string 40} 41 42// See net.Addr. 43func (a *MockAddress) Network() string { 44 return "mock" 45} 46 47// See net.Addr. 48func (a *MockAddress) String() string { 49 return a.addr 50} 51 52// MockTransport directly plumbs messages to other transports its MockNetwork. 53type MockTransport struct { 54 net *MockNetwork 55 addr *MockAddress 56 packetCh chan *Packet 57 streamCh chan net.Conn 58} 59 60// See Transport. 61func (t *MockTransport) FinalAdvertiseAddr(string, int) (net.IP, int, error) { 62 host, portStr, err := net.SplitHostPort(t.addr.String()) 63 if err != nil { 64 return nil, 0, err 65 } 66 67 ip := net.ParseIP(host) 68 if ip == nil { 69 return nil, 0, fmt.Errorf("Failed to parse IP %q", host) 70 } 71 72 port, err := strconv.ParseInt(portStr, 10, 16) 73 if err != nil { 74 return nil, 0, err 75 } 76 77 return ip, int(port), nil 78} 79 80// See Transport. 81func (t *MockTransport) WriteTo(b []byte, addr string) (time.Time, error) { 82 dest, ok := t.net.transports[addr] 83 if !ok { 84 return time.Time{}, fmt.Errorf("No route to %q", addr) 85 } 86 87 now := time.Now() 88 dest.packetCh <- &Packet{ 89 Buf: b, 90 From: t.addr, 91 Timestamp: now, 92 } 93 return now, nil 94} 95 96// See Transport. 97func (t *MockTransport) PacketCh() <-chan *Packet { 98 return t.packetCh 99} 100 101// See Transport. 102func (t *MockTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) { 103 dest, ok := t.net.transports[addr] 104 if !ok { 105 return nil, fmt.Errorf("No route to %q", addr) 106 } 107 108 p1, p2 := net.Pipe() 109 dest.streamCh <- p1 110 return p2, nil 111} 112 113// See Transport. 114func (t *MockTransport) StreamCh() <-chan net.Conn { 115 return t.streamCh 116} 117 118// See Transport. 119func (t *MockTransport) Shutdown() error { 120 return nil 121} 122