...

Source file src/github.com/go-kivik/kivik/v4/x/fsdb/get_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  	"errors"
    18  	"io"
    19  	"net/http"
    20  	"testing"
    21  
    22  	"gitlab.com/flimzy/testy"
    23  
    24  	"github.com/go-kivik/kivik/v4"
    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/x/fsdb/filesystem"
    28  )
    29  
    30  func TestGet(t *testing.T) {
    31  	type tt struct {
    32  		fs           filesystem.Filesystem
    33  		setup        func(*testing.T, *db)
    34  		final        func(*testing.T, *db)
    35  		path, dbname string
    36  		id           string
    37  		options      kivik.Option
    38  		expected     *driver.Document
    39  		status       int
    40  		err          string
    41  	}
    42  	tests := testy.NewTable()
    43  	tests.Add("no id", tt{
    44  		path:   "",
    45  		dbname: "foo",
    46  		status: http.StatusBadRequest,
    47  		err:    "no docid specified",
    48  	})
    49  	tests.Add("not found", tt{
    50  		dbname: "asdf",
    51  		id:     "foo",
    52  		status: http.StatusNotFound,
    53  		err:    `^missing$`,
    54  	})
    55  	tests.Add("forbidden", func(*testing.T) interface{} {
    56  		return tt{
    57  			fs: &filesystem.MockFS{
    58  				OpenFunc: func(_ string) (filesystem.File, error) {
    59  					return nil, statusError{status: http.StatusForbidden, error: errors.New("permission denied")}
    60  				},
    61  			},
    62  			dbname: "foo",
    63  			id:     "foo",
    64  			status: http.StatusForbidden,
    65  			err:    "permission denied$",
    66  		}
    67  	})
    68  	tests.Add("success, no attachments", tt{
    69  		path:   "testdata",
    70  		dbname: "db_foo",
    71  		id:     "noattach",
    72  		expected: &driver.Document{
    73  			Rev: "1-xxxxxxxxxx",
    74  		},
    75  	})
    76  	tests.Add("success, attachment stub", tt{
    77  		path:   "testdata",
    78  		dbname: "db_foo",
    79  		id:     "withattach",
    80  		expected: &driver.Document{
    81  			Rev: "2-yyyyyyyyy",
    82  		},
    83  	})
    84  	tests.Add("success, include mp attachments", tt{
    85  		path:    "testdata",
    86  		dbname:  "db_foo",
    87  		id:      "withattach",
    88  		options: kivik.Param("attachments", true),
    89  		expected: &driver.Document{
    90  			Rev: "2-yyyyyyyyy",
    91  		},
    92  	})
    93  	tests.Add("success, include inline attachments", tt{
    94  		path:   "testdata",
    95  		dbname: "db_foo",
    96  		id:     "withattach",
    97  		options: kivik.Params(map[string]interface{}{
    98  			"attachments":   true,
    99  			"header:accept": "application/json",
   100  		}),
   101  		expected: &driver.Document{
   102  			Rev: "2-yyyyyyyyy",
   103  		},
   104  	})
   105  	tests.Add("specify current rev", tt{
   106  		path:    "testdata",
   107  		dbname:  "db_foo",
   108  		id:      "noattach",
   109  		options: kivik.Rev("1-xxxxxxxxxx"),
   110  		expected: &driver.Document{
   111  			Rev: "1-xxxxxxxxxx",
   112  		},
   113  	})
   114  	tests.Add("specify old rev", tt{
   115  		path:    "testdata",
   116  		dbname:  "db_foo",
   117  		id:      "withattach",
   118  		options: kivik.Rev("1-xxxxxxxxxx"),
   119  		expected: &driver.Document{
   120  			Rev: "1-xxxxxxxxxx",
   121  		},
   122  	})
   123  	tests.Add("autorev", tt{
   124  		path:   "testdata",
   125  		dbname: "db_foo",
   126  		id:     "autorev",
   127  		expected: &driver.Document{
   128  			Rev: "6-",
   129  		},
   130  	})
   131  	tests.Add("intrev", tt{
   132  		path:   "testdata",
   133  		dbname: "db_foo",
   134  		id:     "intrev",
   135  		expected: &driver.Document{
   136  			Rev: "6-",
   137  		},
   138  	})
   139  	tests.Add("norev", tt{
   140  		path:   "testdata",
   141  		dbname: "db_foo",
   142  		id:     "norev",
   143  		expected: &driver.Document{
   144  			Rev: "1-",
   145  		},
   146  	})
   147  	tests.Add("noid", tt{
   148  		path:   "testdata",
   149  		dbname: "db_foo",
   150  		id:     "noid",
   151  		expected: &driver.Document{
   152  			Rev: "6-",
   153  		},
   154  	})
   155  	tests.Add("wrong id", tt{
   156  		path:   "testdata",
   157  		dbname: "db_foo",
   158  		id:     "wrongid",
   159  		expected: &driver.Document{
   160  			Rev: "6-",
   161  		},
   162  	})
   163  	tests.Add("yaml", tt{
   164  		path:   "testdata",
   165  		dbname: "db_foo",
   166  		id:     "yamltest",
   167  		expected: &driver.Document{
   168  			Rev: "3-",
   169  		},
   170  	})
   171  	tests.Add("specify current rev yaml", tt{
   172  		path:    "testdata",
   173  		dbname:  "db_foo",
   174  		id:      "yamltest",
   175  		options: kivik.Rev("3-"),
   176  		expected: &driver.Document{
   177  			Rev: "3-",
   178  		},
   179  	})
   180  	tests.Add("specify old rev yaml", tt{
   181  		path:    "testdata",
   182  		dbname:  "db_foo",
   183  		id:      "yamltest",
   184  		options: kivik.Rev("2-xxx"),
   185  		expected: &driver.Document{
   186  			Rev: "2-xxx",
   187  		},
   188  	})
   189  	tests.Add("specify bogus rev yaml", tt{
   190  		path:    "testdata",
   191  		dbname:  "db_foo",
   192  		id:      "yamltest",
   193  		options: kivik.Rev("1-oink"),
   194  		status:  http.StatusNotFound,
   195  		err:     "missing",
   196  	})
   197  	tests.Add("ddoc yaml", tt{
   198  		path:   "testdata",
   199  		dbname: "db_foo",
   200  		id:     "_design/users",
   201  		expected: &driver.Document{
   202  			Rev: "2-",
   203  		},
   204  	})
   205  	tests.Add("ddoc rev yaml", tt{
   206  		path:    "testdata",
   207  		dbname:  "db_foo",
   208  		id:      "_design/users",
   209  		options: kivik.Rev("2-"),
   210  		expected: &driver.Document{
   211  			Rev: "2-",
   212  		},
   213  	})
   214  	tests.Add("revs", tt{
   215  		path:    "testdata",
   216  		dbname:  "db_foo",
   217  		id:      "wrongid",
   218  		options: kivik.Param("revs", true),
   219  		expected: &driver.Document{
   220  			Rev: "6-",
   221  		},
   222  	})
   223  	tests.Add("revs real", tt{
   224  		path:    "testdata",
   225  		dbname:  "db_foo",
   226  		id:      "noattach",
   227  		options: kivik.Param("revs", true),
   228  		expected: &driver.Document{
   229  			Rev: "1-xxxxxxxxxx",
   230  		},
   231  	})
   232  	tests.Add("note--XkWjFv13acvjJTt-CGJJ8hXlWE", tt{
   233  		path:   "testdata",
   234  		dbname: "db_att",
   235  		id:     "note--XkWjFv13acvjJTt-CGJJ8hXlWE",
   236  		expected: &driver.Document{
   237  			Rev: "1-fbaabe005e0f4e5685a68f857c0777d6",
   238  		},
   239  	})
   240  	tests.Add("note--XkWjFv13acvjJTt-CGJJ8hXlWE + attachments", tt{
   241  		path:    "testdata",
   242  		dbname:  "db_att",
   243  		id:      "note--XkWjFv13acvjJTt-CGJJ8hXlWE",
   244  		options: kivik.Param("attachments", true),
   245  		expected: &driver.Document{
   246  			Rev: "1-fbaabe005e0f4e5685a68f857c0777d6",
   247  		},
   248  	})
   249  	tests.Add("revs_info=true", tt{
   250  		path:    "testdata",
   251  		dbname:  "db_foo",
   252  		id:      "autorev",
   253  		options: kivik.Param("revs_info", true),
   254  		expected: &driver.Document{
   255  			Rev: "6-",
   256  		},
   257  	})
   258  	tests.Add("revs, explicit", tt{
   259  		path:    "testdata",
   260  		dbname:  "db_foo",
   261  		id:      "withrevs",
   262  		options: kivik.Param("revs", true),
   263  		expected: &driver.Document{
   264  			Rev: "8-asdf",
   265  		},
   266  	})
   267  	tests.Add("specify current rev, revs_info=true", tt{
   268  		path:   "testdata",
   269  		dbname: "db_foo",
   270  		id:     "yamltest",
   271  		options: kivik.Params(map[string]interface{}{
   272  			"rev":       "3-",
   273  			"revs_info": true,
   274  		}),
   275  		expected: &driver.Document{
   276  			Rev: "3-",
   277  		},
   278  	})
   279  	tests.Add("specify conflicting rev, revs_info=true", tt{
   280  		path:   "testdata",
   281  		dbname: "db_foo",
   282  		id:     "yamltest",
   283  		options: kivik.Params(map[string]interface{}{
   284  			"rev":       "2-xxx",
   285  			"revs_info": true,
   286  		}),
   287  		expected: &driver.Document{
   288  			Rev: "2-xxx",
   289  		},
   290  	})
   291  	tests.Add("specify rev, revs=true", tt{
   292  		path:   "testdata",
   293  		dbname: "db_foo",
   294  		id:     "withrevs",
   295  		options: kivik.Params(map[string]interface{}{
   296  			"rev":  "8-asdf",
   297  			"revs": true,
   298  		}),
   299  		expected: &driver.Document{
   300  			Rev: "8-asdf",
   301  		},
   302  	})
   303  	tests.Add("interrupted put", tt{
   304  		// This tests a put which was aborted, leaving the attachments in
   305  		// {db}/.{docid}/{rev}/{filename}, while the winning rev is at
   306  		// the friendlier location of {db}/{docid}.{ext}
   307  		path:    "testdata",
   308  		dbname:  "db_foo",
   309  		id:      "abortedput",
   310  		options: kivik.Param("attachments", true),
   311  		expected: &driver.Document{
   312  			Rev: "2-yyyyyyyyy",
   313  		},
   314  	})
   315  	tests.Add("no winner, tied rev", tt{
   316  		// This tests a put which was aborted, leaving the attachments in
   317  		// {db}/.{docid}/{rev}/{filename}, while the winning rev is at
   318  		// the friendlier location of {db}/{docid}.{ext}
   319  		path:   "testdata",
   320  		dbname: "get_nowinner",
   321  		id:     "foo",
   322  		expected: &driver.Document{
   323  			Rev: "1-yyy",
   324  		},
   325  	})
   326  	tests.Add("no winner, greater rev", tt{
   327  		// This tests a put which was aborted, leaving the attachments in
   328  		// {db}/.{docid}/{rev}/{filename}, while the winning rev is at
   329  		// the friendlier location of {db}/{docid}.{ext}
   330  		path:   "testdata",
   331  		dbname: "get_nowinner",
   332  		id:     "bar",
   333  		expected: &driver.Document{
   334  			Rev: "2-yyy",
   335  		},
   336  	})
   337  	tests.Add("atts split between winning and revs dir", tt{
   338  		path:    "testdata",
   339  		dbname:  "get_split_atts",
   340  		id:      "foo",
   341  		options: kivik.Param("attachments", true),
   342  		expected: &driver.Document{
   343  			Rev: "2-zzz",
   344  		},
   345  	})
   346  	tests.Add("atts split between two revs", tt{
   347  		path:    "testdata",
   348  		dbname:  "get_split_atts",
   349  		id:      "bar",
   350  		options: kivik.Param("attachments", true),
   351  		expected: &driver.Document{
   352  			Rev: "2-yyy",
   353  		},
   354  	})
   355  	tests.Add("non-standard filenames", tt{
   356  		path:   "testdata",
   357  		dbname: "db_nonascii",
   358  		id:     "note-i_ɪ",
   359  		expected: &driver.Document{
   360  			Rev: "1-",
   361  		},
   362  	})
   363  	tests.Add("deleted doc", tt{
   364  		path:   "testdata",
   365  		dbname: "db_foo",
   366  		id:     "deleted",
   367  		status: http.StatusNotFound,
   368  		err:    "deleted",
   369  	})
   370  	tests.Add("deleted doc, specific rev", tt{
   371  		path:    "testdata",
   372  		dbname:  "db_foo",
   373  		id:      "deleted",
   374  		options: kivik.Rev("3-"),
   375  		expected: &driver.Document{
   376  			Rev: "3-",
   377  		},
   378  	})
   379  
   380  	tests.Run(t, func(t *testing.T, tt tt) {
   381  		dir := tt.path
   382  		if dir == "" {
   383  			dir = tempDir(t)
   384  			t.Cleanup(func() {
   385  				rmdir(t, dir)
   386  			})
   387  		}
   388  		fs := tt.fs
   389  		if fs == nil {
   390  			fs = filesystem.Default()
   391  		}
   392  		c := &client{root: dir, fs: fs}
   393  		db, err := c.newDB(tt.dbname)
   394  		if err != nil {
   395  			t.Fatal(err)
   396  		}
   397  		if tt.setup != nil {
   398  			tt.setup(t, db)
   399  		}
   400  		opts := tt.options
   401  		if opts == nil {
   402  			opts = kivik.Params(nil)
   403  		}
   404  		result, err := db.Get(context.Background(), tt.id, opts)
   405  		if d := internal.StatusErrorDiffRE(tt.err, tt.status, err); d != "" {
   406  			t.Error(d)
   407  		}
   408  		if err != nil {
   409  			return
   410  		}
   411  		if d := testy.DiffAsJSON(testy.Snapshot(t), result.Body); d != nil {
   412  			t.Errorf("document:\n%s", d)
   413  		}
   414  		if result.Attachments != nil {
   415  			attachments := result.Attachments
   416  			t.Cleanup(func() {
   417  				_ = attachments.Close()
   418  			})
   419  			att := &driver.Attachment{}
   420  			for {
   421  				if err := result.Attachments.Next(att); err != nil {
   422  					if err == io.EOF {
   423  						break
   424  					}
   425  					t.Fatal(err)
   426  				}
   427  				if d := testy.DiffText(&testy.File{Path: "testdata/" + testy.Stub(t) + "_" + att.Filename}, att.Content); d != nil {
   428  					t.Errorf("Attachment %s content:\n%s", att.Filename, d)
   429  				}
   430  				_ = att.Content.Close()
   431  				att.Content = nil
   432  				if d := testy.DiffAsJSON(&testy.File{Path: "testdata/" + testy.Stub(t) + "_" + att.Filename + "_struct"}, att); d != nil {
   433  					t.Errorf("Attachment %s struct:\n%s", att.Filename, d)
   434  				}
   435  			}
   436  		}
   437  		result.Body = nil
   438  		result.Attachments = nil
   439  		if d := testy.DiffInterface(tt.expected, result); d != nil {
   440  			t.Error(d)
   441  		}
   442  		if tt.final != nil {
   443  			tt.final(t, db)
   444  		}
   445  	})
   446  }
   447  

View as plain text