go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/proto/paged/queries_test.go (about) 1 // Copyright 2019 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 paged 16 17 import ( 18 "context" 19 "testing" 20 21 "go.chromium.org/luci/common/errors" 22 "go.chromium.org/luci/gae/impl/memory" 23 "go.chromium.org/luci/gae/service/datastore" 24 25 "go.chromium.org/luci/common/proto/examples" 26 27 . "github.com/smartystreets/goconvey/convey" 28 . "go.chromium.org/luci/common/testing/assertions" 29 ) 30 31 func TestQueries(t *testing.T) { 32 t.Parallel() 33 34 Convey("Query", t, func() { 35 type Record struct { 36 _kind string `gae:"$kind,kind"` 37 ID string `gae:"$id"` 38 } 39 40 c := memory.Use(context.Background()) 41 datastore.GetTestable(c).AutoIndex(true) 42 datastore.GetTestable(c).Consistent(true) 43 rsp := &examples.ListResponse{} 44 q := datastore.NewQuery("kind") 45 46 Convey("invalid", func() { 47 Convey("function", func() { 48 Convey("nil", func() { 49 So(Query(c, 0, "", rsp, q, nil), ShouldErrLike, "callback must be a function") 50 }) 51 52 Convey("no inputs", func() { 53 f := func() error { 54 return nil 55 } 56 So(Query(c, 0, "", rsp, q, f), ShouldErrLike, "callback function must accept one argument") 57 }) 58 59 Convey("many inputs", func() { 60 f := func(any, datastore.CursorCB) error { 61 return nil 62 } 63 So(Query(c, 0, "", rsp, q, f), ShouldErrLike, "callback function must accept one argument") 64 }) 65 66 Convey("no outputs", func() { 67 f := func(any) { 68 } 69 So(Query(c, 0, "", rsp, q, f), ShouldErrLike, "callback function must return one value") 70 }) 71 72 Convey("many outputs", func() { 73 f := func(any) (any, error) { 74 return nil, nil 75 } 76 So(Query(c, 0, "", rsp, q, f), ShouldErrLike, "callback function must return one value") 77 }) 78 }) 79 80 Convey("token", func() { 81 f := func(any) error { 82 return nil 83 } 84 So(Query(c, 0, "tok", rsp, q, f), ShouldErrLike, "invalid page token") 85 }) 86 }) 87 88 Convey("valid", func() { 89 Convey("callback", func() { 90 Convey("error", func() { 91 f := func(r *Record) error { 92 return errors.New("error") 93 } 94 So(datastore.Put(c, &Record{ID: "id"}), ShouldBeNil) 95 96 So(Query(c, 0, "", rsp, q, f), ShouldErrLike, "error") 97 }) 98 99 Convey("stop", func() { 100 f := func(*Record) error { 101 return datastore.Stop 102 } 103 104 Convey("first", func() { 105 So(datastore.Put(c, &Record{ID: "id1"}), ShouldBeNil) 106 So(datastore.Put(c, &Record{ID: "id2"}), ShouldBeNil) 107 108 Convey("limit", func() { 109 Convey("greater", func() { 110 So(Query(c, 10, "", rsp, q, f), ShouldBeNil) 111 So(rsp.NextPageToken, ShouldNotBeEmpty) 112 113 tok := rsp.NextPageToken 114 rsp.NextPageToken = "" 115 So(Query(c, 10, tok, rsp, q, f), ShouldBeNil) 116 So(rsp.NextPageToken, ShouldBeEmpty) 117 }) 118 119 Convey("equal", func() { 120 So(Query(c, 1, "", rsp, q, f), ShouldBeNil) 121 So(rsp.NextPageToken, ShouldNotBeEmpty) 122 123 tok := rsp.NextPageToken 124 rsp.NextPageToken = "" 125 So(Query(c, 1, tok, rsp, q, f), ShouldBeNil) 126 So(rsp.NextPageToken, ShouldBeEmpty) 127 }) 128 }) 129 130 Convey("no limit", func() { 131 So(Query(c, 0, "", rsp, q, f), ShouldBeNil) 132 So(rsp.NextPageToken, ShouldNotBeEmpty) 133 134 tok := rsp.NextPageToken 135 rsp.NextPageToken = "" 136 So(Query(c, 0, tok, rsp, q, f), ShouldBeNil) 137 So(rsp.NextPageToken, ShouldBeEmpty) 138 }) 139 }) 140 141 Convey("intermediate", func() { 142 i := 0 143 f = func(*Record) error { 144 i++ 145 if i == 2 { 146 return datastore.Stop 147 } 148 return nil 149 } 150 So(datastore.Put(c, &Record{ID: "id1"}), ShouldBeNil) 151 So(datastore.Put(c, &Record{ID: "id2"}), ShouldBeNil) 152 So(datastore.Put(c, &Record{ID: "id3"}), ShouldBeNil) 153 154 Convey("limit", func() { 155 Convey("greater", func() { 156 So(Query(c, 10, "", rsp, q, f), ShouldBeNil) 157 So(rsp.NextPageToken, ShouldNotBeEmpty) 158 159 tok := rsp.NextPageToken 160 rsp.NextPageToken = "" 161 So(Query(c, 10, tok, rsp, q, f), ShouldBeNil) 162 So(rsp.NextPageToken, ShouldBeEmpty) 163 }) 164 165 Convey("equal", func() { 166 So(Query(c, 2, "", rsp, q, f), ShouldBeNil) 167 So(rsp.NextPageToken, ShouldNotBeEmpty) 168 169 tok := rsp.NextPageToken 170 rsp.NextPageToken = "" 171 So(Query(c, 2, tok, rsp, q, f), ShouldBeNil) 172 So(rsp.NextPageToken, ShouldBeEmpty) 173 }) 174 }) 175 176 Convey("no limit", func() { 177 So(Query(c, 0, "", rsp, q, f), ShouldBeNil) 178 So(rsp.NextPageToken, ShouldNotBeEmpty) 179 180 tok := rsp.NextPageToken 181 rsp.NextPageToken = "" 182 So(Query(c, 0, tok, rsp, q, f), ShouldBeNil) 183 So(rsp.NextPageToken, ShouldBeEmpty) 184 }) 185 }) 186 187 Convey("last", func() { 188 So(datastore.Put(c, &Record{ID: "id"}), ShouldBeNil) 189 190 Convey("limit", func() { 191 Convey("greater", func() { 192 So(Query(c, 10, "", rsp, q, f), ShouldBeNil) 193 So(rsp.NextPageToken, ShouldBeEmpty) 194 }) 195 196 Convey("equal", func() { 197 So(Query(c, 1, "", rsp, q, f), ShouldBeNil) 198 So(rsp.NextPageToken, ShouldBeEmpty) 199 }) 200 }) 201 202 Convey("no limit", func() { 203 So(Query(c, 0, "", rsp, q, f), ShouldBeNil) 204 So(rsp.NextPageToken, ShouldBeEmpty) 205 }) 206 }) 207 }) 208 209 Convey("ok", func() { 210 f := func(*Record) error { 211 return nil 212 } 213 So(datastore.Put(c, &Record{ID: "id"}), ShouldBeNil) 214 215 Convey("limit", func() { 216 So(Query(c, 10, "", rsp, q, f), ShouldBeNil) 217 }) 218 219 Convey("no limit", func() { 220 So(Query(c, 0, "", rsp, q, f), ShouldBeNil) 221 }) 222 }) 223 }) 224 225 Convey("query", func() { 226 rsp.Records = make([]string, 0) 227 f := func(r *Record) error { 228 rsp.Records = append(rsp.Records, r.ID) 229 return nil 230 } 231 232 Convey("limit", func() { 233 Convey("none", func() { 234 So(Query(c, 2, "", rsp, q, f), ShouldBeNil) 235 So(rsp.Records, ShouldBeEmpty) 236 }) 237 238 Convey("one", func() { 239 So(datastore.Put(c, &Record{ID: "id"}), ShouldBeNil) 240 241 So(Query(c, 2, "", rsp, q, f), ShouldBeNil) 242 So(rsp.Records, ShouldResemble, []string{"id"}) 243 So(rsp.NextPageToken, ShouldBeEmpty) 244 }) 245 246 Convey("many", func() { 247 So(datastore.Put(c, &Record{ID: "id1"}), ShouldBeNil) 248 So(datastore.Put(c, &Record{ID: "id2"}), ShouldBeNil) 249 So(datastore.Put(c, &Record{ID: "id3"}), ShouldBeNil) 250 251 So(Query(c, 2, "", rsp, q, f), ShouldBeNil) 252 So(rsp.Records, ShouldResemble, []string{"id1", "id2"}) 253 So(rsp.NextPageToken, ShouldNotBeEmpty) 254 255 tok := rsp.NextPageToken 256 rsp.NextPageToken = "" 257 rsp.Records = make([]string, 0) 258 So(Query(c, 2, tok, rsp, q, f), ShouldBeNil) 259 So(rsp.Records, ShouldResemble, []string{"id3"}) 260 So(rsp.NextPageToken, ShouldBeEmpty) 261 }) 262 }) 263 264 Convey("no limit", func() { 265 Convey("none", func() { 266 So(Query(c, 0, "", rsp, q, f), ShouldBeNil) 267 So(rsp.Records, ShouldBeEmpty) 268 }) 269 270 Convey("one", func() { 271 So(datastore.Put(c, &Record{ID: "id"}), ShouldBeNil) 272 273 So(Query(c, 0, "", rsp, q, f), ShouldBeNil) 274 So(rsp.Records, ShouldResemble, []string{"id"}) 275 }) 276 277 Convey("many", func() { 278 So(datastore.Put(c, &Record{ID: "id1"}), ShouldBeNil) 279 So(datastore.Put(c, &Record{ID: "id2"}), ShouldBeNil) 280 So(datastore.Put(c, &Record{ID: "id3"}), ShouldBeNil) 281 282 So(Query(c, 0, "", rsp, q, f), ShouldBeNil) 283 So(rsp.Records, ShouldResemble, []string{"id1", "id2", "id3"}) 284 }) 285 286 Convey("error", func() { 287 rsp.Records = make([]string, 0) 288 f := func(r *Record) error { 289 return errors.Reason("error").Err() 290 } 291 So(datastore.Put(c, &Record{ID: "id1"}), ShouldBeNil) 292 So(datastore.Put(c, &Record{ID: "id2"}), ShouldBeNil) 293 So(datastore.Put(c, &Record{ID: "id3"}), ShouldBeNil) 294 295 So(Query(c, 0, "", rsp, q, f), ShouldErrLike, "error") 296 So(rsp.Records, ShouldBeEmpty) 297 So(rsp.NextPageToken, ShouldBeEmpty) 298 }) 299 }) 300 }) 301 }) 302 }) 303 }