package mock import ( "errors" "sync" "github.com/micro/go-micro/transport" ) type mockSocket struct { recv chan *transport.Message send chan *transport.Message // sock exit exit chan bool // listener exit lexit chan bool } type mockClient struct { *mockSocket opts transport.DialOptions } type mockListener struct { addr string exit chan bool conn chan *mockSocket opts transport.ListenOptions } type mockTransport struct { opts transport.Options sync.Mutex listeners map[string]*mockListener } func (ms *mockSocket) Recv(m *transport.Message) error { select { case <-ms.exit: return errors.New("server side connection closed") case <-ms.lexit: return errors.New("server side connection closed") case cm := <-ms.recv: *m = *cm } return nil } func (ms *mockSocket) Send(m *transport.Message) error { select { case <-ms.exit: return errors.New("client side connection closed") case <-ms.lexit: return errors.New("server side connection closed") case ms.send <- m: } return nil } func (ms *mockSocket) Close() error { close(ms.exit) return nil } func (m *mockListener) Addr() string { return m.addr } func (m *mockListener) Close() error { close(m.exit) return nil } func (m *mockListener) Accept(fn func(transport.Socket)) error { for { select { case <-m.exit: return nil case c := <-m.conn: go fn(&mockSocket{ lexit: make(chan bool), exit: c.exit, send: c.recv, recv: c.send, }) } } return nil } func (m *mockTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) { m.Lock() defer m.Unlock() listener, ok := m.listeners[addr] if !ok { return nil, errors.New("could not dial " + addr) } var options transport.DialOptions for _, o := range opts { o(&options) } client := &mockClient{ &mockSocket{ send: make(chan *transport.Message), recv: make(chan *transport.Message), exit: make(chan bool), lexit: listener.exit, }, options, } // pseudo connect select { case <-listener.exit: return nil, errors.New("connection error") case listener.conn <- client.mockSocket: } return client, nil } func (m *mockTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) { m.Lock() defer m.Unlock() if _, ok := m.listeners[addr]; ok { return nil, errors.New("already listening on " + addr) } var options transport.ListenOptions for _, o := range opts { o(&options) } listener := &mockListener{ opts: options, addr: addr, conn: make(chan *mockSocket), exit: make(chan bool), } m.listeners[addr] = listener return listener, nil } func (m *mockTransport) String() string { return "mock" } func NewTransport(opts ...transport.Option) transport.Transport { var options transport.Options for _, o := range opts { o(&options) } return &mockTransport{ opts: options, listeners: make(map[string]*mockListener), } }