Skip to content

Commit 61cfdef

Browse files
committed
Merge branch 'release/v2.1.0'
2 parents de072a9 + c8df9e3 commit 61cfdef

File tree

12 files changed

+733
-90
lines changed

12 files changed

+733
-90
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,26 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## v2.1.0 - 2016-06-26
6+
7+
### Added
8+
9+
- Added ability to mock queries based on the library github.com/stretchr/testify
10+
+ Added the `QueryExecutor` interface and changed query runner methods (`Run`/`Exec`) to accept this type instead of `*Session`, `Session` will still be accepted as it implements the `QueryExecutor` interface.
11+
+ Added the `NewMock` function to create a mock query executor
12+
+ Queries can be mocked using `On` and `Return`, `Mock` also contains functions for asserting that the required mocked queries were executed.
13+
+ For more information about how to mock queries see the readme and tests in `mock_test.go`.
14+
15+
## Changed
16+
17+
- Exported the `Build()` function on `Query` and `Term`.
18+
- Updated import of `github.com/cenkalti/backoff` to `github.com/cenk/backoff`
19+
520
## v2.0.4 - 2016-05-22
621

722
### Changed
823
- Changed `Connect` to return the reason for connections failing (instead of just "no connections were made when creating the session")
24+
- Changed how queries are retried internally, previously when a query failed due to an issue with the connection a new connection was picked from the connection pool and the query was retried, now the driver will attempt to retry the query with a new host (and connection). This should make applications connecting to a multi-node cluster more reliable.
925

1026
### Fixed
1127
- Fixed queries not being retried when using `Query()`, queries are now retried if the request failed due to a bad connection.

README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
![GoRethink Logo](https://raw.github.com/wiki/dancannon/gorethink/gopher-and-thinker-s.png "Golang Gopher and RethinkDB Thinker")
1010

11-
Current version: v2.0.4 (RethinkDB v2.3)
11+
Current version: v2.1.0 (RethinkDB v2.3)
1212

1313
Please note that this version of the driver only supports versions of RethinkDB using the v0.4 protocol (any versions of the driver older than RethinkDB 2.0 will not work).
1414

@@ -297,6 +297,41 @@ Alternatively if you wish to modify the logging behaviour you can modify the log
297297
r.Log.Out = ioutil.Discard
298298
```
299299

300+
## Mocking
301+
302+
The driver includes the ability to mock queries meaning that you can test your code without needing to talk to a real RethinkDB cluster, this is perfect for ensuring that your application has high unit test coverage.
303+
304+
To write tests with mocking you should create an instance of `Mock` and then setup expectations using `On` and `Return`. Expectations allow you to define what results should be returned when a known query is executed, they are configured by passing the query term you want to mock to `On` and then the response and error to `Return`, if a non-nil error is passed to `Return` then any time that query is executed the error will be returned, if no error is passed then a cursor will be built using the value passed to `Return`. Once all your expectations have been created you should then execute you queries using the `Mock` instead of a `Session`.
305+
306+
Here is an example that shows how to mock a query that returns multiple rows and the resulting cursor can be used as normal.
307+
308+
```go
309+
func TestSomething(t *testing.T) {
310+
mock := r.NewMock()
311+
mock.on(r.Table("people")).Return([]interface{}{
312+
map[string]interface{}{"id": 1, "name": "John Smith"},
313+
map[string]interface{}{"id": 2, "name": "Jane Smith"},
314+
}, nil)
315+
316+
cursor, err := r.Table("people").Run(mock)
317+
if err != nil {
318+
t.Errorf(err)
319+
}
320+
321+
var rows []interface{}
322+
err := res.All(&rows)
323+
if err != nil {
324+
t.Errorf(err)
325+
}
326+
327+
// Test result of rows
328+
329+
mock.AssertExpectations(t)
330+
}
331+
```
332+
333+
The mocking implementation is based on amazing https://github.com/stretchr/testify library, thanks to @stretchr for their awesome work!
334+
300335
## Benchmarks
301336

302337
Everyone wants their project's benchmarks to be speedy. And while we know that rethinkDb and the gorethink driver are quite fast, our primary goal is for our benchmarks to be correct. They are designed to give you, the user, an accurate picture of writes per second (w/s). If you come up with a accurate test that meets this aim, submit a pull request please.

cluster.go

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"time"
99

1010
"github.com/Sirupsen/logrus"
11-
"github.com/cenkalti/backoff"
11+
"github.com/cenk/backoff"
1212
"github.com/hailocab/go-hostpool"
1313
)
1414

@@ -58,37 +58,68 @@ func NewCluster(hosts []Host, opts *ConnectOpts) (*Cluster, error) {
5858

5959
// Query executes a ReQL query using the cluster to connect to the database
6060
func (c *Cluster) Query(q Query) (cursor *Cursor, err error) {
61-
node, hpr, err := c.GetNextNode()
62-
if err != nil {
63-
return nil, err
61+
for i := 0; i < c.numRetries(); i++ {
62+
var node *Node
63+
var hpr hostpool.HostPoolResponse
64+
65+
node, hpr, err = c.GetNextNode()
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
cursor, err = node.Query(q)
71+
hpr.Mark(err)
72+
73+
if !shouldRetryQuery(q, err) {
74+
break
75+
}
6476
}
6577

66-
cursor, err = node.Query(q)
67-
hpr.Mark(err)
6878
return cursor, err
6979
}
7080

7181
// Exec executes a ReQL query using the cluster to connect to the database
7282
func (c *Cluster) Exec(q Query) (err error) {
73-
node, hpr, err := c.GetNextNode()
74-
if err != nil {
75-
return err
83+
for i := 0; i < c.numRetries(); i++ {
84+
var node *Node
85+
var hpr hostpool.HostPoolResponse
86+
87+
node, hpr, err = c.GetNextNode()
88+
if err != nil {
89+
return err
90+
}
91+
92+
err = node.Exec(q)
93+
hpr.Mark(err)
94+
95+
if !shouldRetryQuery(q, err) {
96+
break
97+
}
7698
}
7799

78-
err = node.Exec(q)
79-
hpr.Mark(err)
80100
return err
81101
}
82102

83103
// Server returns the server name and server UUID being used by a connection.
84104
func (c *Cluster) Server() (response ServerResponse, err error) {
85-
node, hpr, err := c.GetNextNode()
86-
if err != nil {
87-
return ServerResponse{}, err
105+
for i := 0; i < c.numRetries(); i++ {
106+
var node *Node
107+
var hpr hostpool.HostPoolResponse
108+
109+
node, hpr, err = c.GetNextNode()
110+
if err != nil {
111+
return ServerResponse{}, err
112+
}
113+
114+
response, err = node.Server()
115+
hpr.Mark(err)
116+
117+
// This query should not fail so retry if any error is detected
118+
if err == nil {
119+
break
120+
}
88121
}
89122

90-
response, err = node.Server()
91-
hpr.Mark(err)
92123
return response, err
93124
}
94125

@@ -473,3 +504,11 @@ func (c *Cluster) removeNode(nodeID string) {
473504
func (c *Cluster) nextNodeIndex() int64 {
474505
return atomic.AddInt64(&c.nodeIndex, 1)
475506
}
507+
508+
func (c *Cluster) numRetries() int {
509+
if n := c.opts.NumRetries; n > 0 {
510+
return n
511+
}
512+
513+
return 3
514+
}

connection.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func (c *Connection) Query(q Query) (*Response, *Cursor, error) {
124124
if q.Type == p.Query_START || q.Type == p.Query_NOREPLY_WAIT {
125125
if c.opts.Database != "" {
126126
var err error
127-
q.Opts["db"], err = DB(c.opts.Database).build()
127+
q.Opts["db"], err = DB(c.opts.Database).Build()
128128
if err != nil {
129129
c.mu.Unlock()
130130
return nil, nil, RQLDriverError{rqlError(err.Error())}
@@ -190,7 +190,7 @@ func (c *Connection) Server() (ServerResponse, error) {
190190
// sendQuery marshals the Query and sends the JSON to the server.
191191
func (c *Connection) sendQuery(q Query) error {
192192
// Build query
193-
b, err := json.Marshal(q.build())
193+
b, err := json.Marshal(q.Build())
194194
if err != nil {
195195
return RQLDriverError{rqlError("Error building query")}
196196
}

doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Package gorethink implements a Go driver for RethinkDB
22
//
3-
// Current version: v2.0.4 (RethinkDB v2.3)
3+
// Current version: v2.1.0 (RethinkDB v2.3)
44
// For more in depth information on how to use RethinkDB check out the API docs
55
// at http://rethinkdb.com/api
66
package gorethink

0 commit comments

Comments
 (0)