blob: 048a434191c92616843ec2dbbd804dfc329b9c09 [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 (
"math"
"net/http"
"testing"
"time"
"go.chromium.org/luci/common/clock/testclock"
"go.chromium.org/luci/common/logging"
"go.chromium.org/luci/common/logging/memlogger"
"go.chromium.org/luci/gae/service/datastore"
"go.chromium.org/luci/gae/service/info"
tq "go.chromium.org/luci/gae/service/taskqueue"
. "github.com/smartystreets/goconvey/convey"
)
func TestShardCalculation(t *testing.T) {
t.Parallel()
Convey("shard calculation", t, func() {
tt := &Testing{}
ctx := tt.Context()
cfg := tt.GetConfig(ctx)
cfg.NumShards = 11
tt.UpdateSettings(ctx, cfg)
l := logging.Get(ctx).(*memlogger.MemLogger)
Convey("ExpandedShard->Shard covers the full int64 range", func() {
tcs := []struct {
es int64
s uint64
}{
{math.MinInt64, 0},
{0, cfg.NumShards / 2},
{math.MaxInt64, cfg.NumShards - 1},
}
for _, tc := range tcs {
So((&realMutation{ExpandedShard: tc.es, TargetRoot: &datastore.Key{}}).shard(cfg).shard, ShouldEqual, tc.s)
low, high := expandedShardBounds(ctx, cfg, tc.s)
So(tc.es, ShouldBeGreaterThanOrEqualTo, low)
So(tc.es, ShouldBeLessThanOrEqualTo, high)
So(l.Messages(), ShouldBeEmpty)
}
})
Convey("expandedShardsPerShard returns crossed ranges on shard reduction", func() {
low, high := expandedShardBounds(ctx, cfg, 256)
So(low, ShouldBeGreaterThan, high)
So(l, memlogger.ShouldHaveLog, logging.Warning, "Invalid shard: 256")
})
})
}
func TestFireTasks(t *testing.T) {
t.Parallel()
Convey("fireTasks works as expected", t, func() {
tt := &Testing{}
ctx := tt.Context()
Convey("empty", func() {
So(fireTasks(ctx, tt.GetConfig(ctx), nil, true), ShouldBeTrue)
So(len(tq.GetTestable(ctx).GetScheduledTasks()[baseName]), ShouldEqual, 0)
})
Convey("basic", func() {
So(fireTasks(ctx, tt.GetConfig(ctx), map[taskShard]struct{}{
{2, minTS}: {},
{7, minTS}: {},
// since DelayedMutations is false, this timew will be reset
{5, mkTimestamp(tt.GetConfig(ctx), testclock.TestTimeUTC.Add(time.Minute))}: {},
}, true), ShouldBeTrue)
So(tq.GetTestable(ctx).GetScheduledTasks()[baseName], ShouldResemble, map[string]*tq.Task{
"-62132730888__2": {
Name: "-62132730888__2",
Method: "POST",
Path: processURL(-62132730888, 2, "", true),
ETA: testclock.TestTimeUTC.Add(6 * time.Second).Round(time.Second),
},
"-62132730888__7": {
Name: "-62132730888__7",
Method: "POST",
Path: processURL(-62132730888, 7, "", true),
ETA: testclock.TestTimeUTC.Add(6 * time.Second).Round(time.Second),
},
"-62132730888__5": {
Name: "-62132730888__5",
Method: "POST",
Path: processURL(-62132730888, 5, "", true),
ETA: testclock.TestTimeUTC.Add(6 * time.Second).Round(time.Second),
},
})
})
Convey("namespaced", func() {
ctx = info.MustNamespace(ctx, "foo.bar")
So(fireTasks(ctx, tt.GetConfig(ctx), map[taskShard]struct{}{
{2, minTS}: {},
}, true), ShouldBeTrue)
So(tq.GetTestable(ctx).GetScheduledTasks()[baseName], ShouldResemble, map[string]*tq.Task{
"-62132730888_foo_bar_2": {
Name: "-62132730888_foo_bar_2",
Method: "POST",
Header: http.Header{
"X-Appengine-Current-Namespace": []string{"foo.bar"},
},
Path: processURL(-62132730888, 2, "foo.bar", true),
ETA: testclock.TestTimeUTC.Add(6 * time.Second).Round(time.Second),
},
})
})
Convey("delayed", func() {
cfg := tt.GetConfig(ctx)
cfg.DelayedMutations = true
tt.UpdateSettings(ctx, cfg)
delayedTS := mkTimestamp(cfg, testclock.TestTimeUTC.Add(time.Minute*10))
So(fireTasks(ctx, cfg, map[taskShard]struct{}{
{1, delayedTS}: {},
}, true), ShouldBeTrue)
So(tq.GetTestable(ctx).GetScheduledTasks()[baseName], ShouldResemble, map[string]*tq.Task{
"-62132730288__1": {
Name: "-62132730288__1",
Method: "POST",
Path: processURL(-62132730288, 1, "", true),
ETA: testclock.TestTimeUTC.Add(time.Minute * 10).Add(6 * time.Second).Round(time.Second),
},
})
})
})
}