...

Source file src/github.com/go-kivik/kivik/v4/x/fsdb/put_test.go

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

     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 fs
    14  
    15  import (
    16  	"context"
    17  	"net/http"
    18  	"os"
    19  	"path/filepath"
    20  	"testing"
    21  
    22  	"gitlab.com/flimzy/testy"
    23  
    24  	"github.com/go-kivik/kivik/v4"
    25  	internal "github.com/go-kivik/kivik/v4/int/errors"
    26  	"github.com/go-kivik/kivik/v4/x/fsdb/filesystem"
    27  )
    28  
    29  func TestPut(t *testing.T) {
    30  	if isGopherJS117 {
    31  		t.Skip("Tests broken for GopherJS 1.17")
    32  	}
    33  
    34  	type tt struct {
    35  		fs       filesystem.Filesystem
    36  		path     string
    37  		dbname   string
    38  		id       string
    39  		doc      interface{}
    40  		options  kivik.Option
    41  		status   int
    42  		err      string
    43  		expected string
    44  	}
    45  	tests := testy.NewTable()
    46  	tests.Add("invalid docID", tt{
    47  		path:   "doesntmatter",
    48  		dbname: "doesntmatter",
    49  		id:     "_foo",
    50  		status: http.StatusBadRequest,
    51  		err:    "only reserved document ids may start with underscore",
    52  	})
    53  	tests.Add("invalid document", tt{
    54  		path:   "doesntmatter",
    55  		dbname: "doesntmatter",
    56  		id:     "foo",
    57  		doc:    make(chan int),
    58  		status: http.StatusBadRequest,
    59  		err:    "json: unsupported type: chan int",
    60  	})
    61  	tests.Add("create with revid", func(t *testing.T) interface{} {
    62  		tmpdir := tempDir(t)
    63  		tests.Cleanup(cleanTmpdir(tmpdir))
    64  		if err := os.Mkdir(filepath.Join(tmpdir, "foo"), 0o777); err != nil {
    65  			t.Fatal(err)
    66  		}
    67  
    68  		return tt{
    69  			path:   tmpdir,
    70  			dbname: "foo",
    71  			id:     "foo",
    72  			doc:    map[string]string{"foo": "bar", "_rev": "1-xxx"},
    73  			status: http.StatusConflict,
    74  			err:    "document update conflict",
    75  		}
    76  	})
    77  	tests.Add("simple create", func(t *testing.T) interface{} {
    78  		tmpdir := tempDir(t)
    79  		tests.Cleanup(cleanTmpdir(tmpdir))
    80  		if err := os.Mkdir(filepath.Join(tmpdir, "foo"), 0o777); err != nil {
    81  			t.Fatal(err)
    82  		}
    83  
    84  		return tt{
    85  			path:     tmpdir,
    86  			dbname:   "foo",
    87  			id:       "foo",
    88  			doc:      map[string]string{"foo": "bar"},
    89  			expected: "1-04edfaf9abdaed3c0accf6c463e78fd4",
    90  		}
    91  	})
    92  	tests.Add("update conflict, doc key", func(t *testing.T) interface{} {
    93  		tmpdir := testy.CopyTempDir(t, "testdata/db_put", 1)
    94  		tests.Cleanup(cleanTmpdir(tmpdir))
    95  
    96  		return tt{
    97  			path:   tmpdir,
    98  			dbname: "db_put",
    99  			id:     "foo",
   100  			doc:    map[string]string{"foo": "bar", "_rev": "2-asdf"},
   101  			status: http.StatusConflict,
   102  			err:    "document update conflict",
   103  		}
   104  	})
   105  	tests.Add("update conflict, options", func(t *testing.T) interface{} {
   106  		tmpdir := testy.CopyTempDir(t, "testdata/db_put", 1)
   107  		tests.Cleanup(cleanTmpdir(tmpdir))
   108  
   109  		return tt{
   110  			path:    tmpdir,
   111  			dbname:  "db_put",
   112  			id:      "foo",
   113  			doc:     map[string]string{"foo": "bar"},
   114  			options: kivik.Rev("2-asdf"),
   115  			status:  http.StatusConflict,
   116  			err:     "document update conflict",
   117  		}
   118  	})
   119  	tests.Add("no explicit rev", func(t *testing.T) interface{} {
   120  		tmpdir := testy.CopyTempDir(t, "testdata/db_put", 1)
   121  		tests.Cleanup(cleanTmpdir(tmpdir))
   122  
   123  		return tt{
   124  			path:   tmpdir,
   125  			dbname: "db_put",
   126  			id:     "foo",
   127  			doc:    map[string]string{"foo": "bar"},
   128  			status: http.StatusConflict,
   129  			err:    "document update conflict",
   130  		}
   131  	})
   132  	tests.Add("revs mismatch", tt{
   133  		path:    "/tmp",
   134  		dbname:  "doesntmatter",
   135  		id:      "foo",
   136  		doc:     map[string]string{"foo": "bar", "_rev": "2-asdf"},
   137  		options: kivik.Rev("3-asdf"),
   138  		status:  http.StatusBadRequest,
   139  		err:     "document rev from request body and query string have different values",
   140  	})
   141  	tests.Add("proper update", func(t *testing.T) interface{} {
   142  		tmpdir := testy.CopyTempDir(t, "testdata/db_put", 1)
   143  		tests.Cleanup(cleanTmpdir(tmpdir))
   144  
   145  		return tt{
   146  			path:     tmpdir,
   147  			dbname:   "db_put",
   148  			id:       "foo",
   149  			doc:      map[string]string{"foo": "quxx", "_rev": "1-beea34a62a215ab051862d1e5d93162e"},
   150  			expected: "2-ff3a4f106331244679a6cac83a74ae48",
   151  		}
   152  	})
   153  	tests.Add("design doc", func(t *testing.T) interface{} {
   154  		tmpdir := tempDir(t)
   155  		tests.Cleanup(cleanTmpdir(tmpdir))
   156  		if err := os.Mkdir(filepath.Join(tmpdir, "foo"), 0o777); err != nil {
   157  			t.Fatal(err)
   158  		}
   159  
   160  		return tt{
   161  			path:     tmpdir,
   162  			dbname:   "foo",
   163  			id:       "_design/foo",
   164  			doc:      map[string]string{"foo": "bar"},
   165  			expected: "1-04edfaf9abdaed3c0accf6c463e78fd4",
   166  		}
   167  	})
   168  	tests.Add("invalid doc id", tt{
   169  		path:   "/tmp",
   170  		dbname: "doesntmatter",
   171  		id:     "_oink",
   172  		doc:    map[string]string{"foo": "bar"},
   173  		status: http.StatusBadRequest,
   174  		err:    "only reserved document ids may start with underscore",
   175  	})
   176  	tests.Add("invalid attachments", tt{
   177  		path:   "/tmp",
   178  		dbname: "doesntmatter",
   179  		id:     "foo",
   180  		doc: map[string]interface{}{
   181  			"foo":          "bar",
   182  			"_attachments": 123,
   183  		},
   184  		status: http.StatusBadRequest,
   185  		err:    "json: cannot unmarshal number into Go struct field RevMeta._attachments of type map[string]*cdb.Attachment",
   186  	})
   187  	tests.Add("attachment", func(t *testing.T) interface{} {
   188  		tmpdir := tempDir(t)
   189  		tests.Cleanup(cleanTmpdir(tmpdir))
   190  		if err := os.Mkdir(filepath.Join(tmpdir, "foo"), 0o777); err != nil {
   191  			t.Fatal(err)
   192  		}
   193  
   194  		return tt{
   195  			path:   tmpdir,
   196  			dbname: "foo",
   197  			id:     "foo",
   198  			doc: map[string]interface{}{
   199  				"foo": "bar",
   200  				"_attachments": map[string]interface{}{
   201  					"foo.txt": map[string]interface{}{
   202  						"content_type": "text/plain",
   203  						"data":         []byte("Testing"),
   204  					},
   205  				},
   206  			},
   207  			expected: "1-c706e75b505ddddeed04b959cfcb0ace",
   208  		}
   209  	})
   210  	tests.Add("new_edits=false, no rev", func(t *testing.T) interface{} {
   211  		tmpdir := tempDir(t)
   212  		tests.Cleanup(cleanTmpdir(tmpdir))
   213  		if err := os.Mkdir(filepath.Join(tmpdir, "foo"), 0o777); err != nil {
   214  			t.Fatal(err)
   215  		}
   216  
   217  		return tt{
   218  			path:   tmpdir,
   219  			dbname: "foo",
   220  			id:     "foo",
   221  			doc: map[string]string{
   222  				"foo": "bar",
   223  			},
   224  			options: kivik.Param("new_edits", false),
   225  			status:  http.StatusBadRequest,
   226  			err:     "_rev required with new_edits=false",
   227  		}
   228  	})
   229  	tests.Add("new_edits=false, rev already exists", func(t *testing.T) interface{} {
   230  		tmpdir := testy.CopyTempDir(t, "testdata/db_put", 1)
   231  		tests.Cleanup(cleanTmpdir(tmpdir))
   232  
   233  		return tt{
   234  			path:   tmpdir,
   235  			dbname: "db_put",
   236  			id:     "foo",
   237  			doc: map[string]string{
   238  				"_rev": "1-beea34a62a215ab051862d1e5d93162e",
   239  				"foo":  "bar",
   240  			},
   241  			options:  kivik.Param("new_edits", false),
   242  			expected: "1-beea34a62a215ab051862d1e5d93162e",
   243  		}
   244  	})
   245  	tests.Add("new_edits=false", func(t *testing.T) interface{} {
   246  		tmpdir := testy.CopyTempDir(t, "testdata/db_put", 1)
   247  		tests.Cleanup(cleanTmpdir(tmpdir))
   248  
   249  		return tt{
   250  			path:   tmpdir,
   251  			dbname: "db_put",
   252  			id:     "foo",
   253  			doc: map[string]string{
   254  				"_rev": "1-other",
   255  				"foo":  "bar",
   256  			},
   257  			options:  kivik.Param("new_edits", false),
   258  			expected: "1-other",
   259  		}
   260  	})
   261  
   262  	tests.Run(t, func(t *testing.T, tt tt) {
   263  		if tt.path == "" {
   264  			t.Fatalf("path must be set")
   265  		}
   266  		fs := tt.fs
   267  		if fs == nil {
   268  			fs = filesystem.Default()
   269  		}
   270  		c := &client{root: tt.path, fs: fs}
   271  		db, err := c.newDB(tt.dbname)
   272  		if err != nil {
   273  			t.Fatal(err)
   274  		}
   275  		opts := tt.options
   276  		if opts == nil {
   277  			opts = kivik.Params(nil)
   278  		}
   279  		rev, err := db.Put(context.Background(), tt.id, tt.doc, opts)
   280  		if d := internal.StatusErrorDiff(tt.err, tt.status, err); d != "" {
   281  			t.Error(d)
   282  		}
   283  		if err != nil {
   284  			return
   285  		}
   286  		if rev != tt.expected {
   287  			t.Errorf("Unexpected rev returned: %s", rev)
   288  		}
   289  		if d := testy.DiffAsJSON(testy.Snapshot(t), testy.JSONDir{
   290  			Path:        tt.path,
   291  			NoMD5Sum:    true,
   292  			FileContent: true,
   293  		}); d != nil {
   294  			t.Error(d)
   295  		}
   296  	})
   297  }
   298  

View as plain text