github.com/thiagoyeds/go-cloud@v0.26.0/docstore/docstore_test.go (about) 1 // Copyright 2019 The Go Cloud Development Kit Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package docstore 16 17 import ( 18 "context" 19 "reflect" 20 "testing" 21 "time" 22 23 "github.com/google/go-cmp/cmp" 24 "gocloud.dev/docstore/driver" 25 "gocloud.dev/gcerrors" 26 ) 27 28 type Book struct { 29 Title string `docstore:"key"` 30 Author Name `docstore:"author"` 31 PublicationYears []int `docstore:"pub_years,omitempty"` 32 NumPublications int `docstore:"-"` 33 } 34 35 type Name struct { 36 First, Last string 37 } 38 39 func TestIsIncNumber(t *testing.T) { 40 for _, x := range []interface{}{int(1), 'x', uint(1), byte(1), float32(1), float64(1), time.Duration(1)} { 41 if !isIncNumber(x) { 42 t.Errorf("%v: got false, want true", x) 43 } 44 } 45 for _, x := range []interface{}{1 + 1i, "3", time.Time{}} { 46 if isIncNumber(x) { 47 t.Errorf("%v: got true, want false", x) 48 } 49 } 50 } 51 52 func TestActionsDo(t *testing.T) { 53 c := newCollection(fakeDriverCollection{}) 54 defer c.Close() 55 dn := map[string]interface{}{"key": nil} 56 d1 := map[string]interface{}{"key": 1} 57 d2 := map[string]interface{}{"key": 2} 58 dsn := &Book{} 59 ds1 := &Book{Title: "The Master and Margarita"} 60 ds2 := &Book{Title: "The Martian"} 61 62 for _, test := range []struct { 63 alist *ActionList 64 want []int // error indexes; nil if no error 65 }{ 66 {c.Actions().Get(d1).Get(d2).Get(ds1).Get(ds2), nil}, 67 {c.Actions().Get(d1).Put(d1).Put(ds1).Get(ds1), nil}, 68 {c.Actions().Get(d2).Replace(d1).Put(d2).Get(d1), nil}, 69 {c.Actions().Get(ds2).Replace(ds1).Put(ds2).Get(ds1), nil}, 70 // Missing keys. 71 {c.Actions().Put(dn).Put(dsn), []int{0, 1}}, 72 {c.Actions().Get(dn).Replace(dn).Create(dn).Update(dn, Mods{"a": 1}), []int{0, 1, 3}}, 73 {c.Actions().Get(dsn).Replace(dsn).Create(dsn).Update(dsn, Mods{"a": 1}), []int{0, 1, 3}}, 74 // Duplicate documents. 75 {c.Actions().Create(dn).Create(dn).Create(dsn).Create(dsn), nil}, // each Create without a key is a separate document 76 {c.Actions().Create(d2).Create(ds2).Get(d2).Get(ds2).Create(d2).Put(ds2), []int{4, 5}}, 77 {c.Actions().Get(d1).Get(ds1).Get(d1).Get(ds1), []int{2, 3}}, 78 {c.Actions().Put(d1).Put(ds1).Get(d1).Get(ds1).Get(d1).Get(ds1), []int{4, 5}}, 79 {c.Actions().Get(d1).Get(ds1).Put(d1).Put(d2).Put(ds1).Put(ds2).Put(d1).Replace(ds1), []int{6, 7}}, 80 {c.Actions().Create(dn).Create(d1).Create(dsn).Create(ds1).Get(d1).Get(ds1), nil}, 81 // Get with field paths. 82 {c.Actions().Get(d1, "a.b", "c"), nil}, 83 {c.Actions().Get(ds1, "name.Last", "pub_years"), nil}, 84 {c.Actions().Get(d1, ".c").Get(ds1, "").Get(ds2, "\xa0\xa1"), []int{0, 1, 2}}, // bad field path 85 // Mods. 86 {c.Actions().Update(d1, nil).Update(ds1, nil), []int{0, 1}}, // empty mod 87 {c.Actions().Update(d1, Mods{"a.b.c": 1, "a.b": 2, "a.b+c": 3}), []int{0}}, // a.b is a prefix of a.b.c 88 {c.Actions().Update(d1, Mods{"": 1}).Update(ds1, Mods{".f": 2}), []int{0, 1}}, // invalid field path 89 {c.Actions().Update(d1, Mods{"a": Increment(true)}).Update(ds1, Mods{"name": Increment("b")}), []int{0, 1}}, // invalid incOp 90 } { 91 err := test.alist.Do(context.Background()) 92 if err == nil { 93 if len(test.want) > 0 { 94 t.Errorf("%s: got nil, want error", test.alist) 95 } 96 continue 97 } 98 var got []int 99 for _, e := range err.(ActionListError) { 100 if gcerrors.Code(e.Err) != gcerrors.InvalidArgument { 101 t.Errorf("%s: got %v, want InvalidArgument", test.alist, e.Err) 102 } 103 got = append(got, e.Index) 104 } 105 if !cmp.Equal(got, test.want) { 106 t.Errorf("%s: got %v, want %v", test.alist, got, test.want) 107 } 108 } 109 } 110 111 func TestClosedErrors(t *testing.T) { 112 // Check that all collection methods return errClosed if the collection is closed. 113 ctx := context.Background() 114 c := NewCollection(fakeDriverCollection{}) 115 if err := c.Close(); err != nil { 116 t.Fatalf("got %v, want nil", err) 117 } 118 119 check := func(err error) { 120 t.Helper() 121 if alerr, ok := err.(ActionListError); ok { 122 err = alerr.Unwrap() 123 } 124 if err != errClosed { 125 t.Errorf("got %v, want errClosed", err) 126 } 127 } 128 129 doc := map[string]interface{}{"key": "k"} 130 check(c.Close()) 131 check(c.Actions().Create(doc).Do(ctx)) 132 check(c.Create(ctx, doc)) 133 check(c.Replace(ctx, doc)) 134 check(c.Put(ctx, doc)) 135 check(c.Get(ctx, doc)) 136 check(c.Delete(ctx, doc)) 137 check(c.Update(ctx, doc, Mods{"a": 1})) 138 iter := c.Query().Get(ctx) 139 check(iter.Next(ctx, doc)) 140 141 // Check that DocumentIterator.Next returns errClosed if Close is called 142 // in the middle of the iteration. 143 c = NewCollection(fakeDriverCollection{}) 144 iter = c.Query().Get(ctx) 145 c.Close() 146 check(iter.Next(ctx, doc)) 147 } 148 149 func TestSerializeRevisionErrors(t *testing.T) { 150 c := NewCollection(fakeDriverCollection{}) 151 _, err := c.RevisionToString(nil) 152 if got := gcerrors.Code(err); got != gcerrors.InvalidArgument { 153 t.Errorf("got %v, want InvalidArgument", got) 154 } 155 _, err = c.StringToRevision("") 156 if got := gcerrors.Code(err); got != gcerrors.InvalidArgument { 157 t.Errorf("got %v, want InvalidArgument", got) 158 } 159 } 160 161 type fakeDriverCollection struct { 162 driver.Collection 163 } 164 165 func (fakeDriverCollection) Key(doc driver.Document) (interface{}, error) { 166 key, err := doc.GetField("key") 167 // TODO(#2589): remove this check once we check for empty key. 168 if err != nil || driver.IsEmptyValue(reflect.ValueOf(key)) { 169 return nil, err 170 } 171 return key, nil 172 } 173 174 func (fakeDriverCollection) RevisionField() string { return DefaultRevisionField } 175 176 func (fakeDriverCollection) Close() error { return nil } 177 178 func (fakeDriverCollection) RunActions(ctx context.Context, actions []*driver.Action, opts *driver.RunActionsOptions) driver.ActionListError { 179 return nil 180 } 181 182 func (fakeDriverCollection) RunGetQuery(context.Context, *driver.Query) (driver.DocumentIterator, error) { 183 return fakeDriverDocumentIterator{}, nil 184 } 185 186 type fakeDriverDocumentIterator struct { 187 driver.DocumentIterator 188 } 189 190 func (fakeDriverDocumentIterator) Next(context.Context, driver.Document) error { return nil }