...

Source file src/github.com/go-kivik/kivik/v4/kiviktest/db/query.go

Documentation: github.com/go-kivik/kivik/v4/kiviktest/db

     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("Query", query)
    28  }
    29  
    30  func query(ctx *kt.Context) {
    31  	ctx.RunRW(func(ctx *kt.Context) {
    32  		testQueryRW(ctx)
    33  	})
    34  }
    35  
    36  func testQueryRW(ctx *kt.Context) {
    37  	if ctx.Admin == nil {
    38  		// Can't do anything here without admin access
    39  		return
    40  	}
    41  	dbName, expected, err := setUpQueryTest(ctx)
    42  	if err != nil {
    43  		ctx.Errorf("Failed to set up temp db: %s", err)
    44  	}
    45  	ctx.Run("group", func(ctx *kt.Context) {
    46  		ctx.RunAdmin(func(ctx *kt.Context) {
    47  			doQueryTest(ctx, ctx.Admin, dbName, 0, expected)
    48  		})
    49  		ctx.RunNoAuth(func(ctx *kt.Context) {
    50  			doQueryTest(ctx, ctx.NoAuth, dbName, 0, expected)
    51  		})
    52  	})
    53  }
    54  
    55  var ddoc = map[string]interface{}{
    56  	"_id":      "_design/testddoc",
    57  	"language": "javascript",
    58  	"views": map[string]interface{}{
    59  		"testview": map[string]interface{}{
    60  			"map": `function(doc) {
    61                  if (doc.include) {
    62                      emit(doc._id, doc.index);
    63                  }
    64              }`,
    65  		},
    66  	},
    67  }
    68  
    69  func setUpQueryTest(ctx *kt.Context) (dbName string, docIDs []string, err error) {
    70  	dbName = ctx.TestDB()
    71  	db := ctx.Admin.DB(dbName, ctx.Options("db"))
    72  	if err := db.Err(); err != nil {
    73  		return dbName, nil, fmt.Errorf("fialed to connect to db: %w", err)
    74  	}
    75  	if _, err := db.Put(context.Background(), ddoc["_id"].(string), ddoc); err != nil {
    76  		return dbName, nil, fmt.Errorf("fialed to create design doc: %w", err)
    77  	}
    78  	const maxDocs = 10
    79  	docIDs = make([]string, maxDocs)
    80  	for i := range docIDs {
    81  		id := ctx.TestDBName()
    82  		doc := struct {
    83  			ID      string `json:"id"`
    84  			Include bool   `json:"include"`
    85  			Index   int    `json:"index"`
    86  		}{
    87  			ID:      id,
    88  			Include: true,
    89  			Index:   i,
    90  		}
    91  		if _, err := db.Put(context.Background(), doc.ID, doc); err != nil {
    92  			return dbName, nil, fmt.Errorf("failed to create doc: %w", err)
    93  		}
    94  		docIDs[i] = id
    95  	}
    96  	sort.Strings(docIDs)
    97  	return dbName, docIDs, nil
    98  }
    99  
   100  func doQueryTest(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string) {
   101  	ctx.Run("WithDocs", func(ctx *kt.Context) {
   102  		doQueryTestWithDocs(ctx, client, dbName, expOffset, expected)
   103  	})
   104  	ctx.Run("WithoutDocs", func(ctx *kt.Context) {
   105  		doQueryTestWithoutDocs(ctx, client, dbName, expOffset, expected)
   106  	})
   107  }
   108  
   109  func doQueryTestWithoutDocs(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string) {
   110  	ctx.Parallel()
   111  	db := client.DB(dbName, ctx.Options("db"))
   112  	// Errors may be deferred here, so only return if we actually get
   113  	// an error.
   114  	if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) {
   115  		return
   116  	}
   117  
   118  	rows := db.Query(context.Background(), "testddoc", "testview")
   119  	if !ctx.IsExpectedSuccess(rows.Err()) {
   120  		return
   121  	}
   122  	docIDs := make([]string, 0, len(expected))
   123  	var scanTested bool
   124  	for rows.Next() {
   125  		id, _ := rows.ID()
   126  		docIDs = append(docIDs, id)
   127  		if !scanTested {
   128  			scanTested = true
   129  			ctx.Run("ScanDoc", func(ctx *kt.Context) {
   130  				var i interface{}
   131  				ctx.CheckError(rows.ScanDoc(&i))
   132  			})
   133  			ctx.Run("ScanValue", func(ctx *kt.Context) {
   134  				var i interface{}
   135  				ctx.CheckError(rows.ScanValue(&i))
   136  			})
   137  		}
   138  	}
   139  	meta, err := rows.Metadata()
   140  	if err != nil {
   141  		ctx.Fatalf("Failed to fetch row: %s", rows.Err())
   142  	}
   143  	if d := testy.DiffTextSlices(expected, docIDs); d != nil {
   144  		ctx.Errorf("Unexpected document IDs returned:\n%s\n", d)
   145  	}
   146  	if expOffset != meta.Offset {
   147  		ctx.Errorf("offset: Expected %d, got %d", expOffset, meta.Offset)
   148  	}
   149  	if int64(len(expected)) != meta.TotalRows {
   150  		ctx.Errorf("total rows: Expected %d, got %d", len(expected), meta.TotalRows)
   151  	}
   152  }
   153  
   154  func doQueryTestWithDocs(ctx *kt.Context, client *kivik.Client, dbName string, expOffset int64, expected []string) {
   155  	ctx.Parallel()
   156  	db := client.DB(dbName, ctx.Options("db"))
   157  	// Errors may be deferred here, so only return if we actually get
   158  	// an error.
   159  	if err := db.Err(); err != nil && !ctx.IsExpectedSuccess(err) {
   160  		return
   161  	}
   162  	opts := kivik.Params(map[string]interface{}{
   163  		"include_docs": true,
   164  		"update_seq":   true,
   165  	})
   166  
   167  	rows := db.Query(context.Background(), "testddoc", "testview", opts)
   168  	if !ctx.IsExpectedSuccess(rows.Err()) {
   169  		return
   170  	}
   171  	docIDs := make([]string, 0, len(expected))
   172  	for rows.Next() {
   173  		var doc struct {
   174  			ID    string `json:"_id"`
   175  			Rev   string `json:"_rev"`
   176  			Index int    `json:"index"`
   177  		}
   178  		if err := rows.ScanDoc(&doc); err != nil {
   179  			ctx.Errorf("Failed to scan doc: %s", err)
   180  		}
   181  		var value int
   182  		if err := rows.ScanValue(&value); err != nil {
   183  			ctx.Errorf("Failed to scan value: %s", err)
   184  		}
   185  		if value != doc.Index {
   186  			ctx.Errorf("doc._rev = %d, but value = %d", doc.Index, value)
   187  		}
   188  		id, _ := rows.ID()
   189  		if doc.ID != id {
   190  			ctx.Errorf("doc._id = %s, but rows.ID = %s", doc.ID, id)
   191  		}
   192  		docIDs = append(docIDs, id)
   193  	}
   194  	meta, err := rows.Metadata()
   195  	if err != nil {
   196  		ctx.Fatalf("Failed to fetch row: %s", rows.Err())
   197  	}
   198  	if d := testy.DiffTextSlices(expected, docIDs); d != nil {
   199  		ctx.Errorf("Unexpected document IDs returned:\n%s\n", d)
   200  	}
   201  	if expOffset != meta.Offset {
   202  		ctx.Errorf("offset: Expected %d, got %d", expOffset, meta.Offset)
   203  	}
   204  	ctx.Run("UpdateSeq", func(ctx *kt.Context) {
   205  		if meta.UpdateSeq == "" {
   206  			ctx.Errorf("Expected updated sequence")
   207  		}
   208  	})
   209  	if int64(len(expected)) != meta.TotalRows {
   210  		ctx.Errorf("total rows: Expected %d, got %d", len(expected), meta.TotalRows)
   211  	}
   212  }
   213  

View as plain text