Example #1
0
func runClientServerTests(t testing.TB, f func(*Client)) {
	var wg sync.WaitGroup

	ready1 := make(chan struct{})
	ready2 := make(chan struct{})

	uri := "tcp://127.0.0.1:1883"
	u, err := url.Parse(uri)
	require.NoError(t, err, "Error parsing URL")

	// Start listener
	wg.Add(1)
	go startService(t, u, &wg, ready1, ready2)

	<-ready1

	c := connectToServer(t, uri)
	if c == nil {
		return
	}

	defer topics.Unregister(c.svc.sess.ID())

	if f != nil {
		f(c)
	}

	c.Disconnect()

	close(ready2)

	wg.Wait()
}
Example #2
0
func startServiceN(t testing.TB, u *url.URL, wg *sync.WaitGroup, ready1, ready2 chan struct{}, cnt int) {
	defer wg.Done()

	topics.Unregister("mem")
	tp := topics.NewMemProvider()
	topics.Register("mem", tp)

	sessions.Unregister("mem")
	sp := sessions.NewMemProvider()
	sessions.Register("mem", sp)

	ln, err := net.Listen(u.Scheme, u.Host)
	require.NoError(t, err)
	defer ln.Close()

	close(ready1)

	svr := &Server{
		Authenticator: authenticator,
	}

	for i := 0; i < cnt; i++ {
		conn, err := ln.Accept()
		require.NoError(t, err)

		_, err = svr.handleConnection(conn)
		if authenticator == "mockFailure" {
			require.Error(t, err)
			return
		} else {
			require.NoError(t, err)
		}
	}

	<-ready2

	for _, svc := range svr.svcs {
		glog.Infof("Stopping service %d", svc.id)
		svc.stop()
	}

}
Example #3
0
// FIXME: The order of closing here causes panic sometimes. For example, if receiver
// calls this, and closes the buffers, somehow it causes buffer.go:476 to panid.
func (this *service) stop() {
	defer func() {
		// Let's recover from panic
		if r := recover(); r != nil {
			glog.Errorf("(%s) Recovering from panic: %v", this.cid(), r)
		}
	}()

	doit := atomic.CompareAndSwapInt64(&this.closed, 0, 1)
	if !doit {
		return
	}

	// Close quit channel, effectively telling all the goroutines it's time to quit
	if this.done != nil {
		glog.Debugf("(%s) closing this.done", this.cid())
		close(this.done)
	}

	// Close the network connection
	if this.conn != nil {
		glog.Debugf("(%s) closing this.conn", this.cid())
		this.conn.Close()
	}

	this.in.Close()
	this.out.Close()

	// Wait for all the goroutines to stop.
	this.wgStopped.Wait()

	glog.Debugf("(%s) Received %d bytes in %d messages.", this.cid(), this.inStat.bytes, this.inStat.msgs)
	glog.Debugf("(%s) Sent %d bytes in %d messages.", this.cid(), this.outStat.bytes, this.outStat.msgs)

	// Unsubscribe from all the topics for this client, only for the server side though
	if !this.client && this.sess != nil {
		topics, _, err := this.sess.Topics()
		if err != nil {
			glog.Errorf("(%s/%d): %v", this.cid(), this.id, err)
		} else {
			for _, t := range topics {
				if err := this.topicsMgr.Unsubscribe([]byte(t), &this.onpub); err != nil {
					glog.Errorf("(%s): Error unsubscribing topic %q: %v", this.cid(), t, err)
				}
			}
		}
	}

	// Publish will message if WillFlag is set. Server side only.
	if !this.client && this.sess.Cmsg.WillFlag() {
		glog.Infof("(%s) service/stop: connection unexpectedly closed. Sending Will.", this.cid())
		this.onPublish(this.sess.Will)
	}

	// Remove the client topics manager
	if this.client {
		topics.Unregister(this.sess.ID())
	}

	// Remove the session from session store if it's suppose to be clean session
	if this.sess.Cmsg.CleanSession() && this.sessMgr != nil {
		this.sessMgr.Del(this.sess.ID())
	}

	this.conn = nil
	this.in = nil
	this.out = nil
}
Example #4
0
func TestServiceWillDelivery(t *testing.T) {
	var wg sync.WaitGroup

	ready1 := make(chan struct{})
	ready2 := make(chan struct{})
	ready3 := make(chan struct{})
	subscribers := 3

	uri := "tcp://127.0.0.1:1883"
	u, err := url.Parse(uri)
	require.NoError(t, err, "Error parsing URL")

	// Start listener
	wg.Add(1)
	go startServiceN(t, u, &wg, ready1, ready2, subscribers)

	<-ready1

	c1 := connectToServer(t, uri)
	require.NotNil(t, c1)
	defer topics.Unregister(c1.svc.sess.ID())

	c2 := connectToServer(t, uri)
	require.NotNil(t, c2)
	defer topics.Unregister(c2.svc.sess.ID())

	c3 := connectToServer(t, uri)
	require.NotNil(t, c3)
	defer topics.Unregister(c3.svc.sess.ID())

	sub := message.NewSubscribeMessage()
	sub.AddTopic([]byte("will"), 1)

	subdone := int64(0)
	willdone := int64(0)

	c2.Subscribe(sub,
		func(msg, ack message.Message, err error) error {
			subs := atomic.AddInt64(&subdone, 1)
			if subs == int64(subscribers-1) {
				c1.Disconnect()
			}

			return nil
		},
		func(msg *message.PublishMessage) error {
			require.Equal(t, message.QosAtLeastOnce, msg.QoS())
			require.Equal(t, []byte("send me home"), msg.Payload())

			will := atomic.AddInt64(&willdone, 1)
			if will == int64(subscribers-1) {
				close(ready3)
			}

			return nil
		})

	c3.Subscribe(sub,
		func(msg, ack message.Message, err error) error {
			subs := atomic.AddInt64(&subdone, 1)
			if subs == int64(subscribers-1) {
				c1.Disconnect()
			}

			return nil
		},
		func(msg *message.PublishMessage) error {
			require.Equal(t, message.QosAtLeastOnce, msg.QoS())
			require.Equal(t, []byte("send me home"), msg.Payload())

			will := atomic.AddInt64(&willdone, 1)
			if will == int64(subscribers-1) {
				close(ready3)
			}

			return nil
		})

	select {
	case <-ready3:

	case <-time.After(time.Millisecond * 100):
		require.FailNow(t, "Test timed out")
	}

	c2.Disconnect()

	close(ready2)

	wg.Wait()
}