blob: b88aa49389e5454f0626d1922cb213ac9de009ea [file] [log] [blame]
// Copyright 2020 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package datastore_test
import (
"context"
"testing"
"go.chromium.org/luci/common/logging/memlogger"
"go.chromium.org/luci/gae/impl/memory"
"go.chromium.org/luci/gae/service/datastore"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
type Foo struct {
_kind string `gae:"$kind,Foo"`
ID int64 `gae:"$id"`
MultiVals []string `gae:"multi_vals"`
SingleVal string `gae:"single_val"`
Status bool `gae:"status"`
}
func TestRunMulti(t *testing.T) {
t.Parallel()
Convey("RunMulti", t, func() {
ctx := memory.Use(context.Background())
ctx = memlogger.Use(ctx)
datastore.GetTestable(ctx).AutoIndex(true)
datastore.GetTestable(ctx).Consistent(true)
foos := []*Foo{
{
ID: 1,
MultiVals: []string{"m1", "m2"},
SingleVal: "s1",
Status: true,
},
{
ID: 2,
MultiVals: []string{"m2", "m3"},
SingleVal: "s1",
Status: false,
},
{
ID: 3,
MultiVals: []string{"m3", "m4"},
SingleVal: "s2",
Status: true,
},
{
ID: 4,
MultiVals: []string{"m4", "m5"},
SingleVal: "s2",
Status: false,
},
}
So(datastore.Put(ctx, foos), ShouldBeNil)
Convey("ok", func() {
Convey("default ordering", func() {
queries := []*datastore.Query{
datastore.NewQuery("Foo").Gte("__key__", datastore.KeyForObj(ctx, &Foo{ID: 1})),
}
var res []*Foo
err := datastore.RunMulti(ctx, queries, func(foo *Foo) error {
res = append(res, foo)
return nil
})
So(err, ShouldBeNil)
So(res, ShouldResemble, foos)
})
Convey("querying key only", func() {
queries := []*datastore.Query{
datastore.NewQuery("Foo").Eq("multi_vals", "m2"),
datastore.NewQuery("Foo").Eq("multi_vals", "m3"),
}
var keys []*datastore.Key
err := datastore.RunMulti(ctx, queries, func(k *datastore.Key) error {
keys = append(keys, k)
return nil
})
So(err, ShouldBeNil)
So(keys, ShouldResemble, []*datastore.Key{
datastore.KeyForObj(ctx, foos[0]),
datastore.KeyForObj(ctx, foos[1]),
datastore.KeyForObj(ctx, foos[2]),
})
})
Convey("overlapped results with non-default orders", func() {
queries := []*datastore.Query{
datastore.NewQuery("Foo").Eq("multi_vals", "m2").Order("-single_val", "status"),
datastore.NewQuery("Foo").Eq("multi_vals", "m3").Order("-single_val", "status"),
}
var res []*Foo
err := datastore.RunMulti(ctx, queries, func(foo *Foo) error {
res = append(res, foo)
return nil
})
So(err, ShouldBeNil)
So(res, ShouldResemble, []*Foo{foos[2], foos[1], foos[0]})
})
Convey("send Stop in cb", func() {
queries := []*datastore.Query{
datastore.NewQuery("Foo").Eq("multi_vals", "m2"),
datastore.NewQuery("Foo").Eq("multi_vals", "m3"),
}
var res []*Foo
err := datastore.RunMulti(ctx, queries, func(foo *Foo) error {
if len(res) == 2 {
return datastore.Stop
}
res = append(res, foo)
return nil
})
So(err, ShouldBeNil)
So(res, ShouldResemble, []*Foo{foos[0], foos[1]})
})
Convey("not found", func() {
queries := []*datastore.Query{
datastore.NewQuery("Foo").Eq("single_val", "non-existent"),
}
var res []*Foo
err := datastore.RunMulti(ctx, queries, func(foo *Foo) error {
res = append(res, foo)
return nil
})
So(err, ShouldBeNil)
So(res, ShouldBeNil)
})
})
Convey("bad", func() {
Convey("cb with cursorCB", func() {
queries := []*datastore.Query{
datastore.NewQuery("Foo"),
}
err := datastore.RunMulti(ctx, queries, func(foo *Foo, c datastore.CursorCB) error {
return nil
})
So(err, ShouldErrLike, "datastore: RunMulti doesn't support CursorCB.")
})
})
})
}