...

Source file src/github.com/go-kivik/kivik/v4/bulk_test.go

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

     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 kivik
    14  
    15  import (
    16  	"context"
    17  	"encoding/json"
    18  	"errors"
    19  	"fmt"
    20  	"net/http"
    21  	"testing"
    22  
    23  	"gitlab.com/flimzy/testy"
    24  
    25  	"github.com/go-kivik/kivik/v4/driver"
    26  	internal "github.com/go-kivik/kivik/v4/int/errors"
    27  	"github.com/go-kivik/kivik/v4/int/mock"
    28  )
    29  
    30  func TestDocsInterfaceSlice(t *testing.T) {
    31  	type diTest struct {
    32  		name     string
    33  		input    []interface{}
    34  		expected interface{}
    35  		status   int
    36  		err      string
    37  	}
    38  	tests := []diTest{
    39  		{
    40  			name:     "InterfaceSlice",
    41  			input:    []interface{}{map[string]string{"foo": "bar"}},
    42  			expected: []interface{}{map[string]string{"foo": "bar"}},
    43  		},
    44  		{
    45  			name: "JSONDoc",
    46  			input: []interface{}{
    47  				map[string]string{"foo": "bar"},
    48  				json.RawMessage(`{"foo":"bar"}`),
    49  			},
    50  			expected: []interface{}{
    51  				map[string]string{"foo": "bar"},
    52  				map[string]string{"foo": "bar"},
    53  			},
    54  		},
    55  	}
    56  	for _, test := range tests {
    57  		func(test diTest) {
    58  			t.Run(test.name, func(t *testing.T) {
    59  				result, err := docsInterfaceSlice(test.input)
    60  				if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
    61  					t.Error(d)
    62  				}
    63  				if d := testy.DiffAsJSON(test.expected, result); d != nil {
    64  					t.Errorf("%s", d)
    65  				}
    66  			})
    67  		}(test)
    68  	}
    69  }
    70  
    71  func TestBulkDocs(t *testing.T) { // nolint: gocyclo
    72  	type tt struct {
    73  		db       *DB
    74  		docs     []interface{}
    75  		options  Option
    76  		expected []BulkResult
    77  		status   int
    78  		err      string
    79  	}
    80  
    81  	tests := testy.NewTable()
    82  	tests.Add("invalid JSON", tt{
    83  		db: &DB{
    84  			client: &Client{},
    85  			driverDB: &mock.BulkDocer{
    86  				BulkDocsFunc: func(_ context.Context, docs []interface{}, _ driver.Options) ([]driver.BulkResult, error) {
    87  					_, err := json.Marshal(docs)
    88  					return nil, err
    89  				},
    90  			},
    91  		},
    92  		docs:   []interface{}{json.RawMessage("invalid json")},
    93  		status: http.StatusInternalServerError,
    94  		err:    "json: error calling MarshalJSON for type json.RawMessage: invalid character 'i' looking for beginning of value",
    95  	})
    96  	tests.Add("emulated BulkDocs support", tt{
    97  		db: &DB{
    98  			client: &Client{},
    99  			driverDB: &mock.DocCreator{
   100  				DB: mock.DB{
   101  					PutFunc: func(_ context.Context, docID string, doc interface{}, options driver.Options) (string, error) {
   102  						if docID == "error" {
   103  							return "", errors.New("error")
   104  						}
   105  						if docID != "foo" { // nolint: goconst
   106  							return "", fmt.Errorf("Unexpected docID: %s", docID)
   107  						}
   108  						expectedDoc := map[string]string{"_id": "foo"}
   109  						if d := testy.DiffInterface(expectedDoc, doc); d != nil {
   110  							return "", fmt.Errorf("Unexpected doc:\n%s", d)
   111  						}
   112  						gotOpts := map[string]interface{}{}
   113  						options.Apply(gotOpts)
   114  						if d := testy.DiffInterface(testOptions, gotOpts); d != nil {
   115  							return "", fmt.Errorf("Unexpected opts:\n%s", d)
   116  						}
   117  						return "2-xxx", nil // nolint: goconst
   118  					},
   119  				},
   120  				CreateDocFunc: func(_ context.Context, doc interface{}, options driver.Options) (string, string, error) {
   121  					gotOpts := map[string]interface{}{}
   122  					options.Apply(gotOpts)
   123  					expectedDoc := int(123)
   124  					if d := testy.DiffInterface(expectedDoc, doc); d != nil {
   125  						return "", "", fmt.Errorf("Unexpected doc:\n%s", d)
   126  					}
   127  					if d := testy.DiffInterface(testOptions, gotOpts); d != nil {
   128  						return "", "", fmt.Errorf("Unexpected opts:\n%s", d)
   129  					}
   130  					return "newDocID", "1-xxx", nil // nolint: goconst
   131  				},
   132  			},
   133  		},
   134  		docs: []interface{}{
   135  			map[string]string{"_id": "foo"},
   136  			123,
   137  			map[string]string{"_id": "error"},
   138  		},
   139  		options: Params(testOptions),
   140  		expected: []BulkResult{
   141  			{ID: "foo", Rev: "2-xxx"},
   142  			{ID: "newDocID", Rev: "1-xxx"},
   143  			{ID: "error", Error: errors.New("error")},
   144  		},
   145  	})
   146  	tests.Add("new_edits", tt{
   147  		db: &DB{
   148  			client: &Client{},
   149  			driverDB: &mock.BulkDocer{
   150  				BulkDocsFunc: func(_ context.Context, docs []interface{}, options driver.Options) ([]driver.BulkResult, error) {
   151  					expectedDocs := []interface{}{map[string]string{"_id": "foo"}, 123}
   152  					wantOpts := map[string]interface{}{"new_edits": true}
   153  					gotOpts := map[string]interface{}{}
   154  					options.Apply(gotOpts)
   155  					if d := testy.DiffInterface(expectedDocs, docs); d != nil {
   156  						return nil, fmt.Errorf("Unexpected docs:\n%s", d)
   157  					}
   158  					if d := testy.DiffInterface(wantOpts, gotOpts); d != nil {
   159  						return nil, fmt.Errorf("Unexpected opts:\n%s", d)
   160  					}
   161  					return []driver.BulkResult{
   162  						{ID: "foo"},
   163  					}, nil
   164  				},
   165  			},
   166  		},
   167  		docs: []interface{}{
   168  			map[string]string{"_id": "foo"},
   169  			123,
   170  		},
   171  		options: Param("new_edits", true),
   172  		expected: []BulkResult{
   173  			{ID: "foo"},
   174  		},
   175  	})
   176  	tests.Add("client closed", tt{
   177  		db: &DB{
   178  			client: &Client{
   179  				closed: true,
   180  			},
   181  		},
   182  		docs: []interface{}{
   183  			map[string]string{"_id": "foo"},
   184  		},
   185  		status: http.StatusServiceUnavailable,
   186  		err:    "kivik: client closed",
   187  	})
   188  	tests.Add("db error", tt{
   189  		db: &DB{
   190  			err: errors.New("db error"),
   191  		},
   192  		status: http.StatusInternalServerError,
   193  		err:    "db error",
   194  	})
   195  	tests.Add("unreadable doc", tt{
   196  		db: &DB{
   197  			client: &Client{},
   198  			driverDB: &mock.BulkDocer{
   199  				BulkDocsFunc: func(_ context.Context, docs []interface{}, _ driver.Options) ([]driver.BulkResult, error) {
   200  					_, err := json.Marshal(docs)
   201  					return nil, err
   202  				},
   203  			},
   204  		},
   205  		docs:   []interface{}{testy.ErrorReader("", errors.New("read error"))},
   206  		status: http.StatusBadRequest,
   207  		err:    "read error",
   208  	})
   209  	tests.Add("no docs", tt{
   210  		db: &DB{
   211  			client: &Client{},
   212  			driverDB: &mock.BulkDocer{
   213  				BulkDocsFunc: func(_ context.Context, docs []interface{}, _ driver.Options) ([]driver.BulkResult, error) {
   214  					_, err := json.Marshal(docs)
   215  					return nil, err
   216  				},
   217  			},
   218  		},
   219  		docs:   []interface{}{},
   220  		status: http.StatusBadRequest,
   221  		err:    "kivik: no documents provided",
   222  	})
   223  
   224  	tests.Run(t, func(t *testing.T, tt tt) {
   225  		result, err := tt.db.BulkDocs(context.Background(), tt.docs, tt.options)
   226  		if d := internal.StatusErrorDiff(tt.err, tt.status, err); d != "" {
   227  			t.Error(d)
   228  		}
   229  		if d := testy.DiffInterface(tt.expected, result); d != nil {
   230  			t.Error(d)
   231  		}
   232  	})
   233  }
   234  

View as plain text