gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/connection_test.go (about)

     1  package rethinkdb
     2  
     3  import (
     4  	"encoding/binary"
     5  	"encoding/json"
     6  	"github.com/opentracing/opentracing-go"
     7  	"github.com/opentracing/opentracing-go/mocktracer"
     8  	"github.com/stretchr/testify/mock"
     9  	"golang.org/x/net/context"
    10  	test "gopkg.in/check.v1"
    11  	p "gopkg.in/rethinkdb/rethinkdb-go.v6/ql2"
    12  	"io"
    13  	"sync"
    14  	"time"
    15  )
    16  
    17  func runConnection(c *Connection) <-chan struct{} {
    18  	wg := &sync.WaitGroup{}
    19  	wg.Add(2)
    20  	go func() {
    21  		c.readSocket()
    22  		wg.Done()
    23  	}()
    24  	go func() {
    25  		c.processResponses()
    26  		wg.Done()
    27  	}()
    28  
    29  	doneChan := make(chan struct{})
    30  	go func() {
    31  		wg.Wait()
    32  		close(doneChan)
    33  	}()
    34  	return doneChan
    35  }
    36  
    37  type ConnectionSuite struct{}
    38  
    39  var _ = test.Suite(&ConnectionSuite{})
    40  
    41  func (s *ConnectionSuite) TestConnection_Query_Ok(c *test.C) {
    42  	ctx := context.Background()
    43  	token := int64(1)
    44  	q := testQuery(DB("db").Table("table").Get("id"))
    45  	writeData := serializeQuery(token, q)
    46  	respData := serializeAtomResponse()
    47  	header := respHeader(token, respData)
    48  
    49  	conn := &connMock{}
    50  	conn.On("Write", writeData).Return(len(writeData), nil, nil)
    51  	conn.On("Read", respHeaderLen).Return(header, respHeaderLen, nil, nil)
    52  	conn.On("Read", len(respData)).Return(respData, len(respData), nil, nil)
    53  	conn.On("Close").Return(nil)
    54  
    55  	connection := newConnection(conn, "addr", &ConnectOpts{})
    56  	closed := runConnection(connection)
    57  	response, cursor, err := connection.Query(ctx, q)
    58  	connection.Close()
    59  	<-closed
    60  
    61  	c.Assert(response, test.NotNil)
    62  	c.Assert(response.Token, test.Equals, token)
    63  	c.Assert(response.Type, test.Equals, p.Response_SUCCESS_ATOM)
    64  	c.Assert(response.Responses, test.HasLen, 1)
    65  	c.Assert(response.Responses[0], test.DeepEquals, json.RawMessage([]byte(`"response"`)))
    66  	c.Assert(cursor, test.NotNil)
    67  	c.Assert(cursor.token, test.Equals, token)
    68  	c.Assert(cursor.conn, test.Equals, connection)
    69  	c.Assert(cursor.ctx, test.Equals, ctx)
    70  	c.Assert(cursor.responses, test.DeepEquals, response.Responses)
    71  	c.Assert(err, test.IsNil)
    72  	conn.AssertExpectations(c)
    73  }
    74  
    75  func (s *ConnectionSuite) TestConnection_Query_DefaultDBOk(c *test.C) {
    76  	ctx := context.Background()
    77  	token := int64(1)
    78  	q := testQuery(Table("table").Get("id"))
    79  	q2 := q
    80  	q2.Opts["db"], _ = DB("db").Build()
    81  	writeData := serializeQuery(token, q2)
    82  	respData := serializeAtomResponse()
    83  	header := respHeader(token, respData)
    84  
    85  	conn := &connMock{}
    86  	conn.On("Write", writeData).Return(len(writeData), nil, nil)
    87  	conn.On("Read", respHeaderLen).Return(header, respHeaderLen, nil, nil)
    88  	conn.On("Read", len(respData)).Return(respData, len(respData), nil, nil)
    89  	conn.On("Close").Return(nil)
    90  
    91  	connection := newConnection(conn, "addr", &ConnectOpts{Database: "db"})
    92  	done := runConnection(connection)
    93  	response, cursor, err := connection.Query(ctx, q)
    94  	connection.Close()
    95  	<-done
    96  
    97  	c.Assert(response, test.NotNil)
    98  	c.Assert(response.Token, test.Equals, token)
    99  	c.Assert(response.Type, test.Equals, p.Response_SUCCESS_ATOM)
   100  	c.Assert(response.Responses, test.HasLen, 1)
   101  	c.Assert(response.Responses[0], test.DeepEquals, json.RawMessage([]byte(`"response"`)))
   102  	c.Assert(cursor, test.NotNil)
   103  	c.Assert(cursor.token, test.Equals, token)
   104  	c.Assert(cursor.conn, test.Equals, connection)
   105  	c.Assert(cursor.ctx, test.Equals, ctx)
   106  	c.Assert(cursor.responses, test.DeepEquals, response.Responses)
   107  	c.Assert(err, test.IsNil)
   108  	conn.AssertExpectations(c)
   109  }
   110  
   111  func (s *ConnectionSuite) TestConnection_Query_Nil(c *test.C) {
   112  	response, cursor, err := (*Connection)(nil).Query(nil, Query{})
   113  	c.Assert(err, test.Equals, ErrConnectionClosed)
   114  	c.Assert(response, test.IsNil)
   115  	c.Assert(cursor, test.IsNil)
   116  }
   117  
   118  func (s *ConnectionSuite) TestConnection_Query_NilConn(c *test.C) {
   119  	connection := newConnection(nil, "addr", &ConnectOpts{Database: "db"})
   120  	response, cursor, err := connection.Query(nil, Query{})
   121  	c.Assert(err, test.Equals, ErrConnectionClosed)
   122  	c.Assert(response, test.IsNil)
   123  	c.Assert(cursor, test.IsNil)
   124  }
   125  
   126  func (s *ConnectionSuite) TestConnection_Query_SendFail(c *test.C) {
   127  	ctx := context.Background()
   128  	token := int64(1)
   129  	q := testQuery(DB("db").Table("table").Get("id"))
   130  	writeData := serializeQuery(token, q)
   131  
   132  	conn := &connMock{}
   133  	conn.On("Write", writeData).Return(0, io.EOF, nil)
   134  
   135  	connection := newConnection(conn, "addr", &ConnectOpts{})
   136  	response, cursor, err := connection.Query(ctx, q)
   137  
   138  	c.Assert(response, test.IsNil)
   139  	c.Assert(cursor, test.IsNil)
   140  	c.Assert(err, test.Equals, RQLConnectionError{rqlError(io.EOF.Error())})
   141  	conn.AssertExpectations(c)
   142  }
   143  
   144  func (s *ConnectionSuite) TestConnection_Query_NoReplyOk(c *test.C) {
   145  	token := int64(1)
   146  	q := testQuery(DB("db").Table("table").Get("id"))
   147  	q.Opts["noreply"] = true
   148  	writeData := serializeQuery(token, q)
   149  	respData := serializeAtomResponse()
   150  	header := respHeader(token, respData)
   151  
   152  	conn := &connMock{}
   153  	conn.On("Write", writeData).Return(len(writeData), nil, nil)
   154  	conn.On("Read", respHeaderLen).Return(header, respHeaderLen, nil, nil)
   155  	conn.On("Read", len(respData)).Return(respData, len(respData), nil, nil)
   156  	conn.On("Close").Return(nil)
   157  
   158  	connection := newConnection(conn, "addr", &ConnectOpts{})
   159  	done := runConnection(connection)
   160  	response, cursor, err := connection.Query(nil, q)
   161  	connection.Close()
   162  	<-done
   163  
   164  	c.Assert(response, test.IsNil)
   165  	c.Assert(cursor, test.IsNil)
   166  	c.Assert(err, test.IsNil)
   167  	conn.AssertExpectations(c)
   168  }
   169  
   170  func (s *ConnectionSuite) TestConnection_Query_TimeoutWrite(c *test.C) {
   171  	ctx, cancel := context.WithCancel(context.Background())
   172  	token := int64(1)
   173  	q := testQuery(DB("db").Table("table").Get("id"))
   174  	writeData := serializeQuery(token, q)
   175  	stopData := serializeQuery(token, newStopQuery(token))
   176  
   177  	conn := &connMock{}
   178  	conn.On("Write", writeData).Return(len(writeData), nil, nil)
   179  	conn.On("Write", stopData).Return(len(stopData), nil, nil)
   180  
   181  	connection := newConnection(conn, "addr", &ConnectOpts{ReadTimeout: time.Millisecond, WriteTimeout: time.Millisecond})
   182  	connection.readRequestsChan = make(chan tokenAndPromise, 0)
   183  	cancel()
   184  	response, cursor, err := connection.Query(ctx, q)
   185  
   186  	c.Assert(response, test.IsNil)
   187  	c.Assert(cursor, test.IsNil)
   188  	c.Assert(err, test.Equals, ErrQueryTimeout)
   189  	conn.AssertExpectations(c)
   190  }
   191  
   192  func (s *ConnectionSuite) TestConnection_Query_TimeoutRead(c *test.C) {
   193  	ctx, _ := context.WithTimeout(context.Background(), 5*time.Millisecond)
   194  	token := int64(1)
   195  	q := testQuery(DB("db").Table("table").Get("id"))
   196  	writeData := serializeQuery(token, q)
   197  	stopData := serializeQuery(token, newStopQuery(token))
   198  
   199  	conn := &connMock{}
   200  	conn.On("Write", writeData).Return(len(writeData), nil, 10*time.Millisecond)
   201  	conn.On("Write", stopData).Return(len(stopData), nil, nil)
   202  
   203  	connection := newConnection(conn, "addr", &ConnectOpts{ReadTimeout: time.Millisecond, WriteTimeout: time.Millisecond})
   204  	response, cursor, err := connection.Query(ctx, q)
   205  
   206  	c.Assert(response, test.IsNil)
   207  	c.Assert(cursor, test.IsNil)
   208  	c.Assert(err, test.Equals, ErrQueryTimeout)
   209  	conn.AssertExpectations(c)
   210  }
   211  
   212  func (s *ConnectionSuite) TestConnection_Query_SendFailTracing(c *test.C) {
   213  	tracer := mocktracer.New()
   214  	rootSpan := tracer.StartSpan("root")
   215  	ctx := opentracing.ContextWithSpan(context.Background(), rootSpan)
   216  	token := int64(1)
   217  	q := testQuery(DB("db").Table("table").Get("id"))
   218  	writeData := serializeQuery(token, q)
   219  
   220  	conn := &connMock{}
   221  	conn.On("Write", writeData).Return(0, io.EOF, nil)
   222  
   223  	connection := newConnection(conn, "addr", &ConnectOpts{UseOpentracing: true})
   224  	response, cursor, err := connection.Query(ctx, q)
   225  
   226  	c.Assert(response, test.IsNil)
   227  	c.Assert(cursor, test.IsNil)
   228  	c.Assert(err, test.Equals, RQLConnectionError{rqlError(io.EOF.Error())})
   229  	conn.AssertExpectations(c)
   230  	c.Assert(tracer.FinishedSpans(), test.HasLen, 2)
   231  }
   232  
   233  func (s *ConnectionSuite) TestConnection_processResponses_SocketErr(c *test.C) {
   234  	promise1 := make(chan responseAndCursor, 1)
   235  	promise2 := make(chan responseAndCursor, 1)
   236  	promise3 := make(chan responseAndCursor, 1)
   237  
   238  	conn := &connMock{}
   239  	connection := newConnection(conn, "addr", &ConnectOpts{})
   240  
   241  	conn.On("Close").Return(nil).Run(func(args mock.Arguments) {
   242  		close(connection.responseChan)
   243  	})
   244  
   245  	done := make(chan struct{})
   246  	go func() {
   247  		connection.processResponses()
   248  		close(done)
   249  	}()
   250  
   251  	connection.readRequestsChan <- tokenAndPromise{query: &Query{Token: 1}, promise: promise1}
   252  	connection.readRequestsChan <- tokenAndPromise{query: &Query{Token: 2}, promise: promise2}
   253  	connection.readRequestsChan <- tokenAndPromise{query: &Query{Token: 2}, promise: promise3}
   254  	time.Sleep(5 * time.Millisecond)
   255  	connection.responseChan <- responseAndError{err: io.EOF}
   256  	<-done
   257  
   258  	select {
   259  	case f := <-promise1:
   260  		c.Assert(f.err, test.Equals, io.EOF)
   261  		c.Assert(f.response, test.IsNil)
   262  	default:
   263  		c.Fail()
   264  	}
   265  	select {
   266  	case f := <-promise2:
   267  		c.Assert(f.err, test.Equals, io.EOF)
   268  		c.Assert(f.response, test.IsNil)
   269  	default:
   270  		c.Fail()
   271  	}
   272  	select {
   273  	case f := <-promise3:
   274  		c.Assert(f.err, test.Equals, io.EOF)
   275  		c.Assert(f.response, test.IsNil)
   276  	default:
   277  		c.Fail()
   278  	}
   279  	conn.AssertExpectations(c)
   280  }
   281  
   282  func (s *ConnectionSuite) TestConnection_processResponses_StopOk(c *test.C) {
   283  	promise1 := make(chan responseAndCursor, 1)
   284  
   285  	connection := newConnection(nil, "addr", &ConnectOpts{})
   286  
   287  	done := make(chan struct{})
   288  	go func() {
   289  		connection.processResponses()
   290  		close(done)
   291  	}()
   292  
   293  	connection.readRequestsChan <- tokenAndPromise{query: &Query{Token: 1}, promise: promise1}
   294  	time.Sleep(5 * time.Millisecond)
   295  	close(connection.responseChan)
   296  	<-done
   297  
   298  	select {
   299  	case f := <-promise1:
   300  		c.Assert(f.err, test.Equals, ErrConnectionClosed)
   301  		c.Assert(f.response, test.IsNil)
   302  	default:
   303  		c.Fail()
   304  	}
   305  }
   306  
   307  func (s *ConnectionSuite) TestConnection_processResponses_ResponseFirst(c *test.C) {
   308  	promise1 := make(chan responseAndCursor, 1)
   309  	response1 := &Response{Token: 1, Type: p.Response_RUNTIME_ERROR, ErrorType: p.Response_INTERNAL}
   310  
   311  	conn := &connMock{}
   312  	conn.On("Close").Return(nil)
   313  
   314  	connection := newConnection(conn, "addr", &ConnectOpts{})
   315  
   316  	go connection.processResponses()
   317  
   318  	connection.responseChan <- responseAndError{response: response1}
   319  	time.Sleep(5 * time.Millisecond)
   320  	connection.readRequestsChan <- tokenAndPromise{query: &Query{Token: 1}, promise: promise1}
   321  	time.Sleep(5 * time.Millisecond)
   322  	connection.Close()
   323  	time.Sleep(5 * time.Millisecond)
   324  
   325  	select {
   326  	case f := <-promise1:
   327  		c.Assert(f.err, test.FitsTypeOf, RQLInternalError{})
   328  		c.Assert(f.response, test.Equals, response1)
   329  		c.Assert(f.cursor, test.IsNil)
   330  	default:
   331  		c.Fail()
   332  	}
   333  	conn.AssertExpectations(c)
   334  }
   335  
   336  func (s *ConnectionSuite) TestConnection_readResponse_TimeoutHeader(c *test.C) {
   337  	timeout := time.Second
   338  
   339  	conn := &connMock{}
   340  	conn.On("Read", respHeaderLen).Return(nil, 0, io.EOF, nil)
   341  
   342  	connection := newConnection(conn, "addr", &ConnectOpts{ReadTimeout: timeout})
   343  
   344  	response, err := connection.readResponse()
   345  
   346  	c.Assert(response, test.IsNil)
   347  	c.Assert(err, test.FitsTypeOf, RQLConnectionError{})
   348  	c.Assert(connection.isBad(), test.Equals, true)
   349  	conn.AssertExpectations(c)
   350  }
   351  
   352  func (s *ConnectionSuite) TestConnection_readResponse_BodySocketErr(c *test.C) {
   353  	token := int64(5)
   354  	respData := serializeAtomResponse()
   355  	header := respHeader(token, respData)
   356  
   357  	conn := &connMock{}
   358  	conn.On("Read", respHeaderLen).Return(header, len(header), nil, nil)
   359  	conn.On("Read", len(respData)).Return(nil, 0, io.EOF, nil)
   360  
   361  	connection := newConnection(conn, "addr", &ConnectOpts{})
   362  
   363  	response, err := connection.readResponse()
   364  
   365  	c.Assert(response, test.IsNil)
   366  	c.Assert(err, test.FitsTypeOf, RQLConnectionError{})
   367  	c.Assert(connection.isBad(), test.Equals, true)
   368  	conn.AssertExpectations(c)
   369  }
   370  
   371  func (s *ConnectionSuite) TestConnection_readResponse_BodyUnmarshalErr(c *test.C) {
   372  	token := int64(5)
   373  	respData := serializeAtomResponse()
   374  	header := respHeader(token, respData)
   375  
   376  	conn := &connMock{}
   377  	conn.On("Read", respHeaderLen).Return(header, len(header), nil, nil)
   378  	conn.On("Read", len(respData)).Return(make([]byte, len(respData)), len(respData), nil, nil)
   379  
   380  	connection := newConnection(conn, "addr", &ConnectOpts{})
   381  
   382  	response, err := connection.readResponse()
   383  
   384  	c.Assert(response, test.IsNil)
   385  	c.Assert(err, test.FitsTypeOf, RQLDriverError{})
   386  	c.Assert(connection.isBad(), test.Equals, true)
   387  	conn.AssertExpectations(c)
   388  }
   389  
   390  func (s *ConnectionSuite) TestConnection_processResponse_ClientErrOk(c *test.C) {
   391  	ctx := context.Background()
   392  	token := int64(3)
   393  	q := Query{Token: token}
   394  	response := &Response{Token: token, Type: p.Response_CLIENT_ERROR}
   395  
   396  	connection := newConnection(nil, "addr", &ConnectOpts{})
   397  
   398  	resp, cursor, err := connection.processResponse(ctx, q, response, nil)
   399  
   400  	c.Assert(resp, test.Equals, response)
   401  	c.Assert(cursor, test.IsNil)
   402  	c.Assert(err, test.FitsTypeOf, RQLClientError{})
   403  }
   404  
   405  func (s *ConnectionSuite) TestConnection_processResponse_CompileErrOk(c *test.C) {
   406  	ctx := context.Background()
   407  	token := int64(3)
   408  	q := Query{Token: token}
   409  	response := &Response{Token: token, Type: p.Response_COMPILE_ERROR}
   410  
   411  	connection := newConnection(nil, "addr", &ConnectOpts{})
   412  
   413  	resp, cursor, err := connection.processResponse(ctx, q, response, nil)
   414  
   415  	c.Assert(resp, test.Equals, response)
   416  	c.Assert(cursor, test.IsNil)
   417  	c.Assert(err, test.FitsTypeOf, RQLCompileError{})
   418  }
   419  
   420  func (s *ConnectionSuite) TestConnection_processResponse_RuntimeErrOk(c *test.C) {
   421  	tracer := mocktracer.New()
   422  	rootSpan := tracer.StartSpan("root")
   423  	ctx := opentracing.ContextWithSpan(context.Background(), rootSpan)
   424  	qSpan := rootSpan.Tracer().StartSpan("q", opentracing.ChildOf(rootSpan.Context()))
   425  
   426  	token := int64(3)
   427  	term := Table("test")
   428  	q := Query{Token: token, Term: &term}
   429  	response := &Response{Token: token, Type: p.Response_RUNTIME_ERROR, Responses: []json.RawMessage{{'e', 'r', 'r'}}}
   430  
   431  	connection := newConnection(nil, "addr", &ConnectOpts{})
   432  
   433  	resp, cursor, err := connection.processResponse(ctx, q, response, qSpan)
   434  
   435  	c.Assert(resp, test.Equals, response)
   436  	c.Assert(cursor, test.IsNil)
   437  	c.Assert(err, test.FitsTypeOf, RQLRuntimeError{})
   438  	c.Assert(tracer.FinishedSpans(), test.HasLen, 1)
   439  	c.Assert(tracer.FinishedSpans()[0].Tags()["error"], test.Equals, true)
   440  }
   441  
   442  func (s *ConnectionSuite) TestConnection_processResponse_FirstPartialOk(c *test.C) {
   443  	ctx := context.Background()
   444  	token := int64(3)
   445  	q := Query{Token: token}
   446  	rawResponse1 := json.RawMessage{1, 2, 3}
   447  	rawResponse2 := json.RawMessage{3, 4, 5}
   448  	response := &Response{Token: token, Type: p.Response_SUCCESS_PARTIAL, Responses: []json.RawMessage{rawResponse1, rawResponse2}}
   449  
   450  	connection := newConnection(nil, "addr", &ConnectOpts{})
   451  
   452  	resp, cursor, err := connection.processResponse(ctx, q, response, nil)
   453  
   454  	c.Assert(resp, test.Equals, response)
   455  	c.Assert(cursor, test.NotNil)
   456  	c.Assert(cursor.token, test.Equals, token)
   457  	c.Assert(cursor.ctx, test.Equals, ctx)
   458  	c.Assert(cursor.responses, test.HasLen, 2)
   459  	c.Assert(cursor.responses[0], test.DeepEquals, rawResponse1)
   460  	c.Assert(cursor.responses[1], test.DeepEquals, rawResponse2)
   461  	c.Assert(cursor.conn, test.Equals, connection)
   462  	c.Assert(err, test.IsNil)
   463  	c.Assert(connection.cursors, test.HasLen, 1)
   464  	c.Assert(connection.cursors[token], test.Equals, cursor)
   465  }
   466  
   467  func (s *ConnectionSuite) TestConnection_processResponse_PartialOk(c *test.C) {
   468  	ctx := context.Background()
   469  	token := int64(3)
   470  	term := Table("test")
   471  	q := Query{Token: token}
   472  	rawResponse1 := json.RawMessage{1, 2, 3}
   473  	rawResponse2 := json.RawMessage{3, 4, 5}
   474  	response := &Response{Token: token, Type: p.Response_SUCCESS_PARTIAL, Responses: []json.RawMessage{rawResponse1, rawResponse2}}
   475  
   476  	connection := newConnection(nil, "addr", &ConnectOpts{})
   477  	oldCursor := newCursor(ctx, connection, "Cursor", token, &term, q.Opts)
   478  	connection.cursors[token] = oldCursor
   479  
   480  	resp, cursor, err := connection.processResponse(ctx, q, response, nil)
   481  
   482  	c.Assert(resp, test.Equals, response)
   483  	c.Assert(cursor, test.Equals, oldCursor)
   484  	c.Assert(cursor.responses, test.HasLen, 2)
   485  	c.Assert(cursor.responses[0], test.DeepEquals, rawResponse1)
   486  	c.Assert(cursor.responses[1], test.DeepEquals, rawResponse2)
   487  	c.Assert(err, test.IsNil)
   488  	c.Assert(connection.cursors, test.HasLen, 1)
   489  	c.Assert(connection.cursors[token], test.Equals, cursor)
   490  }
   491  
   492  func (s *ConnectionSuite) TestConnection_processResponse_SequenceOk(c *test.C) {
   493  	tracer := mocktracer.New()
   494  	rootSpan := tracer.StartSpan("root")
   495  	ctx := opentracing.ContextWithSpan(context.Background(), rootSpan)
   496  	qSpan := rootSpan.Tracer().StartSpan("q", opentracing.ChildOf(rootSpan.Context()))
   497  
   498  	token := int64(3)
   499  	q := Query{Token: token}
   500  	rawResponse1 := json.RawMessage{1, 2, 3}
   501  	rawResponse2 := json.RawMessage{3, 4, 5}
   502  	response := &Response{Token: token, Type: p.Response_SUCCESS_SEQUENCE, Responses: []json.RawMessage{rawResponse1, rawResponse2}}
   503  
   504  	connection := newConnection(nil, "addr", &ConnectOpts{})
   505  
   506  	resp, cursor, err := connection.processResponse(ctx, q, response, qSpan)
   507  
   508  	c.Assert(resp, test.Equals, response)
   509  	c.Assert(cursor, test.NotNil)
   510  	c.Assert(cursor.token, test.Equals, token)
   511  	c.Assert(cursor.ctx, test.Equals, ctx)
   512  	c.Assert(cursor.responses, test.HasLen, 2)
   513  	c.Assert(cursor.responses[0], test.DeepEquals, rawResponse1)
   514  	c.Assert(cursor.responses[1], test.DeepEquals, rawResponse2)
   515  	c.Assert(cursor.conn, test.Equals, connection)
   516  	c.Assert(err, test.IsNil)
   517  	c.Assert(connection.cursors, test.HasLen, 0)
   518  	c.Assert(tracer.FinishedSpans(), test.HasLen, 1)
   519  	c.Assert(tracer.FinishedSpans()[0].Tags(), test.HasLen, 0)
   520  }
   521  
   522  func (s *ConnectionSuite) TestConnection_processResponse_WaitOk(c *test.C) {
   523  	ctx := context.Background()
   524  	token := int64(3)
   525  	q := Query{Token: token}
   526  	response := &Response{Token: token, Type: p.Response_WAIT_COMPLETE}
   527  
   528  	connection := newConnection(nil, "addr", &ConnectOpts{})
   529  	connection.cursors[token] = &Cursor{}
   530  
   531  	resp, cursor, err := connection.processResponse(ctx, q, response, nil)
   532  
   533  	c.Assert(resp, test.Equals, response)
   534  	c.Assert(cursor, test.IsNil)
   535  	c.Assert(err, test.IsNil)
   536  	c.Assert(connection.cursors, test.HasLen, 0)
   537  }
   538  
   539  func (s *ConnectionSuite) TestConnection_processResponse_UnexpectedOk(c *test.C) {
   540  	ctx := context.Background()
   541  	token := int64(3)
   542  	q := Query{Token: token}
   543  	response := &Response{Token: token, Type: 99}
   544  
   545  	connection := newConnection(nil, "addr", &ConnectOpts{})
   546  
   547  	resp, cursor, err := connection.processResponse(ctx, q, response, nil)
   548  
   549  	c.Assert(resp, test.IsNil)
   550  	c.Assert(cursor, test.IsNil)
   551  	c.Assert(err, test.FitsTypeOf, RQLDriverError{})
   552  }
   553  
   554  func testQuery(t Term) Query {
   555  	q, _ := newQuery(
   556  		t,
   557  		map[string]interface{}{},
   558  		&ConnectOpts{},
   559  	)
   560  	return q
   561  }
   562  
   563  func respHeader(token int64, msg []byte) []byte {
   564  	header := [respHeaderLen]byte{}
   565  	binary.LittleEndian.PutUint64(header[:], uint64(token))
   566  	binary.LittleEndian.PutUint32(header[8:], uint32(len(msg)))
   567  	return header[:]
   568  }
   569  
   570  func serializeQuery(token int64, q Query) []byte {
   571  	b, _ := json.Marshal(q.Build())
   572  	msg := make([]byte, len(b)+respHeaderLen+1)
   573  	binary.LittleEndian.PutUint64(msg, uint64(token))
   574  	binary.LittleEndian.PutUint32(msg[8:], uint32(len(b)+1))
   575  	copy(msg[respHeaderLen:], b)
   576  	msg[len(msg)-1] = '\n' // encoder.Marshal do this, json.Marshal doesn't
   577  	return msg
   578  }
   579  
   580  func serializeAtomResponse() []byte {
   581  	b, _ := json.Marshal(map[string]interface{}{
   582  		"t": p.Response_SUCCESS_ATOM,
   583  		"r": []interface{}{"response"},
   584  	})
   585  	return b
   586  }