go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/sync/dispatcher/options_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 dispatcher
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  	"time"
    21  
    22  	"golang.org/x/time/rate"
    23  
    24  	"go.chromium.org/luci/common/sync/dispatcher/buffer"
    25  
    26  	. "github.com/smartystreets/goconvey/convey"
    27  	. "go.chromium.org/luci/common/testing/assertions"
    28  )
    29  
    30  func TestOptionValidationGood(t *testing.T) {
    31  	fullOptions := Options{
    32  		ErrorFn:  func(*buffer.Batch, error) bool { return false },
    33  		DropFn:   DropFnQuiet,
    34  		QPSLimit: rate.NewLimiter(rate.Inf, 0),
    35  		Buffer:   buffer.Defaults,
    36  	}
    37  
    38  	var goodOptions = []struct {
    39  		name     string
    40  		options  Options
    41  		expected Options
    42  	}{
    43  		{
    44  			name: "minimal",
    45  			options: Options{
    46  				Buffer: buffer.Defaults,
    47  			},
    48  			expected: Options{
    49  				QPSLimit: rate.NewLimiter(rate.Inf, 0),
    50  				Buffer:   buffer.Defaults,
    51  			},
    52  		},
    53  
    54  		{
    55  			name:     "full",
    56  			options:  fullOptions,
    57  			expected: fullOptions,
    58  		},
    59  	}
    60  
    61  	Convey(`test good option groups`, t, func() {
    62  		ctx := context.Background()
    63  		for _, options := range goodOptions {
    64  			Convey(options.name, func() {
    65  				myOptions := options.options
    66  				expect := options.expected
    67  
    68  				// ShouldResemble has issues with function pointers; don't care about
    69  				// testing buffer options in this test.
    70  				myOptions.Buffer.Retry = nil
    71  				expect.Buffer.Retry = nil
    72  
    73  				So(myOptions.normalize(ctx), ShouldBeNil)
    74  
    75  				// Directly compare function pointers; ShouldResemble doesn't compare
    76  				// them sensibly.
    77  				if expect.ErrorFn == nil {
    78  					So(myOptions.ErrorFn, ShouldNotBeNil) // default is non-nil
    79  				} else {
    80  					So(myOptions.ErrorFn, ShouldEqual, expect.ErrorFn)
    81  					expect.ErrorFn = nil
    82  				}
    83  				myOptions.ErrorFn = nil
    84  
    85  				if expect.DropFn == nil {
    86  					So(myOptions.DropFn, ShouldNotBeNil) // default is non-nil
    87  				} else {
    88  					So(myOptions.DropFn, ShouldEqual, expect.DropFn)
    89  					expect.DropFn = nil
    90  				}
    91  				myOptions.DropFn = nil
    92  
    93  				if expect.ItemSizeFunc == nil {
    94  					So(myOptions.ItemSizeFunc, ShouldBeNil)
    95  				} else {
    96  					So(myOptions.ItemSizeFunc, ShouldEqual, expect.ItemSizeFunc)
    97  					expect.ItemSizeFunc = nil
    98  				}
    99  				myOptions.ItemSizeFunc = nil
   100  
   101  				So(myOptions, ShouldResemble, expect)
   102  			})
   103  		}
   104  	})
   105  }
   106  
   107  func TestOptionValidationBad(t *testing.T) {
   108  	Convey(`bad option validation`, t, func() {
   109  		ctx := context.Background()
   110  
   111  		Convey(`QPSLimit`, func() {
   112  			opts := Options{QPSLimit: rate.NewLimiter(100, 0), Buffer: buffer.Defaults}
   113  			So(opts.normalize(ctx), ShouldErrLike, "QPSLimit has burst size < 1")
   114  		})
   115  
   116  		Convey(`ItemSizeFunc == nil`, func() {
   117  			Convey(`BatchSizeMax > 0`, func() {
   118  				opts := Options{Buffer: buffer.Defaults}
   119  				opts.Buffer.BatchSizeMax = 1000
   120  				So(opts.normalize(ctx), ShouldErrLike, "Buffer.BatchSizeMax > 0")
   121  			})
   122  		})
   123  
   124  		Convey(`MinQPS`, func() {
   125  			Convey(`MinQPS == rate.Inf`, func() {
   126  				opts := Options{
   127  					MinQPS: rate.Inf,
   128  					Buffer: buffer.Defaults}
   129  				So(opts.normalize(ctx), ShouldErrLike, "MinQPS cannot be infinite")
   130  			})
   131  			Convey(`MinQPS greater than QPSLimit`, func() {
   132  				opts := Options{
   133  					QPSLimit: rate.NewLimiter(100, 1),
   134  					MinQPS:   rate.Every(time.Millisecond),
   135  					Buffer:   buffer.Defaults}
   136  				So(opts.normalize(ctx), ShouldErrLike, "MinQPS: 1000.000000 is greater than QPSLimit: 100.000000")
   137  			})
   138  		})
   139  	})
   140  }