go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/logdog/common/storage/memory/memory_test.go (about) 1 // Copyright 2015 The LUCI 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 // http://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 memory 16 17 import ( 18 "bytes" 19 "context" 20 "encoding/binary" 21 "errors" 22 "testing" 23 24 "go.chromium.org/luci/logdog/common/storage" 25 "go.chromium.org/luci/logdog/common/types" 26 27 . "github.com/smartystreets/goconvey/convey" 28 . "go.chromium.org/luci/common/testing/assertions" 29 ) 30 31 func numRec(v types.MessageIndex) *rec { 32 buf := bytes.Buffer{} 33 binary.Write(&buf, binary.BigEndian, v) 34 return &rec{ 35 index: v, 36 data: buf.Bytes(), 37 } 38 } 39 40 func mustGetIndex(e *storage.Entry) types.MessageIndex { 41 idx, err := e.GetStreamIndex() 42 if err != nil { 43 panic(err) 44 } 45 return idx 46 } 47 48 func TestBigTable(t *testing.T) { 49 t.Parallel() 50 51 Convey(`A memory Storage instance.`, t, func() { 52 c := context.TODO() 53 54 st := Storage{} 55 defer st.Close() 56 57 project := "test-project" 58 path := types.StreamPath("testing/+/foo/bar") 59 60 Convey(`Can Put() log stream records {0..5, 7, 8, 10}.`, func() { 61 var indices []types.MessageIndex 62 63 putRange := func(start types.MessageIndex, count int) error { 64 req := storage.PutRequest{ 65 Project: project, 66 Path: path, 67 Index: start, 68 } 69 for i := 0; i < count; i++ { 70 index := start + types.MessageIndex(i) 71 req.Values = append(req.Values, numRec(index).data) 72 indices = append(indices, index) 73 } 74 return st.Put(c, req) 75 } 76 77 So(putRange(0, 6), ShouldBeNil) 78 So(putRange(7, 2), ShouldBeNil) 79 So(putRange(10, 1), ShouldBeNil) 80 81 // Forward-indexed records. 82 recs := make([]*rec, len(indices)) 83 for i, idx := range indices { 84 recs[i] = numRec(idx) 85 } 86 87 var getRecs []*rec 88 getAllCB := func(e *storage.Entry) bool { 89 getRecs = append(getRecs, &rec{ 90 index: mustGetIndex(e), 91 data: e.D, 92 }) 93 return true 94 } 95 96 Convey(`Put()`, func() { 97 req := storage.PutRequest{ 98 Project: project, 99 Path: path, 100 } 101 102 Convey(`Will return ErrExists when putting an existing entry.`, func() { 103 req.Values = [][]byte{[]byte("ohai")} 104 105 So(st.Put(c, req), ShouldEqual, storage.ErrExists) 106 }) 107 108 Convey(`Will return an error if one is set.`, func() { 109 st.SetErr(errors.New("test error")) 110 111 req.Index = 1337 112 So(st.Put(c, req), ShouldErrLike, "test error") 113 }) 114 }) 115 116 Convey(`Get()`, func() { 117 req := storage.GetRequest{ 118 Project: project, 119 Path: path, 120 } 121 122 Convey(`Can retrieve all of the records correctly.`, func() { 123 So(st.Get(c, req, getAllCB), ShouldBeNil) 124 So(getRecs, ShouldResemble, recs) 125 }) 126 127 Convey(`Will adhere to GetRequest limit.`, func() { 128 req.Limit = 4 129 130 So(st.Get(c, req, getAllCB), ShouldBeNil) 131 So(getRecs, ShouldResemble, recs[:4]) 132 }) 133 134 Convey(`Will adhere to hard limit.`, func() { 135 st.MaxGetCount = 3 136 req.Limit = 4 137 138 So(st.Get(c, req, getAllCB), ShouldBeNil) 139 So(getRecs, ShouldResemble, recs[:3]) 140 }) 141 142 Convey(`Will stop iterating if callback returns false.`, func() { 143 count := 0 144 err := st.Get(c, req, func(*storage.Entry) bool { 145 count++ 146 return false 147 }) 148 So(err, ShouldBeNil) 149 So(count, ShouldEqual, 1) 150 }) 151 152 Convey(`Will fail to retrieve records if the project doesn't exist.`, func() { 153 req.Project = "project-does-not-exist" 154 155 So(st.Get(c, req, getAllCB), ShouldEqual, storage.ErrDoesNotExist) 156 }) 157 158 Convey(`Will fail to retrieve records if the path doesn't exist.`, func() { 159 req.Path = "testing/+/does/not/exist" 160 161 So(st.Get(c, req, getAllCB), ShouldEqual, storage.ErrDoesNotExist) 162 }) 163 164 Convey(`Will return an error if one is set.`, func() { 165 st.SetErr(errors.New("test error")) 166 167 So(st.Get(c, req, nil), ShouldErrLike, "test error") 168 }) 169 }) 170 171 Convey(`Tail()`, func() { 172 Convey(`Can retrieve the tail record, 10.`, func() { 173 e, err := st.Tail(c, project, path) 174 So(err, ShouldBeNil) 175 So(e.D, ShouldResemble, numRec(10).data) 176 So(mustGetIndex(e), ShouldEqual, 10) 177 }) 178 179 Convey(`Will fail to retrieve records if the project doesn't exist.`, func() { 180 _, err := st.Tail(c, "project-does-not-exist", path) 181 So(err, ShouldEqual, storage.ErrDoesNotExist) 182 }) 183 184 Convey(`Will fail to retrieve records if the path doesn't exist.`, func() { 185 _, err := st.Tail(c, project, "testing/+/does/not/exist") 186 So(err, ShouldEqual, storage.ErrDoesNotExist) 187 }) 188 189 Convey(`Will return an error if one is set.`, func() { 190 st.SetErr(errors.New("test error")) 191 _, err := st.Tail(c, "", "") 192 So(err, ShouldErrLike, "test error") 193 }) 194 }) 195 196 }) 197 }) 198 }