github.com/go-kivik/kivik/v4@v4.3.2/kiviktest/db/find.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 package db 14 15 import ( 16 "context" 17 "fmt" 18 "sort" 19 20 "gitlab.com/flimzy/testy" 21 22 "github.com/go-kivik/kivik/v4" 23 "github.com/go-kivik/kivik/v4/kiviktest/kt" 24 ) 25 26 func init() { 27 kt.Register("Find", find) 28 } 29 30 func find(ctx *kt.Context) { 31 ctx.RunAdmin(func(ctx *kt.Context) { 32 testFind(ctx, ctx.Admin) 33 }) 34 ctx.RunNoAuth(func(ctx *kt.Context) { 35 testFind(ctx, ctx.NoAuth) 36 }) 37 ctx.RunRW(func(ctx *kt.Context) { 38 testFindRW(ctx) 39 }) 40 } 41 42 func testFindRW(ctx *kt.Context) { 43 if ctx.Admin == nil { 44 // Can't do anything here without admin access 45 return 46 } 47 dbName, expected, err := setUpFindTest(ctx) 48 if err != nil { 49 ctx.Errorf("Failed to set up temp db: %s", err) 50 } 51 ctx.Run("group", func(ctx *kt.Context) { 52 ctx.RunAdmin(func(ctx *kt.Context) { 53 doFindTest(ctx, ctx.Admin, dbName, 0, expected) 54 }) 55 ctx.RunNoAuth(func(ctx *kt.Context) { 56 doFindTest(ctx, ctx.NoAuth, dbName, 0, expected) 57 }) 58 }) 59 } 60 61 func setUpFindTest(ctx *kt.Context) (dbName string, docIDs []string, err error) { 62 dbName = ctx.TestDB() 63 db := ctx.Admin.DB(dbName, ctx.Options("db")) 64 if err := db.Err(); err != nil { 65 return dbName, nil, fmt.Errorf("failed to connect to db: %w", err) 66 } 67 const maxDocs = 10 68 docIDs = make([]string, maxDocs) 69 for i := range docIDs { 70 id := ctx.TestDBName() 71 doc := struct { 72 ID string `json:"id"` 73 }{ 74 ID: id, 75 } 76 if _, err := db.Put(context.Background(), doc.ID, doc); err != nil { 77 return dbName, nil, fmt.Errorf("failed to create doc: %w", err) 78 } 79 docIDs[i] = id 80 } 81 sort.Strings(docIDs) 82 return dbName, docIDs, nil 83 } 84 85 func testFind(ctx *kt.Context, client *kivik.Client) { 86 if !ctx.IsSet("databases") { 87 ctx.Errorf("databases not set; Did you configure this test?") 88 return 89 } 90 for _, dbName := range ctx.StringSlice("databases") { 91 func(dbName string) { 92 ctx.Run(dbName, func(ctx *kt.Context) { 93 doFindTest(ctx, client, dbName, int64(ctx.Int("offset")), ctx.StringSlice("expected")) 94 }) 95 }(dbName) 96 } 97 } 98 99 func doFindTest(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string) { 100 ctx.Parallel() 101 db := client.DB(dbName, ctx.Options("db")) 102 // Errors may be deferred here, so only return if we actually get 103 // an error. 104 if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) { 105 return 106 } 107 108 var rows *kivik.ResultSet 109 err := kt.Retry(func() error { 110 rows = db.Find(context.Background(), `{"selector":{"_id":{"$gt":null}}}`) 111 return rows.Err() 112 }) 113 114 if !ctx.IsExpectedSuccess(err) { 115 return 116 } 117 docIDs := make([]string, 0, len(expected)) 118 for rows.Next() { 119 var doc struct { 120 DocID string `json:"_id"` 121 Rev string `json:"_rev"` 122 ID string `json:"id"` 123 } 124 if err := rows.ScanDoc(&doc); err != nil { 125 ctx.Errorf("Failed to scan doc: %s", err) 126 } 127 docIDs = append(docIDs, doc.DocID) 128 } 129 meta, err := rows.Metadata() 130 if err != nil { 131 ctx.Fatalf("Failed to fetch row: %s", rows.Err()) 132 } 133 sort.Strings(docIDs) // normalize order 134 if d := testy.DiffTextSlices(expected, docIDs); d != nil { 135 ctx.Errorf("Unexpected document IDs returned:\n%s\n", d) 136 } 137 if meta.Offset != expOffset { 138 ctx.Errorf("Unexpected offset: %v", meta.Offset) 139 } 140 ctx.Run("Warning", func(ctx *kt.Context) { 141 rows := db.Find(context.Background(), `{"selector":{"foo":{"$gt":null}}}`) 142 if !ctx.IsExpectedSuccess(rows.Err()) { 143 return 144 } 145 for rows.Next() { 146 } 147 if w := ctx.String("warning"); w != meta.Warning { 148 ctx.Errorf("Warning:\nExpected: %s\n Actual: %s", w, meta.Warning) 149 } 150 }) 151 }