1
2
3
4
5
6
7
8
9
10
11
12
13 package fs
14
15 import (
16 "context"
17 "errors"
18 "io"
19 "net/http"
20 "testing"
21
22 "gitlab.com/flimzy/testy"
23
24 "github.com/go-kivik/kivik/v4"
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/x/fsdb/filesystem"
28 )
29
30 func TestGet(t *testing.T) {
31 type tt struct {
32 fs filesystem.Filesystem
33 setup func(*testing.T, *db)
34 final func(*testing.T, *db)
35 path, dbname string
36 id string
37 options kivik.Option
38 expected *driver.Document
39 status int
40 err string
41 }
42 tests := testy.NewTable()
43 tests.Add("no id", tt{
44 path: "",
45 dbname: "foo",
46 status: http.StatusBadRequest,
47 err: "no docid specified",
48 })
49 tests.Add("not found", tt{
50 dbname: "asdf",
51 id: "foo",
52 status: http.StatusNotFound,
53 err: `^missing$`,
54 })
55 tests.Add("forbidden", func(*testing.T) interface{} {
56 return tt{
57 fs: &filesystem.MockFS{
58 OpenFunc: func(_ string) (filesystem.File, error) {
59 return nil, statusError{status: http.StatusForbidden, error: errors.New("permission denied")}
60 },
61 },
62 dbname: "foo",
63 id: "foo",
64 status: http.StatusForbidden,
65 err: "permission denied$",
66 }
67 })
68 tests.Add("success, no attachments", tt{
69 path: "testdata",
70 dbname: "db_foo",
71 id: "noattach",
72 expected: &driver.Document{
73 Rev: "1-xxxxxxxxxx",
74 },
75 })
76 tests.Add("success, attachment stub", tt{
77 path: "testdata",
78 dbname: "db_foo",
79 id: "withattach",
80 expected: &driver.Document{
81 Rev: "2-yyyyyyyyy",
82 },
83 })
84 tests.Add("success, include mp attachments", tt{
85 path: "testdata",
86 dbname: "db_foo",
87 id: "withattach",
88 options: kivik.Param("attachments", true),
89 expected: &driver.Document{
90 Rev: "2-yyyyyyyyy",
91 },
92 })
93 tests.Add("success, include inline attachments", tt{
94 path: "testdata",
95 dbname: "db_foo",
96 id: "withattach",
97 options: kivik.Params(map[string]interface{}{
98 "attachments": true,
99 "header:accept": "application/json",
100 }),
101 expected: &driver.Document{
102 Rev: "2-yyyyyyyyy",
103 },
104 })
105 tests.Add("specify current rev", tt{
106 path: "testdata",
107 dbname: "db_foo",
108 id: "noattach",
109 options: kivik.Rev("1-xxxxxxxxxx"),
110 expected: &driver.Document{
111 Rev: "1-xxxxxxxxxx",
112 },
113 })
114 tests.Add("specify old rev", tt{
115 path: "testdata",
116 dbname: "db_foo",
117 id: "withattach",
118 options: kivik.Rev("1-xxxxxxxxxx"),
119 expected: &driver.Document{
120 Rev: "1-xxxxxxxxxx",
121 },
122 })
123 tests.Add("autorev", tt{
124 path: "testdata",
125 dbname: "db_foo",
126 id: "autorev",
127 expected: &driver.Document{
128 Rev: "6-",
129 },
130 })
131 tests.Add("intrev", tt{
132 path: "testdata",
133 dbname: "db_foo",
134 id: "intrev",
135 expected: &driver.Document{
136 Rev: "6-",
137 },
138 })
139 tests.Add("norev", tt{
140 path: "testdata",
141 dbname: "db_foo",
142 id: "norev",
143 expected: &driver.Document{
144 Rev: "1-",
145 },
146 })
147 tests.Add("noid", tt{
148 path: "testdata",
149 dbname: "db_foo",
150 id: "noid",
151 expected: &driver.Document{
152 Rev: "6-",
153 },
154 })
155 tests.Add("wrong id", tt{
156 path: "testdata",
157 dbname: "db_foo",
158 id: "wrongid",
159 expected: &driver.Document{
160 Rev: "6-",
161 },
162 })
163 tests.Add("yaml", tt{
164 path: "testdata",
165 dbname: "db_foo",
166 id: "yamltest",
167 expected: &driver.Document{
168 Rev: "3-",
169 },
170 })
171 tests.Add("specify current rev yaml", tt{
172 path: "testdata",
173 dbname: "db_foo",
174 id: "yamltest",
175 options: kivik.Rev("3-"),
176 expected: &driver.Document{
177 Rev: "3-",
178 },
179 })
180 tests.Add("specify old rev yaml", tt{
181 path: "testdata",
182 dbname: "db_foo",
183 id: "yamltest",
184 options: kivik.Rev("2-xxx"),
185 expected: &driver.Document{
186 Rev: "2-xxx",
187 },
188 })
189 tests.Add("specify bogus rev yaml", tt{
190 path: "testdata",
191 dbname: "db_foo",
192 id: "yamltest",
193 options: kivik.Rev("1-oink"),
194 status: http.StatusNotFound,
195 err: "missing",
196 })
197 tests.Add("ddoc yaml", tt{
198 path: "testdata",
199 dbname: "db_foo",
200 id: "_design/users",
201 expected: &driver.Document{
202 Rev: "2-",
203 },
204 })
205 tests.Add("ddoc rev yaml", tt{
206 path: "testdata",
207 dbname: "db_foo",
208 id: "_design/users",
209 options: kivik.Rev("2-"),
210 expected: &driver.Document{
211 Rev: "2-",
212 },
213 })
214 tests.Add("revs", tt{
215 path: "testdata",
216 dbname: "db_foo",
217 id: "wrongid",
218 options: kivik.Param("revs", true),
219 expected: &driver.Document{
220 Rev: "6-",
221 },
222 })
223 tests.Add("revs real", tt{
224 path: "testdata",
225 dbname: "db_foo",
226 id: "noattach",
227 options: kivik.Param("revs", true),
228 expected: &driver.Document{
229 Rev: "1-xxxxxxxxxx",
230 },
231 })
232 tests.Add("note--XkWjFv13acvjJTt-CGJJ8hXlWE", tt{
233 path: "testdata",
234 dbname: "db_att",
235 id: "note--XkWjFv13acvjJTt-CGJJ8hXlWE",
236 expected: &driver.Document{
237 Rev: "1-fbaabe005e0f4e5685a68f857c0777d6",
238 },
239 })
240 tests.Add("note--XkWjFv13acvjJTt-CGJJ8hXlWE + attachments", tt{
241 path: "testdata",
242 dbname: "db_att",
243 id: "note--XkWjFv13acvjJTt-CGJJ8hXlWE",
244 options: kivik.Param("attachments", true),
245 expected: &driver.Document{
246 Rev: "1-fbaabe005e0f4e5685a68f857c0777d6",
247 },
248 })
249 tests.Add("revs_info=true", tt{
250 path: "testdata",
251 dbname: "db_foo",
252 id: "autorev",
253 options: kivik.Param("revs_info", true),
254 expected: &driver.Document{
255 Rev: "6-",
256 },
257 })
258 tests.Add("revs, explicit", tt{
259 path: "testdata",
260 dbname: "db_foo",
261 id: "withrevs",
262 options: kivik.Param("revs", true),
263 expected: &driver.Document{
264 Rev: "8-asdf",
265 },
266 })
267 tests.Add("specify current rev, revs_info=true", tt{
268 path: "testdata",
269 dbname: "db_foo",
270 id: "yamltest",
271 options: kivik.Params(map[string]interface{}{
272 "rev": "3-",
273 "revs_info": true,
274 }),
275 expected: &driver.Document{
276 Rev: "3-",
277 },
278 })
279 tests.Add("specify conflicting rev, revs_info=true", tt{
280 path: "testdata",
281 dbname: "db_foo",
282 id: "yamltest",
283 options: kivik.Params(map[string]interface{}{
284 "rev": "2-xxx",
285 "revs_info": true,
286 }),
287 expected: &driver.Document{
288 Rev: "2-xxx",
289 },
290 })
291 tests.Add("specify rev, revs=true", tt{
292 path: "testdata",
293 dbname: "db_foo",
294 id: "withrevs",
295 options: kivik.Params(map[string]interface{}{
296 "rev": "8-asdf",
297 "revs": true,
298 }),
299 expected: &driver.Document{
300 Rev: "8-asdf",
301 },
302 })
303 tests.Add("interrupted put", tt{
304
305
306
307 path: "testdata",
308 dbname: "db_foo",
309 id: "abortedput",
310 options: kivik.Param("attachments", true),
311 expected: &driver.Document{
312 Rev: "2-yyyyyyyyy",
313 },
314 })
315 tests.Add("no winner, tied rev", tt{
316
317
318
319 path: "testdata",
320 dbname: "get_nowinner",
321 id: "foo",
322 expected: &driver.Document{
323 Rev: "1-yyy",
324 },
325 })
326 tests.Add("no winner, greater rev", tt{
327
328
329
330 path: "testdata",
331 dbname: "get_nowinner",
332 id: "bar",
333 expected: &driver.Document{
334 Rev: "2-yyy",
335 },
336 })
337 tests.Add("atts split between winning and revs dir", tt{
338 path: "testdata",
339 dbname: "get_split_atts",
340 id: "foo",
341 options: kivik.Param("attachments", true),
342 expected: &driver.Document{
343 Rev: "2-zzz",
344 },
345 })
346 tests.Add("atts split between two revs", tt{
347 path: "testdata",
348 dbname: "get_split_atts",
349 id: "bar",
350 options: kivik.Param("attachments", true),
351 expected: &driver.Document{
352 Rev: "2-yyy",
353 },
354 })
355 tests.Add("non-standard filenames", tt{
356 path: "testdata",
357 dbname: "db_nonascii",
358 id: "note-i_ɪ",
359 expected: &driver.Document{
360 Rev: "1-",
361 },
362 })
363 tests.Add("deleted doc", tt{
364 path: "testdata",
365 dbname: "db_foo",
366 id: "deleted",
367 status: http.StatusNotFound,
368 err: "deleted",
369 })
370 tests.Add("deleted doc, specific rev", tt{
371 path: "testdata",
372 dbname: "db_foo",
373 id: "deleted",
374 options: kivik.Rev("3-"),
375 expected: &driver.Document{
376 Rev: "3-",
377 },
378 })
379
380 tests.Run(t, func(t *testing.T, tt tt) {
381 dir := tt.path
382 if dir == "" {
383 dir = tempDir(t)
384 t.Cleanup(func() {
385 rmdir(t, dir)
386 })
387 }
388 fs := tt.fs
389 if fs == nil {
390 fs = filesystem.Default()
391 }
392 c := &client{root: dir, fs: fs}
393 db, err := c.newDB(tt.dbname)
394 if err != nil {
395 t.Fatal(err)
396 }
397 if tt.setup != nil {
398 tt.setup(t, db)
399 }
400 opts := tt.options
401 if opts == nil {
402 opts = kivik.Params(nil)
403 }
404 result, err := db.Get(context.Background(), tt.id, opts)
405 if d := internal.StatusErrorDiffRE(tt.err, tt.status, err); d != "" {
406 t.Error(d)
407 }
408 if err != nil {
409 return
410 }
411 if d := testy.DiffAsJSON(testy.Snapshot(t), result.Body); d != nil {
412 t.Errorf("document:\n%s", d)
413 }
414 if result.Attachments != nil {
415 attachments := result.Attachments
416 t.Cleanup(func() {
417 _ = attachments.Close()
418 })
419 att := &driver.Attachment{}
420 for {
421 if err := result.Attachments.Next(att); err != nil {
422 if err == io.EOF {
423 break
424 }
425 t.Fatal(err)
426 }
427 if d := testy.DiffText(&testy.File{Path: "testdata/" + testy.Stub(t) + "_" + att.Filename}, att.Content); d != nil {
428 t.Errorf("Attachment %s content:\n%s", att.Filename, d)
429 }
430 _ = att.Content.Close()
431 att.Content = nil
432 if d := testy.DiffAsJSON(&testy.File{Path: "testdata/" + testy.Stub(t) + "_" + att.Filename + "_struct"}, att); d != nil {
433 t.Errorf("Attachment %s struct:\n%s", att.Filename, d)
434 }
435 }
436 }
437 result.Body = nil
438 result.Attachments = nil
439 if d := testy.DiffInterface(tt.expected, result); d != nil {
440 t.Error(d)
441 }
442 if tt.final != nil {
443 tt.final(t, db)
444 }
445 })
446 }
447
View as plain text