blob: 7d895fe1081be95fec1b85ccc48a727f72ec9ce6 [file] [log] [blame]
// Copyright 2015 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 tumble
import (
"context"
"testing"
ds "go.chromium.org/luci/gae/service/datastore"
. "github.com/smartystreets/goconvey/convey"
)
type BigObjectGroup struct {
_id int64 `gae:"$id,1"`
Count int64
}
type BigObject struct {
ID int64 `gae:"$id"`
Group *ds.Key `gae:"$parent"`
Data []byte `gae:",noindex"`
}
type SlowMutation struct {
Count int64
}
func (s *SlowMutation) Root(c context.Context) *ds.Key {
return ds.MakeKey(c, "BigObjectGroup", 1)
}
var JunkBytes = make([]byte, 512*1024)
func init() {
for i := 0; i < 32768; i += 16 {
copy(JunkBytes[i:i+16], []byte("BuhNerfCatBlarty"))
}
}
func (s *SlowMutation) RollForward(c context.Context) (muts []Mutation, err error) {
grp := &BigObjectGroup{}
err = ds.Get(c, grp)
if err == ds.ErrNoSuchEntity {
err = ds.Put(c, grp)
}
if err != nil {
return
}
grp.Count++
bo := &BigObject{ID: grp.Count, Group: ds.KeyForObj(c, grp), Data: JunkBytes}
err = ds.Put(c, grp, bo)
retMut := *s
retMut.Count--
if retMut.Count > 0 {
muts = append(muts, &retMut)
}
return
}
func init() {
Register((*SlowMutation)(nil))
}
func TestTailCallOptimization(t *testing.T) {
if testing.Short() {
t.Skip("TCO test skipped in -short mode")
}
t.Parallel()
Convey("Tail Call optimization test", t, func() {
testing := &Testing{}
c := testing.Context()
// This will start a chain.
So(RunMutation(c, &SlowMutation{40}), ShouldBeNil)
// 2 processed shards shows that we did 1 transaction and 1 empty tail call.
So(testing.Drain(c), ShouldEqual, 2)
bog := &BigObjectGroup{}
So(ds.Get(c, bog), ShouldBeNil)
// Hey look at that, bog shows all 40 :)
So(bog.Count, ShouldEqual, 40)
})
}