github.com/go-kivik/kivik/v4@v4.3.2/kiviktest/db/explain.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 18 "gitlab.com/flimzy/testy" 19 20 "github.com/go-kivik/kivik/v4" 21 "github.com/go-kivik/kivik/v4/kiviktest/kt" 22 ) 23 24 func init() { 25 kt.Register("Explain", explain) 26 } 27 28 func explain(ctx *kt.Context) { 29 ctx.RunAdmin(func(ctx *kt.Context) { 30 testExplain(ctx, ctx.Admin) 31 }) 32 ctx.RunNoAuth(func(ctx *kt.Context) { 33 testExplain(ctx, ctx.NoAuth) 34 }) 35 ctx.RunRW(func(ctx *kt.Context) { 36 testExplainRW(ctx) 37 }) 38 } 39 40 func testExplainRW(ctx *kt.Context) { 41 if ctx.Admin == nil { 42 // Can't do anything here without admin access 43 return 44 } 45 dbName := ctx.TestDB() 46 ctx.Run("group", func(ctx *kt.Context) { 47 ctx.RunAdmin(func(ctx *kt.Context) { 48 doExplainTest(ctx, ctx.Admin, dbName) 49 }) 50 ctx.RunNoAuth(func(ctx *kt.Context) { 51 doExplainTest(ctx, ctx.NoAuth, dbName) 52 }) 53 }) 54 } 55 56 func testExplain(ctx *kt.Context, client *kivik.Client) { 57 if !ctx.IsSet("databases") { 58 ctx.Errorf("databases not set; Did you configure this test?") 59 return 60 } 61 for _, dbName := range ctx.StringSlice("databases") { 62 func(dbName string) { 63 ctx.Run(dbName, func(ctx *kt.Context) { 64 doExplainTest(ctx, client, dbName) 65 }) 66 }(dbName) 67 } 68 } 69 70 func doExplainTest(ctx *kt.Context, client *kivik.Client, dbName string) { 71 const limit = 25 72 ctx.Parallel() 73 db := client.DB(dbName, ctx.Options("db")) 74 // Errors may be deferred here, so only return if we actually get 75 // an error. 76 if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) { 77 return 78 } 79 80 var plan *kivik.QueryPlan 81 err := kt.Retry(func() error { 82 var e error 83 plan, e = db.Explain(context.Background(), `{"selector":{"_id":{"$gt":null}}}`) 84 return e 85 }) 86 if !ctx.IsExpectedSuccess(err) { 87 return 88 } 89 expected := new(kivik.QueryPlan) 90 if e, ok := ctx.Interface("plan").(*kivik.QueryPlan); ok { 91 *expected = *e // Make a shallow copy 92 } else { 93 expected = &kivik.QueryPlan{ 94 Index: map[string]interface{}{ 95 "ddoc": nil, 96 "name": "_all_docs", 97 "type": "special", 98 "def": map[string]interface{}{"fields": []interface{}{map[string]string{"_id": "asc"}}}, 99 }, 100 Selector: map[string]interface{}{"_id": map[string]interface{}{"$gt": nil}}, 101 Options: map[string]interface{}{ 102 "bookmark": "nil", 103 "conflicts": false, 104 "fields": "all_fields", 105 "limit": limit, 106 "r": []int{49}, 107 "skip": 0, 108 "sort": map[string]interface{}{}, 109 "use_index": []interface{}{}, 110 }, 111 Limit: limit, 112 Range: map[string]interface{}{ 113 "start_key": nil, 114 "end_key": "\xef\xbf\xbd", 115 }, 116 } 117 } 118 expected.DBName = dbName 119 if d := testy.DiffAsJSON(expected, plan); d != nil { 120 ctx.Errorf("Unexpected plan returned:\n%s\n", d) 121 } 122 }