...

Source file src/github.com/go-kivik/kivik/v4/kiviktest/db/alldocs.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 provides integration tests for the kivik db.
    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  		// Can't do anything here without admin access
    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  	// 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.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  	// Errors may be deferred here, so only return if we actually get
   146  	// an error.
   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