blob: 2d8876994177873217255e80f9b75140ed0504ce [file] [log] [blame]
// Copyright 2019 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 dispatcher
import (
"context"
"testing"
"time"
"golang.org/x/time/rate"
"go.chromium.org/luci/common/sync/dispatcher/buffer"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func TestOptionValidationGood(t *testing.T) {
fullOptions := Options{
ErrorFn: func(*buffer.Batch, error) bool { return false },
DropFn: DropFnQuiet,
QPSLimit: rate.NewLimiter(rate.Inf, 0),
Buffer: buffer.Defaults,
}
var goodOptions = []struct {
name string
options Options
expected Options
}{
{
name: "minimal",
options: Options{
Buffer: buffer.Defaults,
},
expected: Options{
QPSLimit: rate.NewLimiter(rate.Inf, 0),
Buffer: buffer.Defaults,
},
},
{
name: "full",
options: fullOptions,
expected: fullOptions,
},
}
Convey(`test good option groups`, t, func() {
ctx := context.Background()
for _, options := range goodOptions {
Convey(options.name, func() {
myOptions := options.options
expect := options.expected
// ShouldResemble has issues with function pointers; don't care about
// testing buffer options in this test.
myOptions.Buffer.Retry = nil
expect.Buffer.Retry = nil
So(myOptions.normalize(ctx), ShouldBeNil)
// Directly compare function pointers; ShouldResemble doesn't compare
// them sensibly.
if expect.ErrorFn == nil {
So(myOptions.ErrorFn, ShouldNotBeNil) // default is non-nil
} else {
So(myOptions.ErrorFn, ShouldEqual, expect.ErrorFn)
expect.ErrorFn = nil
}
myOptions.ErrorFn = nil
if expect.DropFn == nil {
So(myOptions.DropFn, ShouldNotBeNil) // default is non-nil
} else {
So(myOptions.DropFn, ShouldEqual, expect.DropFn)
expect.DropFn = nil
}
myOptions.DropFn = nil
if expect.ItemSizeFunc == nil {
So(myOptions.ItemSizeFunc, ShouldBeNil)
} else {
So(myOptions.ItemSizeFunc, ShouldEqual, expect.ItemSizeFunc)
expect.ItemSizeFunc = nil
}
myOptions.ItemSizeFunc = nil
So(myOptions, ShouldResemble, expect)
})
}
})
}
func TestOptionValidationBad(t *testing.T) {
Convey(`bad option validation`, t, func() {
ctx := context.Background()
Convey(`QPSLimit`, func() {
opts := Options{QPSLimit: rate.NewLimiter(100, 0), Buffer: buffer.Defaults}
So(opts.normalize(ctx), ShouldErrLike, "QPSLimit has burst size < 1")
})
Convey(`ItemSizeFunc == nil`, func() {
Convey(`BatchSizeMax > 0`, func() {
opts := Options{Buffer: buffer.Defaults}
opts.Buffer.BatchSizeMax = 1000
So(opts.normalize(ctx), ShouldErrLike, "Buffer.BatchSizeMax > 0")
})
})
Convey(`MinQPS`, func() {
Convey(`MinQPS == rate.Inf`, func() {
opts := Options{
MinQPS: rate.Inf,
Buffer: buffer.Defaults}
So(opts.normalize(ctx), ShouldErrLike, "MinQPS cannot be infinite")
})
Convey(`MinQPS greater than QPSLimit`, func() {
opts := Options{
QPSLimit: rate.NewLimiter(100, 1),
MinQPS: rate.Every(time.Millisecond),
Buffer: buffer.Defaults}
So(opts.normalize(ctx), ShouldErrLike, "MinQPS: 1000.000000 is greater than QPSLimit: 100.000000")
})
})
})
}