github.com/vmware/transport-go@v1.3.4/stompserver/stomp_connection_test.go (about)

     1  // Copyright 2019-2020 VMware, Inc.
     2  // SPDX-License-Identifier: BSD-2-Clause
     3  
     4  package stompserver
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"github.com/go-stomp/stomp/v3/frame"
    10  	"github.com/stretchr/testify/assert"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  type MockRawConnection struct {
    17  	connected       bool
    18  	incomingFrames  chan interface{}
    19  	lock            sync.Mutex
    20  	currentDeadline time.Time
    21  	sentFrames      []*frame.Frame
    22  	nextWriteErr    error
    23  	nextReadErr     error
    24  	writeWg         *sync.WaitGroup
    25  }
    26  
    27  func NewMockRawConnection() *MockRawConnection {
    28  	return &MockRawConnection{
    29  		connected:      true,
    30  		incomingFrames: make(chan interface{}),
    31  		sentFrames:     []*frame.Frame{},
    32  		nextWriteErr:   nil,
    33  	}
    34  }
    35  
    36  func (con *MockRawConnection) ReadFrame() (*frame.Frame, error) {
    37  	obj := <-con.incomingFrames
    38  
    39  	if obj == nil {
    40  		// heart-beat
    41  		return nil, nil
    42  	}
    43  
    44  	f, ok := obj.(*frame.Frame)
    45  	if ok {
    46  		return f, nil
    47  	}
    48  
    49  	return nil, obj.(error)
    50  }
    51  
    52  func (con *MockRawConnection) WriteFrame(frame *frame.Frame) error {
    53  	defer func() { con.nextWriteErr = nil }()
    54  	if con.nextWriteErr != nil {
    55  		return con.nextWriteErr
    56  	}
    57  
    58  	con.lock.Lock()
    59  	con.sentFrames = append(con.sentFrames, frame)
    60  	if con.writeWg != nil {
    61  		con.writeWg.Done()
    62  	}
    63  	con.lock.Unlock()
    64  	return nil
    65  }
    66  
    67  func (con *MockRawConnection) LastSentFrame() *frame.Frame {
    68  	return con.sentFrames[len(con.sentFrames)-1]
    69  }
    70  
    71  func (con *MockRawConnection) SetReadDeadline(t time.Time) {
    72  	con.lock.Lock()
    73  	con.currentDeadline = t
    74  	con.lock.Unlock()
    75  }
    76  
    77  func (con *MockRawConnection) getCurrentReadDeadline() time.Time {
    78  	con.lock.Lock()
    79  	defer con.lock.Unlock()
    80  	return con.currentDeadline
    81  }
    82  
    83  func (con *MockRawConnection) Close() error {
    84  	con.connected = false
    85  	return nil
    86  }
    87  
    88  func (con *MockRawConnection) SendConnectFrame() {
    89  	con.incomingFrames <- frame.New(
    90  		frame.CONNECT,
    91  		frame.AcceptVersion, "1.2")
    92  }
    93  
    94  func getTestStompConn(conf StompConfig, events chan *ConnEvent) (*stompConn, *MockRawConnection, chan *ConnEvent) {
    95  	if events == nil {
    96  		events = make(chan *ConnEvent, 1000)
    97  	}
    98  
    99  	rawConn := NewMockRawConnection()
   100  	return NewStompConn(rawConn, conf, events).(*stompConn), rawConn, events
   101  }
   102  
   103  func TestStompConn_Connect(t *testing.T) {
   104  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   105  
   106  	assert.NotNil(t, stompConn.GetId())
   107  
   108  	assert.Equal(t, stompConn.state, connecting)
   109  
   110  	rawConn.incomingFrames <- frame.New(frame.CONNECT, frame.AcceptVersion, "1.0,1.2,1.1,1.3")
   111  
   112  	e := <-events
   113  
   114  	assert.Equal(t, e.eventType, ConnectionEstablished)
   115  	assert.Equal(t, e.conn, stompConn)
   116  
   117  	assert.Equal(t, len(rawConn.sentFrames), 1)
   118  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED,
   119  		frame.Version, "1.2",
   120  		frame.HeartBeat, "0,0",
   121  		frame.Server, "stompServer/0.0.1"), true)
   122  
   123  	assert.Equal(t, stompConn.state, connected)
   124  }
   125  
   126  func TestStompConn_ConnectStomp10(t *testing.T) {
   127  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   128  
   129  	assert.Equal(t, stompConn.state, connecting)
   130  
   131  	rawConn.incomingFrames <- frame.New(frame.CONNECT, frame.AcceptVersion, "1.0")
   132  
   133  	e := <-events
   134  
   135  	assert.Equal(t, e.eventType, ConnectionClosed)
   136  	assert.Equal(t, e.conn, stompConn)
   137  
   138  	assert.Equal(t, len(rawConn.sentFrames), 1)
   139  
   140  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   141  		frame.Message, unsupportedStompVersionError.Error()), true)
   142  
   143  	assert.Equal(t, stompConn.state, closed)
   144  	assert.Equal(t, rawConn.connected, false)
   145  }
   146  
   147  func TestStompConn_ConnectInvalidStompVersion(t *testing.T) {
   148  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   149  
   150  	assert.Equal(t, stompConn.state, connecting)
   151  
   152  	rawConn.incomingFrames <- frame.New(frame.CONNECT, frame.AcceptVersion, "5.0")
   153  
   154  	e := <-events
   155  
   156  	assert.Equal(t, e.eventType, ConnectionClosed)
   157  	assert.Equal(t, e.conn, stompConn)
   158  
   159  	assert.Equal(t, len(rawConn.sentFrames), 1)
   160  
   161  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   162  		frame.Message, unsupportedStompVersionError.Error()), true)
   163  
   164  	assert.Equal(t, stompConn.state, closed)
   165  	assert.Equal(t, rawConn.connected, false)
   166  }
   167  
   168  func TestStompConn_ConnectWithReceiptHeader(t *testing.T) {
   169  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   170  
   171  	assert.Equal(t, stompConn.state, connecting)
   172  
   173  	rawConn.incomingFrames <- frame.New(frame.CONNECT,
   174  		frame.AcceptVersion, "1.2",
   175  		frame.Receipt, "receipt-id")
   176  
   177  	e := <-events
   178  
   179  	assert.Equal(t, e.eventType, ConnectionClosed)
   180  	assert.Equal(t, e.conn, stompConn)
   181  
   182  	assert.Equal(t, len(rawConn.sentFrames), 1)
   183  
   184  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   185  		frame.Message, invalidHeaderError.Error()), true)
   186  
   187  	assert.Equal(t, stompConn.state, closed)
   188  	assert.Equal(t, rawConn.connected, false)
   189  }
   190  
   191  func TestStompConn_ConnectMissingStompVersionHeader(t *testing.T) {
   192  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   193  
   194  	assert.Equal(t, stompConn.state, connecting)
   195  
   196  	rawConn.incomingFrames <- frame.New(frame.CONNECT)
   197  
   198  	e := <-events
   199  	assert.Equal(t, e.eventType, ConnectionClosed)
   200  	assert.Equal(t, e.conn, stompConn)
   201  
   202  	assert.Equal(t, len(rawConn.sentFrames), 1)
   203  
   204  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   205  		frame.Message, unsupportedStompVersionError.Error()), true)
   206  
   207  	assert.Equal(t, stompConn.state, closed)
   208  }
   209  
   210  func TestStompConn_ConnectInvalidHeartbeatHeader(t *testing.T) {
   211  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   212  
   213  	assert.Equal(t, stompConn.state, connecting)
   214  
   215  	rawConn.incomingFrames <- frame.New(frame.CONNECT,
   216  		frame.AcceptVersion, "1.2",
   217  		frame.HeartBeat, "12,asd")
   218  
   219  	e := <-events
   220  
   221  	assert.Equal(t, e.eventType, ConnectionClosed)
   222  	assert.Equal(t, e.conn, stompConn)
   223  
   224  	assert.Equal(t, len(rawConn.sentFrames), 1)
   225  
   226  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   227  		frame.Message, frame.ErrInvalidHeartBeat.Error()), true)
   228  
   229  	assert.Equal(t, stompConn.state, closed)
   230  	assert.Equal(t, rawConn.connected, false)
   231  }
   232  
   233  func TestStompConn_InvalidStompCommand(t *testing.T) {
   234  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   235  
   236  	assert.Equal(t, stompConn.state, connecting)
   237  
   238  	rawConn.incomingFrames <- frame.New("invalid-stomp-command",
   239  		frame.AcceptVersion, "1.2")
   240  
   241  	e := <-events
   242  
   243  	assert.Equal(t, e.eventType, ConnectionClosed)
   244  	assert.Equal(t, e.conn, stompConn)
   245  
   246  	assert.Equal(t, len(rawConn.sentFrames), 1)
   247  
   248  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   249  		frame.Message, unsupportedStompCommandError.Error()), true)
   250  
   251  	assert.Equal(t, stompConn.state, closed)
   252  	assert.Equal(t, rawConn.connected, false)
   253  }
   254  
   255  func TestStompConn_ConnectNoServerHeartbeat(t *testing.T) {
   256  	_, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   257  
   258  	rawConn.incomingFrames <- frame.New(
   259  		frame.CONNECT,
   260  		frame.AcceptVersion, "1.1,1.0",
   261  		frame.HeartBeat, "4000,4000")
   262  
   263  	<-events
   264  
   265  	assert.Equal(t, len(rawConn.sentFrames), 1)
   266  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED,
   267  		frame.Version, "1.1",
   268  		frame.HeartBeat, "0,0"), false)
   269  }
   270  
   271  func TestStompConn_ConnectServerHeartbeat(t *testing.T) {
   272  	_, rawConn, events := getTestStompConn(NewStompConfig(9999999991, []string{}), nil)
   273  	rawConn.incomingFrames <- frame.New(
   274  		frame.CONNECT,
   275  		frame.AcceptVersion, "1.1,1.0",
   276  		frame.HeartBeat, "4000,4000")
   277  
   278  	<-events
   279  
   280  	assert.Equal(t, len(rawConn.sentFrames), 1)
   281  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED,
   282  		frame.Version, "1.1",
   283  		frame.HeartBeat, "999999999,999999999"), false)
   284  }
   285  
   286  func TestStompConn_ConnectClientHeartbeat(t *testing.T) {
   287  	_, rawConn, events := getTestStompConn(NewStompConfig(7000, []string{}), nil)
   288  
   289  	rawConn.incomingFrames <- frame.New(
   290  		frame.CONNECT,
   291  		frame.AcceptVersion, "1.2",
   292  		frame.HeartBeat, "8000,9000")
   293  
   294  	<-events
   295  
   296  	assert.Equal(t, len(rawConn.sentFrames), 1)
   297  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED,
   298  		frame.HeartBeat, "9000,8000"), false)
   299  }
   300  
   301  func TestStompConn_ConnectWhenConnected(t *testing.T) {
   302  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   303  
   304  	rawConn.SendConnectFrame()
   305  
   306  	e := <-events
   307  	assert.Equal(t, e.eventType, ConnectionEstablished)
   308  
   309  	assert.Equal(t, len(rawConn.sentFrames), 1)
   310  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED), false)
   311  
   312  	rawConn.SendConnectFrame()
   313  
   314  	e = <-events
   315  	assert.Equal(t, e.eventType, ConnectionClosed)
   316  
   317  	assert.Equal(t, len(rawConn.sentFrames), 2)
   318  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.ERROR,
   319  		frame.Message, unexpectedStompCommandError.Error()), true)
   320  
   321  	assert.Equal(t, stompConn.state, closed)
   322  }
   323  
   324  func TestStompConn_SubscribeNotConnected(t *testing.T) {
   325  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   326  
   327  	rawConn.incomingFrames <- frame.New(
   328  		frame.SUBSCRIBE,
   329  		frame.Destination, "/topic/test")
   330  
   331  	e := <-events
   332  	assert.Equal(t, e.eventType, ConnectionClosed)
   333  	assert.Equal(t, e.conn, stompConn)
   334  
   335  	assert.Equal(t, len(rawConn.sentFrames), 1)
   336  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   337  		frame.Message, notConnectedStompError.Error()), true)
   338  	assert.Equal(t, stompConn.state, closed)
   339  }
   340  
   341  func TestStompConn_SubscribeMissingIdHeader(t *testing.T) {
   342  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   343  
   344  	rawConn.SendConnectFrame()
   345  
   346  	e := <-events
   347  	assert.Equal(t, e.eventType, ConnectionEstablished)
   348  
   349  	rawConn.incomingFrames <- frame.New(
   350  		frame.SUBSCRIBE,
   351  		frame.Destination, "/topic/test")
   352  
   353  	e = <-events
   354  	assert.Equal(t, e.eventType, ConnectionClosed)
   355  
   356  	assert.Equal(t, len(rawConn.sentFrames), 2)
   357  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.ERROR,
   358  		frame.Message, invalidSubscriptionError.Error()), true)
   359  	assert.Equal(t, stompConn.state, closed)
   360  }
   361  
   362  func TestStompConn_SubscribeMissingDestinationHeader(t *testing.T) {
   363  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   364  
   365  	rawConn.SendConnectFrame()
   366  
   367  	e := <-events
   368  	assert.Equal(t, e.eventType, ConnectionEstablished)
   369  
   370  	rawConn.incomingFrames <- frame.New(
   371  		frame.SUBSCRIBE,
   372  		frame.Id, "sub-id")
   373  
   374  	e = <-events
   375  	assert.Equal(t, e.eventType, ConnectionClosed)
   376  
   377  	assert.Equal(t, len(rawConn.sentFrames), 2)
   378  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.ERROR,
   379  		frame.Message, invalidFrameError.Error()), true)
   380  	assert.Equal(t, stompConn.state, closed)
   381  }
   382  
   383  func TestStompConn_Subscribe(t *testing.T) {
   384  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   385  
   386  	rawConn.SendConnectFrame()
   387  
   388  	e := <-events
   389  	assert.Equal(t, e.eventType, ConnectionEstablished)
   390  
   391  	assert.Equal(t, len(rawConn.sentFrames), 1)
   392  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED), false)
   393  
   394  	rawConn.incomingFrames <- frame.New(
   395  		frame.SUBSCRIBE,
   396  		frame.Id, "sub-id",
   397  		frame.Destination, "/topic/test")
   398  
   399  	e = <-events
   400  	assert.Equal(t, e.eventType, SubscribeToTopic)
   401  	assert.Equal(t, e.conn, stompConn)
   402  	assert.Equal(t, e.destination, "/topic/test")
   403  	assert.Equal(t, e.sub.destination, "/topic/test")
   404  	assert.Equal(t, e.sub.id, "sub-id")
   405  	assert.Equal(t, e.frame.Command, frame.SUBSCRIBE)
   406  
   407  	assert.Equal(t, len(rawConn.sentFrames), 1)
   408  	assert.Equal(t, stompConn.state, connected)
   409  
   410  	assert.Equal(t, stompConn.subscriptions["sub-id"].destination, "/topic/test")
   411  
   412  	// trigger send subscribe request with the same id
   413  	rawConn.incomingFrames <- frame.New(
   414  		frame.SUBSCRIBE,
   415  		frame.Id, "sub-id",
   416  		frame.Destination, "/topic/test")
   417  
   418  	// verify that there was no second subscription created for the same subscription id
   419  	assert.Equal(t, e.sub, stompConn.subscriptions["sub-id"])
   420  }
   421  
   422  func TestStompConn_SendNotConnected(t *testing.T) {
   423  	_, rawConn, events := getTestStompConn(NewStompConfig(0, []string{"/pub/"}), nil)
   424  
   425  	rawConn.incomingFrames <- frame.New(
   426  		frame.SEND,
   427  		frame.Destination, "/pub/test")
   428  
   429  	e := <-events
   430  	assert.Equal(t, e.eventType, ConnectionClosed)
   431  
   432  	assert.Equal(t, len(rawConn.sentFrames), 1)
   433  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   434  		frame.Message, notConnectedStompError.Error()), true)
   435  }
   436  
   437  func TestStompConn_SendMissingDestinationHeader(t *testing.T) {
   438  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{"/pub/"}), nil)
   439  
   440  	rawConn.SendConnectFrame()
   441  
   442  	e := <-events
   443  	assert.Equal(t, e.eventType, ConnectionEstablished)
   444  
   445  	rawConn.incomingFrames <- frame.New(
   446  		frame.SEND)
   447  
   448  	e = <-events
   449  	assert.Equal(t, e.eventType, ConnectionClosed)
   450  
   451  	assert.Equal(t, len(rawConn.sentFrames), 2)
   452  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.ERROR,
   453  		frame.Message, invalidFrameError.Error()), true)
   454  	assert.Equal(t, stompConn.state, closed)
   455  }
   456  
   457  func TestStompConn_Send_InvalidSend(t *testing.T) {
   458  	_, rawConn, events := getTestStompConn(NewStompConfig(0, []string{"/pub/"}), nil)
   459  
   460  	rawConn.SendConnectFrame()
   461  
   462  	e := <-events
   463  	assert.Equal(t, e.eventType, ConnectionEstablished)
   464  	assert.Equal(t, len(rawConn.sentFrames), 1)
   465  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED), false)
   466  
   467  	// try sending a frame to a topic channel directly not request channel
   468  	rawConn.incomingFrames <- frame.New(frame.SEND,
   469  		frame.Destination, "/topic/test")
   470  	e = <-events
   471  
   472  	assert.Equal(t, e.eventType, ConnectionClosed)
   473  	assert.Equal(t, len(rawConn.sentFrames), 2)
   474  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.ERROR,
   475  		frame.Message, invalidSendDestinationError.Error()), true)
   476  }
   477  
   478  func TestStompConn_Send(t *testing.T) {
   479  	_, rawConn, events := getTestStompConn(NewStompConfig(0, []string{"/pub/"}), nil)
   480  
   481  	rawConn.SendConnectFrame()
   482  
   483  	e := <-events
   484  	assert.Equal(t, e.eventType, ConnectionEstablished)
   485  
   486  	msgF := frame.New(frame.SEND, frame.Destination, "/pub/test")
   487  
   488  	rawConn.incomingFrames <- msgF
   489  
   490  	e = <-events
   491  	assert.Equal(t, e.eventType, IncomingMessage)
   492  	assert.Equal(t, e.frame, msgF)
   493  	assert.Equal(t, e.frame.Command, frame.MESSAGE)
   494  
   495  	rawConn.incomingFrames <- frame.New(frame.SEND,
   496  		frame.Destination, "/pub/test", frame.Receipt, "receipt-id")
   497  
   498  	e = <-events
   499  	assert.Equal(t, e.eventType, IncomingMessage)
   500  
   501  	assert.Equal(t, len(rawConn.sentFrames), 2)
   502  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.RECEIPT,
   503  		frame.ReceiptId, "receipt-id"), true)
   504  }
   505  
   506  func TestStompConn_UnsubscribeNotConnected(t *testing.T) {
   507  	_, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   508  
   509  	rawConn.incomingFrames <- frame.New(
   510  		frame.UNSUBSCRIBE,
   511  		frame.Destination, "/topic/test")
   512  
   513  	e := <-events
   514  	assert.Equal(t, e.eventType, ConnectionClosed)
   515  
   516  	assert.Equal(t, len(rawConn.sentFrames), 1)
   517  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   518  		frame.Message, notConnectedStompError.Error()), true)
   519  }
   520  
   521  func TestStompConn_UnsubscribeMissingIdHeader(t *testing.T) {
   522  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   523  
   524  	rawConn.SendConnectFrame()
   525  
   526  	e := <-events
   527  	assert.Equal(t, e.eventType, ConnectionEstablished)
   528  
   529  	rawConn.incomingFrames <- frame.New(
   530  		frame.UNSUBSCRIBE)
   531  
   532  	e = <-events
   533  	assert.Equal(t, e.eventType, ConnectionClosed)
   534  
   535  	assert.Equal(t, len(rawConn.sentFrames), 2)
   536  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.ERROR,
   537  		frame.Message, invalidSubscriptionError.Error()), true)
   538  	assert.Equal(t, stompConn.state, closed)
   539  }
   540  
   541  func TestStompConn_Unsubscribe(t *testing.T) {
   542  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   543  
   544  	rawConn.SendConnectFrame()
   545  
   546  	e := <-events
   547  	assert.Equal(t, e.eventType, ConnectionEstablished)
   548  
   549  	rawConn.incomingFrames <- frame.New(
   550  		frame.UNSUBSCRIBE,
   551  		frame.Id, "invalid-sub-id",
   552  		frame.Receipt, "receipt-id")
   553  
   554  	rawConn.incomingFrames <- frame.New(
   555  		frame.SUBSCRIBE,
   556  		frame.Id, "sub-id",
   557  		frame.Destination, "/topic/test")
   558  
   559  	e = <-events
   560  	assert.Equal(t, e.eventType, SubscribeToTopic)
   561  
   562  	assert.Equal(t, len(rawConn.sentFrames), 2)
   563  	verifyFrame(t, rawConn.sentFrames[1], frame.New(frame.RECEIPT,
   564  		frame.ReceiptId, "receipt-id"), true)
   565  
   566  	rawConn.incomingFrames <- frame.New(
   567  		frame.UNSUBSCRIBE,
   568  		frame.Id, "sub-id")
   569  
   570  	e = <-events
   571  	assert.Equal(t, e.eventType, UnsubscribeFromTopic)
   572  	assert.Equal(t, e.conn, stompConn)
   573  	assert.Equal(t, e.destination, "/topic/test")
   574  	assert.Equal(t, e.sub.destination, "/topic/test")
   575  	assert.Equal(t, e.sub.id, "sub-id")
   576  
   577  	assert.Equal(t, len(stompConn.subscriptions), 0)
   578  	assert.Equal(t, stompConn.state, connected)
   579  }
   580  
   581  func TestStompConn_DisconnectNotConnected(t *testing.T) {
   582  	_, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   583  
   584  	rawConn.incomingFrames <- frame.New(
   585  		frame.DISCONNECT)
   586  
   587  	e := <-events
   588  	assert.Equal(t, e.eventType, ConnectionClosed)
   589  
   590  	assert.Equal(t, len(rawConn.sentFrames), 1)
   591  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.ERROR,
   592  		frame.Message, notConnectedStompError.Error()), true)
   593  }
   594  
   595  func TestStompConn_Disconnect(t *testing.T) {
   596  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   597  
   598  	rawConn.SendConnectFrame()
   599  
   600  	e := <-events
   601  	assert.Equal(t, e.eventType, ConnectionEstablished)
   602  
   603  	assert.Equal(t, len(rawConn.sentFrames), 1)
   604  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED), false)
   605  
   606  	rawConn.incomingFrames <- frame.New(
   607  		frame.DISCONNECT)
   608  
   609  	e = <-events
   610  	assert.Equal(t, e.eventType, ConnectionClosed)
   611  
   612  	assert.Equal(t, len(rawConn.sentFrames), 1)
   613  	assert.Equal(t, stompConn.state, closed)
   614  }
   615  
   616  func TestStompConn_DisconnectWithReceipt(t *testing.T) {
   617  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   618  
   619  	rawConn.SendConnectFrame()
   620  
   621  	e := <-events
   622  	assert.Equal(t, e.eventType, ConnectionEstablished)
   623  
   624  	assert.Equal(t, len(rawConn.sentFrames), 1)
   625  	verifyFrame(t, rawConn.sentFrames[0], frame.New(frame.CONNECTED), false)
   626  
   627  	rawConn.incomingFrames <- frame.New(
   628  		frame.DISCONNECT,
   629  		frame.Receipt, "test-receipt")
   630  
   631  	e = <-events
   632  	assert.Equal(t, e.eventType, ConnectionClosed)
   633  
   634  	assert.Equal(t, len(rawConn.sentFrames), 2)
   635  	verifyFrame(t, rawConn.sentFrames[1],
   636  		frame.New(frame.RECEIPT, frame.ReceiptId, "test-receipt"), true)
   637  	assert.Equal(t, stompConn.state, closed)
   638  }
   639  
   640  func TestStompConn_Close(t *testing.T) {
   641  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   642  
   643  	stompConn.Close()
   644  
   645  	e := <-events
   646  	assert.Equal(t, e.eventType, ConnectionClosed)
   647  
   648  	assert.Equal(t, len(rawConn.sentFrames), 0)
   649  	assert.Equal(t, stompConn.state, closed)
   650  	assert.Equal(t, rawConn.connected, false)
   651  }
   652  
   653  func TestStompConn_SendFrameToSubscription(t *testing.T) {
   654  	stompConn, rawConn, _ := getTestStompConn(NewStompConfig(0, []string{}), nil)
   655  
   656  	sub := &subscription{
   657  		id:          "sub-id",
   658  		destination: "/topic/test",
   659  	}
   660  
   661  	f := frame.New(frame.MESSAGE, frame.Destination, "/topic/test")
   662  
   663  	rawConn.writeWg = &sync.WaitGroup{}
   664  	rawConn.writeWg.Add(1)
   665  
   666  	stompConn.SendFrameToSubscription(f, sub)
   667  
   668  	rawConn.writeWg.Wait()
   669  	assert.Equal(t, len(rawConn.sentFrames), 1)
   670  
   671  	assert.Equal(t, rawConn.sentFrames[0], f)
   672  	assert.Equal(t, rawConn.sentFrames[0].Header.Get(frame.MessageId), "1")
   673  
   674  	rawConn.writeWg.Add(1)
   675  	stompConn.SendFrameToSubscription(f, sub)
   676  	rawConn.writeWg.Wait()
   677  	assert.Equal(t, len(rawConn.sentFrames), 2)
   678  	assert.Equal(t, rawConn.sentFrames[1].Header.Get(frame.MessageId), "2")
   679  
   680  	rawConn.writeWg.Add(50)
   681  	for i := 0; i < 50; i++ {
   682  		go stompConn.SendFrameToSubscription(f.Clone(), sub)
   683  	}
   684  
   685  	rawConn.writeWg.Wait()
   686  	assert.Equal(t, len(rawConn.sentFrames), 52)
   687  }
   688  
   689  func TestStompConn_SendErrorFrameToSubscription(t *testing.T) {
   690  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   691  
   692  	sub := &subscription{
   693  		id:          "sub-id",
   694  		destination: "/topic/test",
   695  	}
   696  
   697  	f := frame.New(frame.ERROR, frame.Destination, "/topic/test")
   698  	stompConn.SendFrameToSubscription(f, sub)
   699  
   700  	e := <-events
   701  
   702  	assert.Equal(t, e.eventType, ConnectionClosed)
   703  	assert.Equal(t, len(rawConn.sentFrames), 1)
   704  }
   705  
   706  func TestStompConn_ReadError(t *testing.T) {
   707  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   708  
   709  	rawConn.incomingFrames <- errors.New("read error")
   710  
   711  	e := <-events
   712  	assert.Equal(t, e.eventType, ConnectionClosed)
   713  
   714  	assert.Equal(t, len(rawConn.sentFrames), 0)
   715  	assert.Equal(t, stompConn.state, closed)
   716  }
   717  
   718  func TestStompConn_WriteErrorDuringConnect(t *testing.T) {
   719  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{}), nil)
   720  
   721  	rawConn.nextWriteErr = errors.New("write error")
   722  	rawConn.SendConnectFrame()
   723  
   724  	e := <-events
   725  	assert.Equal(t, e.eventType, ConnectionClosed)
   726  	assert.Equal(t, stompConn.state, closed)
   727  }
   728  
   729  func TestStompConn_WriteErrorDuringSend(t *testing.T) {
   730  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(0, []string{"/pub/"}), nil)
   731  
   732  	rawConn.SendConnectFrame()
   733  
   734  	e := <-events
   735  	assert.Equal(t, e.eventType, ConnectionEstablished)
   736  
   737  	rawConn.nextWriteErr = errors.New("write error")
   738  	rawConn.incomingFrames <- frame.New(
   739  		frame.SEND,
   740  		frame.Destination, "/pub/",
   741  		frame.Receipt, "receipt-id")
   742  
   743  	e = <-events
   744  
   745  	assert.Equal(t, e.eventType, ConnectionClosed)
   746  	assert.Equal(t, stompConn.state, closed)
   747  }
   748  
   749  func TestStompConn_SetReadDeadline(t *testing.T) {
   750  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(20000, []string{}), nil)
   751  
   752  	infiniteTimeout := time.Time{}
   753  
   754  	assert.Equal(t, rawConn.getCurrentReadDeadline(), infiniteTimeout)
   755  
   756  	rawConn.incomingFrames <- frame.New(
   757  		frame.CONNECT,
   758  		frame.AcceptVersion, "1.2",
   759  		frame.HeartBeat, "200,200")
   760  
   761  	<-events
   762  
   763  	// verify timeout is set to 20 seconds
   764  	assert.Equal(t, stompConn.readTimeoutMs, int64(20000))
   765  
   766  	rawConn.incomingFrames <- nil
   767  	rawConn.incomingFrames <- nil
   768  
   769  	diff := rawConn.getCurrentReadDeadline().Sub(time.Now())
   770  
   771  	// verify the read deadline for the connection is
   772  	// between 15 and 21 seconds
   773  	assert.Greater(t, diff.Seconds(), float64(15))
   774  	assert.Greater(t, float64(21), diff.Seconds())
   775  }
   776  
   777  func TestStompConn_WriteHeartbeat(t *testing.T) {
   778  	stompConn, rawConn, events := getTestStompConn(NewStompConfig(100, []string{}), nil)
   779  
   780  	rawConn.incomingFrames <- frame.New(
   781  		frame.CONNECT,
   782  		frame.AcceptVersion, "1.2",
   783  		frame.HeartBeat, "50,50")
   784  
   785  	<-events
   786  
   787  	rawConn.lock.Lock()
   788  	rawConn.writeWg = new(sync.WaitGroup)
   789  	rawConn.writeWg.Add(2)
   790  	rawConn.lock.Unlock()
   791  
   792  	rawConn.writeWg.Wait()
   793  
   794  	// verify the last frame is heartbeat (nil)
   795  	rawConn.lock.Lock()
   796  	assert.Nil(t, rawConn.LastSentFrame())
   797  	rawConn.lock.Unlock()
   798  
   799  	rawConn.writeWg.Add(3)
   800  	stompConn.SendFrameToSubscription(frame.New(frame.MESSAGE), &subscription{id: "sub-1"})
   801  	rawConn.writeWg.Wait()
   802  
   803  	// verify the last frame is heartbeat (nil)
   804  	rawConn.lock.Lock()
   805  	rawConn.writeWg = nil
   806  	assert.Nil(t, rawConn.LastSentFrame())
   807  	rawConn.lock.Unlock()
   808  }
   809  
   810  func verifyFrame(t *testing.T, actualFrame *frame.Frame, expectedFrame *frame.Frame, exactHeaderMatch bool) {
   811  	assert.Equal(t, expectedFrame.Command, actualFrame.Command)
   812  	if exactHeaderMatch {
   813  		assert.Equal(t, expectedFrame.Header.Len(), actualFrame.Header.Len())
   814  	}
   815  
   816  	for i := 0; i < expectedFrame.Header.Len(); i++ {
   817  		key, value := expectedFrame.Header.GetAt(i)
   818  		assert.Equal(t, actualFrame.Header.Get(key), value)
   819  	}
   820  }
   821  
   822  func printFrame(f *frame.Frame) {
   823  	if f == nil {
   824  		fmt.Println("HEARTBEAT FRAME")
   825  	} else {
   826  		fmt.Println("FRAME:", f.Command)
   827  		for i := 0; i < f.Header.Len(); i++ {
   828  			key, value := f.Header.GetAt(i)
   829  			fmt.Println(key+":", value)
   830  		}
   831  		fmt.Println("BODY:", string(f.Body))
   832  	}
   833  }