1
2
3
4
5
6
7
8
9
10
11
12
13 package kivik
14
15 import (
16 "context"
17 "encoding/json"
18 "errors"
19 "fmt"
20 "net/http"
21 "testing"
22
23 "gitlab.com/flimzy/testy"
24
25 "github.com/go-kivik/kivik/v4/driver"
26 internal "github.com/go-kivik/kivik/v4/int/errors"
27 "github.com/go-kivik/kivik/v4/int/mock"
28 )
29
30 func TestDocsInterfaceSlice(t *testing.T) {
31 type diTest struct {
32 name string
33 input []interface{}
34 expected interface{}
35 status int
36 err string
37 }
38 tests := []diTest{
39 {
40 name: "InterfaceSlice",
41 input: []interface{}{map[string]string{"foo": "bar"}},
42 expected: []interface{}{map[string]string{"foo": "bar"}},
43 },
44 {
45 name: "JSONDoc",
46 input: []interface{}{
47 map[string]string{"foo": "bar"},
48 json.RawMessage(`{"foo":"bar"}`),
49 },
50 expected: []interface{}{
51 map[string]string{"foo": "bar"},
52 map[string]string{"foo": "bar"},
53 },
54 },
55 }
56 for _, test := range tests {
57 func(test diTest) {
58 t.Run(test.name, func(t *testing.T) {
59 result, err := docsInterfaceSlice(test.input)
60 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
61 t.Error(d)
62 }
63 if d := testy.DiffAsJSON(test.expected, result); d != nil {
64 t.Errorf("%s", d)
65 }
66 })
67 }(test)
68 }
69 }
70
71 func TestBulkDocs(t *testing.T) {
72 type tt struct {
73 db *DB
74 docs []interface{}
75 options Option
76 expected []BulkResult
77 status int
78 err string
79 }
80
81 tests := testy.NewTable()
82 tests.Add("invalid JSON", tt{
83 db: &DB{
84 client: &Client{},
85 driverDB: &mock.BulkDocer{
86 BulkDocsFunc: func(_ context.Context, docs []interface{}, _ driver.Options) ([]driver.BulkResult, error) {
87 _, err := json.Marshal(docs)
88 return nil, err
89 },
90 },
91 },
92 docs: []interface{}{json.RawMessage("invalid json")},
93 status: http.StatusInternalServerError,
94 err: "json: error calling MarshalJSON for type json.RawMessage: invalid character 'i' looking for beginning of value",
95 })
96 tests.Add("emulated BulkDocs support", tt{
97 db: &DB{
98 client: &Client{},
99 driverDB: &mock.DocCreator{
100 DB: mock.DB{
101 PutFunc: func(_ context.Context, docID string, doc interface{}, options driver.Options) (string, error) {
102 if docID == "error" {
103 return "", errors.New("error")
104 }
105 if docID != "foo" {
106 return "", fmt.Errorf("Unexpected docID: %s", docID)
107 }
108 expectedDoc := map[string]string{"_id": "foo"}
109 if d := testy.DiffInterface(expectedDoc, doc); d != nil {
110 return "", fmt.Errorf("Unexpected doc:\n%s", d)
111 }
112 gotOpts := map[string]interface{}{}
113 options.Apply(gotOpts)
114 if d := testy.DiffInterface(testOptions, gotOpts); d != nil {
115 return "", fmt.Errorf("Unexpected opts:\n%s", d)
116 }
117 return "2-xxx", nil
118 },
119 },
120 CreateDocFunc: func(_ context.Context, doc interface{}, options driver.Options) (string, string, error) {
121 gotOpts := map[string]interface{}{}
122 options.Apply(gotOpts)
123 expectedDoc := int(123)
124 if d := testy.DiffInterface(expectedDoc, doc); d != nil {
125 return "", "", fmt.Errorf("Unexpected doc:\n%s", d)
126 }
127 if d := testy.DiffInterface(testOptions, gotOpts); d != nil {
128 return "", "", fmt.Errorf("Unexpected opts:\n%s", d)
129 }
130 return "newDocID", "1-xxx", nil
131 },
132 },
133 },
134 docs: []interface{}{
135 map[string]string{"_id": "foo"},
136 123,
137 map[string]string{"_id": "error"},
138 },
139 options: Params(testOptions),
140 expected: []BulkResult{
141 {ID: "foo", Rev: "2-xxx"},
142 {ID: "newDocID", Rev: "1-xxx"},
143 {ID: "error", Error: errors.New("error")},
144 },
145 })
146 tests.Add("new_edits", tt{
147 db: &DB{
148 client: &Client{},
149 driverDB: &mock.BulkDocer{
150 BulkDocsFunc: func(_ context.Context, docs []interface{}, options driver.Options) ([]driver.BulkResult, error) {
151 expectedDocs := []interface{}{map[string]string{"_id": "foo"}, 123}
152 wantOpts := map[string]interface{}{"new_edits": true}
153 gotOpts := map[string]interface{}{}
154 options.Apply(gotOpts)
155 if d := testy.DiffInterface(expectedDocs, docs); d != nil {
156 return nil, fmt.Errorf("Unexpected docs:\n%s", d)
157 }
158 if d := testy.DiffInterface(wantOpts, gotOpts); d != nil {
159 return nil, fmt.Errorf("Unexpected opts:\n%s", d)
160 }
161 return []driver.BulkResult{
162 {ID: "foo"},
163 }, nil
164 },
165 },
166 },
167 docs: []interface{}{
168 map[string]string{"_id": "foo"},
169 123,
170 },
171 options: Param("new_edits", true),
172 expected: []BulkResult{
173 {ID: "foo"},
174 },
175 })
176 tests.Add("client closed", tt{
177 db: &DB{
178 client: &Client{
179 closed: true,
180 },
181 },
182 docs: []interface{}{
183 map[string]string{"_id": "foo"},
184 },
185 status: http.StatusServiceUnavailable,
186 err: "kivik: client closed",
187 })
188 tests.Add("db error", tt{
189 db: &DB{
190 err: errors.New("db error"),
191 },
192 status: http.StatusInternalServerError,
193 err: "db error",
194 })
195 tests.Add("unreadable doc", tt{
196 db: &DB{
197 client: &Client{},
198 driverDB: &mock.BulkDocer{
199 BulkDocsFunc: func(_ context.Context, docs []interface{}, _ driver.Options) ([]driver.BulkResult, error) {
200 _, err := json.Marshal(docs)
201 return nil, err
202 },
203 },
204 },
205 docs: []interface{}{testy.ErrorReader("", errors.New("read error"))},
206 status: http.StatusBadRequest,
207 err: "read error",
208 })
209 tests.Add("no docs", tt{
210 db: &DB{
211 client: &Client{},
212 driverDB: &mock.BulkDocer{
213 BulkDocsFunc: func(_ context.Context, docs []interface{}, _ driver.Options) ([]driver.BulkResult, error) {
214 _, err := json.Marshal(docs)
215 return nil, err
216 },
217 },
218 },
219 docs: []interface{}{},
220 status: http.StatusBadRequest,
221 err: "kivik: no documents provided",
222 })
223
224 tests.Run(t, func(t *testing.T, tt tt) {
225 result, err := tt.db.BulkDocs(context.Background(), tt.docs, tt.options)
226 if d := internal.StatusErrorDiff(tt.err, tt.status, err); d != "" {
227 t.Error(d)
228 }
229 if d := testy.DiffInterface(tt.expected, result); d != nil {
230 t.Error(d)
231 }
232 })
233 }
234
View as plain text