1
2
3
4
5
6
7
8
9
10
11
12
13
14 package db
15
16 import (
17 "context"
18 "fmt"
19 "sort"
20
21 "gitlab.com/flimzy/testy"
22
23 "github.com/go-kivik/kivik/v4"
24 "github.com/go-kivik/kivik/v4/kiviktest/kt"
25 )
26
27 func init() {
28 kt.Register("AllDocs", allDocs)
29 }
30
31 func allDocs(ctx *kt.Context) {
32 ctx.RunAdmin(func(ctx *kt.Context) {
33 testAllDocs(ctx, ctx.Admin)
34 })
35 ctx.RunNoAuth(func(ctx *kt.Context) {
36 testAllDocs(ctx, ctx.NoAuth)
37 })
38 ctx.RunRW(func(ctx *kt.Context) {
39 testAllDocsRW(ctx)
40 })
41 }
42
43 func testAllDocsRW(ctx *kt.Context) {
44 if ctx.Admin == nil {
45
46 return
47 }
48 dbName, expected, err := setUpAllDocsTest(ctx)
49 if err != nil {
50 ctx.Errorf("Failed to set up temp db: %s", err)
51 }
52 ctx.Run("group", func(ctx *kt.Context) {
53 ctx.RunAdmin(func(ctx *kt.Context) {
54 doTest(ctx, ctx.Admin, dbName, 0, expected, true)
55 })
56 ctx.RunNoAuth(func(ctx *kt.Context) {
57 doTest(ctx, ctx.NoAuth, dbName, 0, expected, true)
58 })
59 })
60 }
61
62 func setUpAllDocsTest(ctx *kt.Context) (dbName string, docIDs []string, err error) {
63 dbName = ctx.TestDB()
64 db := ctx.Admin.DB(dbName, ctx.Options("db"))
65 if err := db.Err(); err != nil {
66 return dbName, nil, fmt.Errorf("failed to connect to db: %w", err)
67 }
68 const maxDocs = 10
69 docIDs = make([]string, maxDocs)
70 for i := range docIDs {
71 id := ctx.TestDBName()
72 doc := struct {
73 ID string `json:"id"`
74 }{
75 ID: id,
76 }
77 if _, err := db.Put(context.Background(), doc.ID, doc); err != nil {
78 return dbName, nil, fmt.Errorf("failed to create doc: %w", err)
79 }
80 docIDs[i] = id
81 }
82 sort.Strings(docIDs)
83 return dbName, docIDs, nil
84 }
85
86 func testAllDocs(ctx *kt.Context, client *kivik.Client) {
87 if !ctx.IsSet("databases") {
88 ctx.Errorf("databases not set; Did you configure this test?")
89 return
90 }
91 for _, dbName := range ctx.StringSlice("databases") {
92 func(dbName string) {
93 ctx.Run(dbName, func(ctx *kt.Context) {
94 doTest(ctx, client, dbName, int64(ctx.Int("offset")), ctx.StringSlice("expected"), false)
95 })
96 }(dbName)
97 }
98 }
99
100 func doTest(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string, exact bool) {
101 ctx.Run("WithDocs", func(ctx *kt.Context) {
102 doTestWithDocs(ctx, client, dbName, expOffset, expected, exact)
103 })
104 ctx.Run("WithoutDocs", func(ctx *kt.Context) {
105 doTestWithoutDocs(ctx, client, dbName, expOffset, expected, exact)
106 })
107 }
108
109 func doTestWithoutDocs(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string, exact bool) {
110 ctx.Parallel()
111 db := client.DB(dbName, ctx.Options("db"))
112
113
114 if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) {
115 return
116 }
117
118 rows := db.AllDocs(context.Background())
119 if !ctx.IsExpectedSuccess(rows.Err()) {
120 return
121 }
122 docIDs := make([]string, 0, len(expected))
123 for rows.Next() {
124 id, _ := rows.ID()
125 docIDs = append(docIDs, id)
126 }
127 meta, err := rows.Metadata()
128 if err != nil {
129 ctx.Fatalf("Failed to fetch row: %s", rows.Err())
130 }
131 testExpectedDocs(ctx, expected, docIDs, exact)
132 if expOffset != meta.Offset {
133 ctx.Errorf("offset: Expected %d, got %d", expOffset, meta.Offset)
134 }
135 if exact {
136 if int64(len(expected)) != meta.TotalRows {
137 ctx.Errorf("total rows: Expected %d, got %d", len(expected), meta.TotalRows)
138 }
139 }
140 }
141
142 func doTestWithDocs(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string, exact bool) {
143 ctx.Parallel()
144 db := client.DB(dbName, ctx.Options("db"))
145
146
147 if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) {
148 return
149 }
150 opts := kivik.Params(map[string]interface{}{
151 "include_docs": true,
152 "update_seq": true,
153 })
154
155 rows := db.AllDocs(context.Background(), opts)
156 if !ctx.IsExpectedSuccess(rows.Err()) {
157 return
158 }
159 docIDs := make([]string, 0, len(expected))
160 for rows.Next() {
161 var doc struct {
162 ID string `json:"_id"`
163 Rev string `json:"_rev"`
164 }
165 if err := rows.ScanDoc(&doc); err != nil {
166 ctx.Errorf("Failed to scan doc: %s", err)
167 }
168 var value struct {
169 Rev string `json:"rev"`
170 }
171 if err := rows.ScanValue(&value); err != nil {
172 ctx.Errorf("Failed to scan value: %s", err)
173 }
174 if value.Rev != doc.Rev {
175 ctx.Errorf("doc._rev = %s, but value.rev = %s", doc.Rev, value.Rev)
176 }
177 id, _ := rows.ID()
178 if doc.ID != id {
179 ctx.Errorf("doc._id = %s, but rows.ID = %s", doc.ID, id)
180 }
181 docIDs = append(docIDs, id)
182 }
183 meta, err := rows.Metadata()
184 if err != nil {
185 ctx.Fatalf("Failed to fetch row: %s", rows.Err())
186 }
187 testExpectedDocs(ctx, expected, docIDs, exact)
188 if expOffset != meta.Offset {
189 ctx.Errorf("offset: Expected %d, got %d", expOffset, meta.Offset)
190 }
191 ctx.Run("UpdateSeq", func(ctx *kt.Context) {
192 if meta.UpdateSeq == "" {
193 ctx.Errorf("Expected updated sequence")
194 }
195 })
196 if exact {
197 if int64(len(expected)) != meta.TotalRows {
198 ctx.Errorf("total rows: Expected %d, got %d", len(expected), meta.TotalRows)
199 }
200 }
201 }
202
203 func testExpectedDocs(ctx *kt.Context, expected, actual []string, exact bool) {
204 if exact {
205 if d := testy.DiffTextSlices(expected, actual); d != nil {
206 ctx.Errorf("Unexpected document IDs returned:\n%s\n", d)
207 }
208 return
209 }
210 actualIDs := make(map[string]struct{})
211 for _, id := range actual {
212 actualIDs[id] = struct{}{}
213 }
214 for _, id := range expected {
215 if _, ok := actualIDs[id]; !ok {
216 ctx.Errorf("Expected document '%s' not found", id)
217 }
218 }
219 }
220
View as plain text