-
Notifications
You must be signed in to change notification settings - Fork 1
/
clientmock.go
221 lines (191 loc) · 4.99 KB
/
clientmock.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
package kivikmock
import (
"encoding/json"
"fmt"
"reflect"
"time"
kivik "github.com/go-kivik/kivik/v4"
)
// Client allows configuring the mock kivik client.
type Client struct {
ordered bool
dsn string
opened int
drv *mockDriver
expected []expectation
newdbcount int
}
// nextExpectation accepts the expected value actual, checks that this is a
// valid expectation, and if so, populates actual with the matching expectation.
// If the expectation is not expected, an error is returned.
func (c *Client) nextExpectation(actual expectation) error {
c.drv.Lock()
defer c.drv.Unlock()
var expected expectation
var fulfilled int
for _, next := range c.expected {
next.Lock()
if next.fulfilled() {
next.Unlock()
fulfilled++
continue
}
if c.ordered {
if reflect.TypeOf(actual).Elem().Name() == reflect.TypeOf(next).Elem().Name() {
if meets(actual, next) {
expected = next
break
}
next.Unlock()
return fmt.Errorf("Expectation not met:\nExpected: %s\n Actual: %s",
next, actual)
}
next.Unlock()
return fmt.Errorf("call to %s was not expected. Next expectation is: %s", actual.method(false), next.method(false))
}
if meets(actual, next) {
expected = next
break
}
next.Unlock()
}
if expected == nil {
if fulfilled == len(c.expected) {
return fmt.Errorf("call to %s was not expected, all expectations already fulfilled", actual.method(false))
}
return fmt.Errorf("call to %s was not expected", actual.method(!c.ordered))
}
defer expected.Unlock()
expected.fulfill()
reflect.ValueOf(actual).Elem().Set(reflect.ValueOf(expected).Elem())
return nil
}
func (c *Client) open() (*kivik.Client, *Client, error) {
client, err := kivik.New("kivikmock", c.dsn)
return client, c, err
}
// ExpectationsWereMet returns an error if any outstanding expectatios were
// not met.
func (c *Client) ExpectationsWereMet() error {
c.drv.Lock()
defer c.drv.Unlock()
for _, e := range c.expected {
e.Lock()
fulfilled := e.fulfilled()
e.Unlock()
if !fulfilled {
return fmt.Errorf("there is a remaining unmet expectation: %s", e)
}
}
return nil
}
// MatchExpectationsInOrder sets whether expectations should occur in the
// precise order in which they were defined.
func (c *Client) MatchExpectationsInOrder(b bool) {
c.ordered = b
}
// ExpectAuthenticate queues an expectation for an Authenticate() call.
func (c *Client) ExpectAuthenticate() *ExpectedAuthenticate {
e := &ExpectedAuthenticate{}
c.expected = append(c.expected, e)
return e
}
// ExpectCreateDB queues an expectation for a CreateDB() call.
func (c *Client) ExpectCreateDB() *ExpectedCreateDB {
e := &ExpectedCreateDB{}
c.expected = append(c.expected, e)
return e
}
// NewDB creates a new mock DB object, which can be used along with ExpectDB()
// or ExpectCreateDB() calls to mock database actions.
func (c *Client) NewDB() *DB {
c.newdbcount++
return &DB{
client: c,
id: c.newdbcount,
}
}
// NewRows returns a new, empty set of rows, which can be returned by any of
// the row-returning expectations.
func NewRows() *Rows {
return &Rows{}
}
// NewChanges returns a new, empty changes set, which can be returned by the
// DB.Changes() expectation.
func NewChanges() *Changes {
return &Changes{}
}
// NewDBUpdates returns a new, empty update set, which can be returned by the
// DBUpdates() expectation.
func NewDBUpdates() *Updates {
return &Updates{}
}
// Replication is a replication instance.
type Replication struct {
id string
source string
target string
startTime time.Time
endTime time.Time
state string
err error
}
// NewReplication returns a new, empty Replication.
func (c *Client) NewReplication() *Replication {
return &Replication{}
}
func (r *Replication) MarshalJSON() ([]byte, error) {
type rep struct {
ID string `json:"replication_id,omitempty"`
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`
StartTime *time.Time `json:"start_time,omitempty"`
EndTime *time.Time `json:"end_time,omitempty"`
State string `json:"state,omitempty"`
Err string `json:"error,omitempty"`
}
doc := &rep{
ID: r.id,
Source: r.source,
Target: r.target,
State: r.state,
}
if !r.startTime.IsZero() {
doc.StartTime = &r.startTime
}
if !r.endTime.IsZero() {
doc.EndTime = &r.endTime
}
if r.err != nil {
doc.Err = r.err.Error()
}
return json.Marshal(doc)
}
func (r *Replication) ID(id string) *Replication {
r.id = id
return r
}
func (r *Replication) Source(s string) *Replication {
r.source = s
return r
}
func (r *Replication) Target(t string) *Replication {
r.target = t
return r
}
func (r *Replication) StartTime(t time.Time) *Replication {
r.startTime = t
return r
}
func (r *Replication) EndTime(t time.Time) *Replication {
r.endTime = t
return r
}
func (r *Replication) State(s kivik.ReplicationState) *Replication {
r.state = string(s)
return r
}
func (r *Replication) Err(e error) *Replication {
r.err = e
return r
}