TUN-8861: Add session limiter to UDP session manager

## Summary
In order to make cloudflared behavior more predictable and
prevent an exhaustion of resources, we have decided to add
session limits that can be configured by the user. This first
commit introduces the session limiter and adds it to the UDP
handling path. For now the limiter is set to run only in
unlimited mode.
This commit is contained in:
João "Pisco" Fernandes
2025-01-20 02:52:32 -08:00
parent 8918b6729e
commit bf4954e96a
66 changed files with 3409 additions and 1184 deletions

506
vendor/go.uber.org/mock/gomock/call.go generated vendored Normal file
View File

@@ -0,0 +1,506 @@
// Copyright 2010 Google Inc.
//
// 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 gomock
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// Call represents an expected call to a mock.
type Call struct {
t TestHelper // for triggering test failures on invalid call setup
receiver any // the receiver of the method call
method string // the name of the method
methodType reflect.Type // the type of the method
args []Matcher // the args
origin string // file and line number of call setup
preReqs []*Call // prerequisite calls
// Expectations
minCalls, maxCalls int
numCalls int // actual number made
// actions are called when this Call is called. Each action gets the args and
// can set the return values by returning a non-nil slice. Actions run in the
// order they are created.
actions []func([]any) []any
}
// newCall creates a *Call. It requires the method type in order to support
// unexported methods.
func newCall(t TestHelper, receiver any, method string, methodType reflect.Type, args ...any) *Call {
t.Helper()
// TODO: check arity, types.
mArgs := make([]Matcher, len(args))
for i, arg := range args {
if m, ok := arg.(Matcher); ok {
mArgs[i] = m
} else if arg == nil {
// Handle nil specially so that passing a nil interface value
// will match the typed nils of concrete args.
mArgs[i] = Nil()
} else {
mArgs[i] = Eq(arg)
}
}
// callerInfo's skip should be updated if the number of calls between the user's test
// and this line changes, i.e. this code is wrapped in another anonymous function.
// 0 is us, 1 is RecordCallWithMethodType(), 2 is the generated recorder, and 3 is the user's test.
origin := callerInfo(3)
actions := []func([]any) []any{func([]any) []any {
// Synthesize the zero value for each of the return args' types.
rets := make([]any, methodType.NumOut())
for i := 0; i < methodType.NumOut(); i++ {
rets[i] = reflect.Zero(methodType.Out(i)).Interface()
}
return rets
}}
return &Call{
t: t, receiver: receiver, method: method, methodType: methodType,
args: mArgs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions,
}
}
// AnyTimes allows the expectation to be called 0 or more times
func (c *Call) AnyTimes() *Call {
c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity
return c
}
// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called or if MaxTimes
// was previously called with 1, MinTimes also sets the maximum number of calls to infinity.
func (c *Call) MinTimes(n int) *Call {
c.minCalls = n
if c.maxCalls == 1 {
c.maxCalls = 1e8
}
return c
}
// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called or if MinTimes was
// previously called with 1, MaxTimes also sets the minimum number of calls to 0.
func (c *Call) MaxTimes(n int) *Call {
c.maxCalls = n
if c.minCalls == 1 {
c.minCalls = 0
}
return c
}
// DoAndReturn declares the action to run when the call is matched.
// The return values from this function are returned by the mocked function.
// It takes an any argument to support n-arity functions.
// The anonymous function must match the function signature mocked method.
func (c *Call) DoAndReturn(f any) *Call {
// TODO: Check arity and types here, rather than dying badly elsewhere.
v := reflect.ValueOf(f)
c.addAction(func(args []any) []any {
c.t.Helper()
ft := v.Type()
if c.methodType.NumIn() != ft.NumIn() {
if ft.IsVariadic() {
c.t.Fatalf("wrong number of arguments in DoAndReturn func for %T.%v The function signature must match the mocked method, a variadic function cannot be used.",
c.receiver, c.method)
} else {
c.t.Fatalf("wrong number of arguments in DoAndReturn func for %T.%v: got %d, want %d [%s]",
c.receiver, c.method, ft.NumIn(), c.methodType.NumIn(), c.origin)
}
return nil
}
vArgs := make([]reflect.Value, len(args))
for i := 0; i < len(args); i++ {
if args[i] != nil {
vArgs[i] = reflect.ValueOf(args[i])
} else {
// Use the zero value for the arg.
vArgs[i] = reflect.Zero(ft.In(i))
}
}
vRets := v.Call(vArgs)
rets := make([]any, len(vRets))
for i, ret := range vRets {
rets[i] = ret.Interface()
}
return rets
})
return c
}
// Do declares the action to run when the call is matched. The function's
// return values are ignored to retain backward compatibility. To use the
// return values call DoAndReturn.
// It takes an any argument to support n-arity functions.
// The anonymous function must match the function signature mocked method.
func (c *Call) Do(f any) *Call {
// TODO: Check arity and types here, rather than dying badly elsewhere.
v := reflect.ValueOf(f)
c.addAction(func(args []any) []any {
c.t.Helper()
ft := v.Type()
if c.methodType.NumIn() != ft.NumIn() {
if ft.IsVariadic() {
c.t.Fatalf("wrong number of arguments in Do func for %T.%v The function signature must match the mocked method, a variadic function cannot be used.",
c.receiver, c.method)
} else {
c.t.Fatalf("wrong number of arguments in Do func for %T.%v: got %d, want %d [%s]",
c.receiver, c.method, ft.NumIn(), c.methodType.NumIn(), c.origin)
}
return nil
}
vArgs := make([]reflect.Value, len(args))
for i := 0; i < len(args); i++ {
if args[i] != nil {
vArgs[i] = reflect.ValueOf(args[i])
} else {
// Use the zero value for the arg.
vArgs[i] = reflect.Zero(ft.In(i))
}
}
v.Call(vArgs)
return nil
})
return c
}
// Return declares the values to be returned by the mocked function call.
func (c *Call) Return(rets ...any) *Call {
c.t.Helper()
mt := c.methodType
if len(rets) != mt.NumOut() {
c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]",
c.receiver, c.method, len(rets), mt.NumOut(), c.origin)
}
for i, ret := range rets {
if got, want := reflect.TypeOf(ret), mt.Out(i); got == want {
// Identical types; nothing to do.
} else if got == nil {
// Nil needs special handling.
switch want.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
// ok
default:
c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]",
i, c.receiver, c.method, want, c.origin)
}
} else if got.AssignableTo(want) {
// Assignable type relation. Make the assignment now so that the generated code
// can return the values with a type assertion.
v := reflect.New(want).Elem()
v.Set(reflect.ValueOf(ret))
rets[i] = v.Interface()
} else {
c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]",
i, c.receiver, c.method, got, want, c.origin)
}
}
c.addAction(func([]any) []any {
return rets
})
return c
}
// Times declares the exact number of times a function call is expected to be executed.
func (c *Call) Times(n int) *Call {
c.minCalls, c.maxCalls = n, n
return c
}
// SetArg declares an action that will set the nth argument's value,
// indirected through a pointer. Or, in the case of a slice and map, SetArg
// will copy value's elements/key-value pairs into the nth argument.
func (c *Call) SetArg(n int, value any) *Call {
c.t.Helper()
mt := c.methodType
// TODO: This will break on variadic methods.
// We will need to check those at invocation time.
if n < 0 || n >= mt.NumIn() {
c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]",
n, mt.NumIn(), c.origin)
}
// Permit setting argument through an interface.
// In the interface case, we don't (nay, can't) check the type here.
at := mt.In(n)
switch at.Kind() {
case reflect.Ptr:
dt := at.Elem()
if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) {
c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]",
n, vt, dt, c.origin)
}
case reflect.Interface, reflect.Slice, reflect.Map:
// nothing to do
default:
c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice non-map type %v [%s]",
n, at, c.origin)
}
c.addAction(func(args []any) []any {
v := reflect.ValueOf(value)
switch reflect.TypeOf(args[n]).Kind() {
case reflect.Slice:
setSlice(args[n], v)
case reflect.Map:
setMap(args[n], v)
default:
reflect.ValueOf(args[n]).Elem().Set(v)
}
return nil
})
return c
}
// isPreReq returns true if other is a direct or indirect prerequisite to c.
func (c *Call) isPreReq(other *Call) bool {
for _, preReq := range c.preReqs {
if other == preReq || preReq.isPreReq(other) {
return true
}
}
return false
}
// After declares that the call may only match after preReq has been exhausted.
func (c *Call) After(preReq *Call) *Call {
c.t.Helper()
if c == preReq {
c.t.Fatalf("A call isn't allowed to be its own prerequisite")
}
if preReq.isPreReq(c) {
c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq)
}
c.preReqs = append(c.preReqs, preReq)
return c
}
// Returns true if the minimum number of calls have been made.
func (c *Call) satisfied() bool {
return c.numCalls >= c.minCalls
}
// Returns true if the maximum number of calls have been made.
func (c *Call) exhausted() bool {
return c.numCalls >= c.maxCalls
}
func (c *Call) String() string {
args := make([]string, len(c.args))
for i, arg := range c.args {
args[i] = arg.String()
}
arguments := strings.Join(args, ", ")
return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin)
}
// Tests if the given call matches the expected call.
// If yes, returns nil. If no, returns error with message explaining why it does not match.
func (c *Call) matches(args []any) error {
if !c.methodType.IsVariadic() {
if len(args) != len(c.args) {
return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d",
c.origin, len(args), len(c.args))
}
for i, m := range c.args {
if !m.Matches(args[i]) {
return fmt.Errorf(
"expected call at %s doesn't match the argument at index %d.\nGot: %v\nWant: %v",
c.origin, i, formatGottenArg(m, args[i]), m,
)
}
}
} else {
if len(c.args) < c.methodType.NumIn()-1 {
return fmt.Errorf("expected call at %s has the wrong number of matchers. Got: %d, want: %d",
c.origin, len(c.args), c.methodType.NumIn()-1)
}
if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) {
return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d",
c.origin, len(args), len(c.args))
}
if len(args) < len(c.args)-1 {
return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d",
c.origin, len(args), len(c.args)-1)
}
for i, m := range c.args {
if i < c.methodType.NumIn()-1 {
// Non-variadic args
if !m.Matches(args[i]) {
return fmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
c.origin, strconv.Itoa(i), formatGottenArg(m, args[i]), m)
}
continue
}
// The last arg has a possibility of a variadic argument, so let it branch
// sample: Foo(a int, b int, c ...int)
if i < len(c.args) && i < len(args) {
if m.Matches(args[i]) {
// Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any())
// Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher)
// Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC)
// Got Foo(a, b) want Foo(matcherA, matcherB)
// Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD)
continue
}
}
// The number of actual args don't match the number of matchers,
// or the last matcher is a slice and the last arg is not.
// If this function still matches it is because the last matcher
// matches all the remaining arguments or the lack of any.
// Convert the remaining arguments, if any, into a slice of the
// expected type.
vArgsType := c.methodType.In(c.methodType.NumIn() - 1)
vArgs := reflect.MakeSlice(vArgsType, 0, len(args)-i)
for _, arg := range args[i:] {
vArgs = reflect.Append(vArgs, reflect.ValueOf(arg))
}
if m.Matches(vArgs.Interface()) {
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any())
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher)
// Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any())
// Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher)
break
}
// Wrong number of matchers or not match. Fail.
// Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD)
// Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD)
// Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE)
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD)
// Got Foo(a, b, c) want Foo(matcherA, matcherB)
return fmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
c.origin, strconv.Itoa(i), formatGottenArg(m, args[i:]), c.args[i])
}
}
// Check that all prerequisite calls have been satisfied.
for _, preReqCall := range c.preReqs {
if !preReqCall.satisfied() {
return fmt.Errorf("expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v",
c.origin, preReqCall, c)
}
}
// Check that the call is not exhausted.
if c.exhausted() {
return fmt.Errorf("expected call at %s has already been called the max number of times", c.origin)
}
return nil
}
// dropPrereqs tells the expected Call to not re-check prerequisite calls any
// longer, and to return its current set.
func (c *Call) dropPrereqs() (preReqs []*Call) {
preReqs = c.preReqs
c.preReqs = nil
return
}
func (c *Call) call() []func([]any) []any {
c.numCalls++
return c.actions
}
// InOrder declares that the given calls should occur in order.
// It panics if the type of any of the arguments isn't *Call or a generated
// mock with an embedded *Call.
func InOrder(args ...any) {
calls := make([]*Call, 0, len(args))
for i := 0; i < len(args); i++ {
if call := getCall(args[i]); call != nil {
calls = append(calls, call)
continue
}
panic(fmt.Sprintf(
"invalid argument at position %d of type %T, InOrder expects *gomock.Call or generated mock types with an embedded *gomock.Call",
i,
args[i],
))
}
for i := 1; i < len(calls); i++ {
calls[i].After(calls[i-1])
}
}
// getCall checks if the parameter is a *Call or a generated struct
// that wraps a *Call and returns the *Call pointer - if neither, it returns nil.
func getCall(arg any) *Call {
if call, ok := arg.(*Call); ok {
return call
}
t := reflect.ValueOf(arg)
if t.Kind() != reflect.Ptr && t.Kind() != reflect.Interface {
return nil
}
t = t.Elem()
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if !f.CanInterface() {
continue
}
if call, ok := f.Interface().(*Call); ok {
return call
}
}
return nil
}
func setSlice(arg any, v reflect.Value) {
va := reflect.ValueOf(arg)
for i := 0; i < v.Len(); i++ {
va.Index(i).Set(v.Index(i))
}
}
func setMap(arg any, v reflect.Value) {
va := reflect.ValueOf(arg)
for _, e := range va.MapKeys() {
va.SetMapIndex(e, reflect.Value{})
}
for _, e := range v.MapKeys() {
va.SetMapIndex(e, v.MapIndex(e))
}
}
func (c *Call) addAction(action func([]any) []any) {
c.actions = append(c.actions, action)
}
func formatGottenArg(m Matcher, arg any) string {
got := fmt.Sprintf("%v (%T)", arg, arg)
if gs, ok := m.(GotFormatter); ok {
got = gs.Got(arg)
}
return got
}

164
vendor/go.uber.org/mock/gomock/callset.go generated vendored Normal file
View File

@@ -0,0 +1,164 @@
// Copyright 2011 Google Inc.
//
// 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 gomock
import (
"bytes"
"errors"
"fmt"
"sync"
)
// callSet represents a set of expected calls, indexed by receiver and method
// name.
type callSet struct {
// Calls that are still expected.
expected map[callSetKey][]*Call
expectedMu *sync.Mutex
// Calls that have been exhausted.
exhausted map[callSetKey][]*Call
// when set to true, existing call expectations are overridden when new call expectations are made
allowOverride bool
}
// callSetKey is the key in the maps in callSet
type callSetKey struct {
receiver any
fname string
}
func newCallSet() *callSet {
return &callSet{
expected: make(map[callSetKey][]*Call),
expectedMu: &sync.Mutex{},
exhausted: make(map[callSetKey][]*Call),
}
}
func newOverridableCallSet() *callSet {
return &callSet{
expected: make(map[callSetKey][]*Call),
expectedMu: &sync.Mutex{},
exhausted: make(map[callSetKey][]*Call),
allowOverride: true,
}
}
// Add adds a new expected call.
func (cs callSet) Add(call *Call) {
key := callSetKey{call.receiver, call.method}
cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()
m := cs.expected
if call.exhausted() {
m = cs.exhausted
}
if cs.allowOverride {
m[key] = make([]*Call, 0)
}
m[key] = append(m[key], call)
}
// Remove removes an expected call.
func (cs callSet) Remove(call *Call) {
key := callSetKey{call.receiver, call.method}
cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()
calls := cs.expected[key]
for i, c := range calls {
if c == call {
// maintain order for remaining calls
cs.expected[key] = append(calls[:i], calls[i+1:]...)
cs.exhausted[key] = append(cs.exhausted[key], call)
break
}
}
}
// FindMatch searches for a matching call. Returns error with explanation message if no call matched.
func (cs callSet) FindMatch(receiver any, method string, args []any) (*Call, error) {
key := callSetKey{receiver, method}
cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()
// Search through the expected calls.
expected := cs.expected[key]
var callsErrors bytes.Buffer
for _, call := range expected {
err := call.matches(args)
if err != nil {
_, _ = fmt.Fprintf(&callsErrors, "\n%v", err)
} else {
return call, nil
}
}
// If we haven't found a match then search through the exhausted calls so we
// get useful error messages.
exhausted := cs.exhausted[key]
for _, call := range exhausted {
if err := call.matches(args); err != nil {
_, _ = fmt.Fprintf(&callsErrors, "\n%v", err)
continue
}
_, _ = fmt.Fprintf(
&callsErrors, "all expected calls for method %q have been exhausted", method,
)
}
if len(expected)+len(exhausted) == 0 {
_, _ = fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method)
}
return nil, errors.New(callsErrors.String())
}
// Failures returns the calls that are not satisfied.
func (cs callSet) Failures() []*Call {
cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()
failures := make([]*Call, 0, len(cs.expected))
for _, calls := range cs.expected {
for _, call := range calls {
if !call.satisfied() {
failures = append(failures, call)
}
}
}
return failures
}
// Satisfied returns true in case all expected calls in this callSet are satisfied.
func (cs callSet) Satisfied() bool {
cs.expectedMu.Lock()
defer cs.expectedMu.Unlock()
for _, calls := range cs.expected {
for _, call := range calls {
if !call.satisfied() {
return false
}
}
}
return true
}

326
vendor/go.uber.org/mock/gomock/controller.go generated vendored Normal file
View File

@@ -0,0 +1,326 @@
// Copyright 2010 Google Inc.
//
// 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 gomock
import (
"context"
"fmt"
"reflect"
"runtime"
"sync"
)
// A TestReporter is something that can be used to report test failures. It
// is satisfied by the standard library's *testing.T.
type TestReporter interface {
Errorf(format string, args ...any)
Fatalf(format string, args ...any)
}
// TestHelper is a TestReporter that has the Helper method. It is satisfied
// by the standard library's *testing.T.
type TestHelper interface {
TestReporter
Helper()
}
// cleanuper is used to check if TestHelper also has the `Cleanup` method. A
// common pattern is to pass in a `*testing.T` to
// `NewController(t TestReporter)`. In Go 1.14+, `*testing.T` has a cleanup
// method. This can be utilized to call `Finish()` so the caller of this library
// does not have to.
type cleanuper interface {
Cleanup(func())
}
// A Controller represents the top-level control of a mock ecosystem. It
// defines the scope and lifetime of mock objects, as well as their
// expectations. It is safe to call Controller's methods from multiple
// goroutines. Each test should create a new Controller.
//
// func TestFoo(t *testing.T) {
// ctrl := gomock.NewController(t)
// // ..
// }
//
// func TestBar(t *testing.T) {
// t.Run("Sub-Test-1", st) {
// ctrl := gomock.NewController(st)
// // ..
// })
// t.Run("Sub-Test-2", st) {
// ctrl := gomock.NewController(st)
// // ..
// })
// })
type Controller struct {
// T should only be called within a generated mock. It is not intended to
// be used in user code and may be changed in future versions. T is the
// TestReporter passed in when creating the Controller via NewController.
// If the TestReporter does not implement a TestHelper it will be wrapped
// with a nopTestHelper.
T TestHelper
mu sync.Mutex
expectedCalls *callSet
finished bool
}
// NewController returns a new Controller. It is the preferred way to create a Controller.
//
// Passing [*testing.T] registers cleanup function to automatically call [Controller.Finish]
// when the test and all its subtests complete.
func NewController(t TestReporter, opts ...ControllerOption) *Controller {
h, ok := t.(TestHelper)
if !ok {
h = &nopTestHelper{t}
}
ctrl := &Controller{
T: h,
expectedCalls: newCallSet(),
}
for _, opt := range opts {
opt.apply(ctrl)
}
if c, ok := isCleanuper(ctrl.T); ok {
c.Cleanup(func() {
ctrl.T.Helper()
ctrl.finish(true, nil)
})
}
return ctrl
}
// ControllerOption configures how a Controller should behave.
type ControllerOption interface {
apply(*Controller)
}
type overridableExpectationsOption struct{}
// WithOverridableExpectations allows for overridable call expectations
// i.e., subsequent call expectations override existing call expectations
func WithOverridableExpectations() overridableExpectationsOption {
return overridableExpectationsOption{}
}
func (o overridableExpectationsOption) apply(ctrl *Controller) {
ctrl.expectedCalls = newOverridableCallSet()
}
type cancelReporter struct {
t TestHelper
cancel func()
}
func (r *cancelReporter) Errorf(format string, args ...any) {
r.t.Errorf(format, args...)
}
func (r *cancelReporter) Fatalf(format string, args ...any) {
defer r.cancel()
r.t.Fatalf(format, args...)
}
func (r *cancelReporter) Helper() {
r.t.Helper()
}
// WithContext returns a new Controller and a Context, which is cancelled on any
// fatal failure.
func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) {
h, ok := t.(TestHelper)
if !ok {
h = &nopTestHelper{t: t}
}
ctx, cancel := context.WithCancel(ctx)
return NewController(&cancelReporter{t: h, cancel: cancel}), ctx
}
type nopTestHelper struct {
t TestReporter
}
func (h *nopTestHelper) Errorf(format string, args ...any) {
h.t.Errorf(format, args...)
}
func (h *nopTestHelper) Fatalf(format string, args ...any) {
h.t.Fatalf(format, args...)
}
func (h nopTestHelper) Helper() {}
// RecordCall is called by a mock. It should not be called by user code.
func (ctrl *Controller) RecordCall(receiver any, method string, args ...any) *Call {
ctrl.T.Helper()
recv := reflect.ValueOf(receiver)
for i := 0; i < recv.Type().NumMethod(); i++ {
if recv.Type().Method(i).Name == method {
return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...)
}
}
ctrl.T.Fatalf("gomock: failed finding method %s on %T", method, receiver)
panic("unreachable")
}
// RecordCallWithMethodType is called by a mock. It should not be called by user code.
func (ctrl *Controller) RecordCallWithMethodType(receiver any, method string, methodType reflect.Type, args ...any) *Call {
ctrl.T.Helper()
call := newCall(ctrl.T, receiver, method, methodType, args...)
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
ctrl.expectedCalls.Add(call)
return call
}
// Call is called by a mock. It should not be called by user code.
func (ctrl *Controller) Call(receiver any, method string, args ...any) []any {
ctrl.T.Helper()
// Nest this code so we can use defer to make sure the lock is released.
actions := func() []func([]any) []any {
ctrl.T.Helper()
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args)
if err != nil {
// callerInfo's skip should be updated if the number of calls between the user's test
// and this line changes, i.e. this code is wrapped in another anonymous function.
// 0 is us, 1 is controller.Call(), 2 is the generated mock, and 3 is the user's test.
origin := callerInfo(3)
stringArgs := make([]string, len(args))
for i, arg := range args {
stringArgs[i] = getString(arg)
}
ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, stringArgs, origin, err)
}
// Two things happen here:
// * the matching call no longer needs to check prerequisite calls,
// * and the prerequisite calls are no longer expected, so remove them.
preReqCalls := expected.dropPrereqs()
for _, preReqCall := range preReqCalls {
ctrl.expectedCalls.Remove(preReqCall)
}
actions := expected.call()
if expected.exhausted() {
ctrl.expectedCalls.Remove(expected)
}
return actions
}()
var rets []any
for _, action := range actions {
if r := action(args); r != nil {
rets = r
}
}
return rets
}
// Finish checks to see if all the methods that were expected to be called were called.
// It is not idempotent and therefore can only be invoked once.
//
// Note: If you pass a *testing.T into [NewController], you no longer
// need to call ctrl.Finish() in your test methods.
func (ctrl *Controller) Finish() {
// If we're currently panicking, probably because this is a deferred call.
// This must be recovered in the deferred function.
err := recover()
ctrl.finish(false, err)
}
// Satisfied returns whether all expected calls bound to this Controller have been satisfied.
// Calling Finish is then guaranteed to not fail due to missing calls.
func (ctrl *Controller) Satisfied() bool {
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
return ctrl.expectedCalls.Satisfied()
}
func (ctrl *Controller) finish(cleanup bool, panicErr any) {
ctrl.T.Helper()
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
if ctrl.finished {
if _, ok := isCleanuper(ctrl.T); !ok {
ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.")
}
return
}
ctrl.finished = true
// Short-circuit, pass through the panic.
if panicErr != nil {
panic(panicErr)
}
// Check that all remaining expected calls are satisfied.
failures := ctrl.expectedCalls.Failures()
for _, call := range failures {
ctrl.T.Errorf("missing call(s) to %v", call)
}
if len(failures) != 0 {
if !cleanup {
ctrl.T.Fatalf("aborting test due to missing call(s)")
return
}
ctrl.T.Errorf("aborting test due to missing call(s)")
}
}
// callerInfo returns the file:line of the call site. skip is the number
// of stack frames to skip when reporting. 0 is callerInfo's call site.
func callerInfo(skip int) string {
if _, file, line, ok := runtime.Caller(skip + 1); ok {
return fmt.Sprintf("%s:%d", file, line)
}
return "unknown file"
}
// isCleanuper checks it if t's base TestReporter has a Cleanup method.
func isCleanuper(t TestReporter) (cleanuper, bool) {
tr := unwrapTestReporter(t)
c, ok := tr.(cleanuper)
return c, ok
}
// unwrapTestReporter unwraps TestReporter to the base implementation.
func unwrapTestReporter(t TestReporter) TestReporter {
tr := t
switch nt := t.(type) {
case *cancelReporter:
tr = nt.t
if h, check := tr.(*nopTestHelper); check {
tr = h.t
}
case *nopTestHelper:
tr = nt.t
default:
// not wrapped
}
return tr
}

60
vendor/go.uber.org/mock/gomock/doc.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2022 Google LLC
//
// 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 gomock is a mock framework for Go.
//
// Standard usage:
//
// (1) Define an interface that you wish to mock.
// type MyInterface interface {
// SomeMethod(x int64, y string)
// }
// (2) Use mockgen to generate a mock from the interface.
// (3) Use the mock in a test:
// func TestMyThing(t *testing.T) {
// mockCtrl := gomock.NewController(t)
// mockObj := something.NewMockMyInterface(mockCtrl)
// mockObj.EXPECT().SomeMethod(4, "blah")
// // pass mockObj to a real object and play with it.
// }
//
// By default, expected calls are not enforced to run in any particular order.
// Call order dependency can be enforced by use of InOrder and/or Call.After.
// Call.After can create more varied call order dependencies, but InOrder is
// often more convenient.
//
// The following examples create equivalent call order dependencies.
//
// Example of using Call.After to chain expected call order:
//
// firstCall := mockObj.EXPECT().SomeMethod(1, "first")
// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall)
// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall)
//
// Example of using InOrder to declare expected call order:
//
// gomock.InOrder(
// mockObj.EXPECT().SomeMethod(1, "first"),
// mockObj.EXPECT().SomeMethod(2, "second"),
// mockObj.EXPECT().SomeMethod(3, "third"),
// )
//
// The standard TestReporter most users will pass to `NewController` is a
// `*testing.T` from the context of the test. Note that this will use the
// standard `t.Error` and `t.Fatal` methods to report what happened in the test.
// In some cases this can leave your testing package in a weird state if global
// state is used since `t.Fatal` is like calling panic in the middle of a
// function. In these cases it is recommended that you pass in your own
// `TestReporter`.
package gomock

447
vendor/go.uber.org/mock/gomock/matchers.go generated vendored Normal file
View File

@@ -0,0 +1,447 @@
// Copyright 2010 Google Inc.
//
// 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 gomock
import (
"fmt"
"reflect"
"regexp"
"strings"
)
// A Matcher is a representation of a class of values.
// It is used to represent the valid or expected arguments to a mocked method.
type Matcher interface {
// Matches returns whether x is a match.
Matches(x any) bool
// String describes what the matcher matches.
String() string
}
// WantFormatter modifies the given Matcher's String() method to the given
// Stringer. This allows for control on how the "Want" is formatted when
// printing .
func WantFormatter(s fmt.Stringer, m Matcher) Matcher {
type matcher interface {
Matches(x any) bool
}
return struct {
matcher
fmt.Stringer
}{
matcher: m,
Stringer: s,
}
}
// StringerFunc type is an adapter to allow the use of ordinary functions as
// a Stringer. If f is a function with the appropriate signature,
// StringerFunc(f) is a Stringer that calls f.
type StringerFunc func() string
// String implements fmt.Stringer.
func (f StringerFunc) String() string {
return f()
}
// GotFormatter is used to better print failure messages. If a matcher
// implements GotFormatter, it will use the result from Got when printing
// the failure message.
type GotFormatter interface {
// Got is invoked with the received value. The result is used when
// printing the failure message.
Got(got any) string
}
// GotFormatterFunc type is an adapter to allow the use of ordinary
// functions as a GotFormatter. If f is a function with the appropriate
// signature, GotFormatterFunc(f) is a GotFormatter that calls f.
type GotFormatterFunc func(got any) string
// Got implements GotFormatter.
func (f GotFormatterFunc) Got(got any) string {
return f(got)
}
// GotFormatterAdapter attaches a GotFormatter to a Matcher.
func GotFormatterAdapter(s GotFormatter, m Matcher) Matcher {
return struct {
GotFormatter
Matcher
}{
GotFormatter: s,
Matcher: m,
}
}
type anyMatcher struct{}
func (anyMatcher) Matches(any) bool {
return true
}
func (anyMatcher) String() string {
return "is anything"
}
type condMatcher[T any] struct {
fn func(x T) bool
}
func (c condMatcher[T]) Matches(x any) bool {
typed, ok := x.(T)
if !ok {
return false
}
return c.fn(typed)
}
func (c condMatcher[T]) String() string {
return "adheres to a custom condition"
}
type eqMatcher struct {
x any
}
func (e eqMatcher) Matches(x any) bool {
// In case, some value is nil
if e.x == nil || x == nil {
return reflect.DeepEqual(e.x, x)
}
// Check if types assignable and convert them to common type
x1Val := reflect.ValueOf(e.x)
x2Val := reflect.ValueOf(x)
if x1Val.Type().AssignableTo(x2Val.Type()) {
x1ValConverted := x1Val.Convert(x2Val.Type())
return reflect.DeepEqual(x1ValConverted.Interface(), x2Val.Interface())
}
return false
}
func (e eqMatcher) String() string {
return fmt.Sprintf("is equal to %s (%T)", getString(e.x), e.x)
}
type nilMatcher struct{}
func (nilMatcher) Matches(x any) bool {
if x == nil {
return true
}
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
reflect.Ptr, reflect.Slice:
return v.IsNil()
}
return false
}
func (nilMatcher) String() string {
return "is nil"
}
type notMatcher struct {
m Matcher
}
func (n notMatcher) Matches(x any) bool {
return !n.m.Matches(x)
}
func (n notMatcher) String() string {
return "not(" + n.m.String() + ")"
}
type regexMatcher struct {
regex *regexp.Regexp
}
func (m regexMatcher) Matches(x any) bool {
switch t := x.(type) {
case string:
return m.regex.MatchString(t)
case []byte:
return m.regex.Match(t)
default:
return false
}
}
func (m regexMatcher) String() string {
return "matches regex " + m.regex.String()
}
type assignableToTypeOfMatcher struct {
targetType reflect.Type
}
func (m assignableToTypeOfMatcher) Matches(x any) bool {
return reflect.TypeOf(x).AssignableTo(m.targetType)
}
func (m assignableToTypeOfMatcher) String() string {
return "is assignable to " + m.targetType.Name()
}
type anyOfMatcher struct {
matchers []Matcher
}
func (am anyOfMatcher) Matches(x any) bool {
for _, m := range am.matchers {
if m.Matches(x) {
return true
}
}
return false
}
func (am anyOfMatcher) String() string {
ss := make([]string, 0, len(am.matchers))
for _, matcher := range am.matchers {
ss = append(ss, matcher.String())
}
return strings.Join(ss, " | ")
}
type allMatcher struct {
matchers []Matcher
}
func (am allMatcher) Matches(x any) bool {
for _, m := range am.matchers {
if !m.Matches(x) {
return false
}
}
return true
}
func (am allMatcher) String() string {
ss := make([]string, 0, len(am.matchers))
for _, matcher := range am.matchers {
ss = append(ss, matcher.String())
}
return strings.Join(ss, "; ")
}
type lenMatcher struct {
i int
}
func (m lenMatcher) Matches(x any) bool {
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == m.i
default:
return false
}
}
func (m lenMatcher) String() string {
return fmt.Sprintf("has length %d", m.i)
}
type inAnyOrderMatcher struct {
x any
}
func (m inAnyOrderMatcher) Matches(x any) bool {
given, ok := m.prepareValue(x)
if !ok {
return false
}
wanted, ok := m.prepareValue(m.x)
if !ok {
return false
}
if given.Len() != wanted.Len() {
return false
}
usedFromGiven := make([]bool, given.Len())
foundFromWanted := make([]bool, wanted.Len())
for i := 0; i < wanted.Len(); i++ {
wantedMatcher := Eq(wanted.Index(i).Interface())
for j := 0; j < given.Len(); j++ {
if usedFromGiven[j] {
continue
}
if wantedMatcher.Matches(given.Index(j).Interface()) {
foundFromWanted[i] = true
usedFromGiven[j] = true
break
}
}
}
missingFromWanted := 0
for _, found := range foundFromWanted {
if !found {
missingFromWanted++
}
}
extraInGiven := 0
for _, used := range usedFromGiven {
if !used {
extraInGiven++
}
}
return extraInGiven == 0 && missingFromWanted == 0
}
func (m inAnyOrderMatcher) prepareValue(x any) (reflect.Value, bool) {
xValue := reflect.ValueOf(x)
switch xValue.Kind() {
case reflect.Slice, reflect.Array:
return xValue, true
default:
return reflect.Value{}, false
}
}
func (m inAnyOrderMatcher) String() string {
return fmt.Sprintf("has the same elements as %v", m.x)
}
// Constructors
// All returns a composite Matcher that returns true if and only all of the
// matchers return true.
func All(ms ...Matcher) Matcher { return allMatcher{ms} }
// Any returns a matcher that always matches.
func Any() Matcher { return anyMatcher{} }
// Cond returns a matcher that matches when the given function returns true
// after passing it the parameter to the mock function.
// This is particularly useful in case you want to match over a field of a custom struct, or dynamic logic.
//
// Example usage:
//
// Cond(func(x int){return x == 1}).Matches(1) // returns true
// Cond(func(x int){return x == 2}).Matches(1) // returns false
func Cond[T any](fn func(x T) bool) Matcher { return condMatcher[T]{fn} }
// AnyOf returns a composite Matcher that returns true if at least one of the
// matchers returns true.
//
// Example usage:
//
// AnyOf(1, 2, 3).Matches(2) // returns true
// AnyOf(1, 2, 3).Matches(10) // returns false
// AnyOf(Nil(), Len(2)).Matches(nil) // returns true
// AnyOf(Nil(), Len(2)).Matches("hi") // returns true
// AnyOf(Nil(), Len(2)).Matches("hello") // returns false
func AnyOf(xs ...any) Matcher {
ms := make([]Matcher, 0, len(xs))
for _, x := range xs {
if m, ok := x.(Matcher); ok {
ms = append(ms, m)
} else {
ms = append(ms, Eq(x))
}
}
return anyOfMatcher{ms}
}
// Eq returns a matcher that matches on equality.
//
// Example usage:
//
// Eq(5).Matches(5) // returns true
// Eq(5).Matches(4) // returns false
func Eq(x any) Matcher { return eqMatcher{x} }
// Len returns a matcher that matches on length. This matcher returns false if
// is compared to a type that is not an array, chan, map, slice, or string.
func Len(i int) Matcher {
return lenMatcher{i}
}
// Nil returns a matcher that matches if the received value is nil.
//
// Example usage:
//
// var x *bytes.Buffer
// Nil().Matches(x) // returns true
// x = &bytes.Buffer{}
// Nil().Matches(x) // returns false
func Nil() Matcher { return nilMatcher{} }
// Not reverses the results of its given child matcher.
//
// Example usage:
//
// Not(Eq(5)).Matches(4) // returns true
// Not(Eq(5)).Matches(5) // returns false
func Not(x any) Matcher {
if m, ok := x.(Matcher); ok {
return notMatcher{m}
}
return notMatcher{Eq(x)}
}
// Regex checks whether parameter matches the associated regex.
//
// Example usage:
//
// Regex("[0-9]{2}:[0-9]{2}").Matches("23:02") // returns true
// Regex("[0-9]{2}:[0-9]{2}").Matches([]byte{'2', '3', ':', '0', '2'}) // returns true
// Regex("[0-9]{2}:[0-9]{2}").Matches("hello world") // returns false
// Regex("[0-9]{2}").Matches(21) // returns false as it's not a valid type
func Regex(regexStr string) Matcher {
return regexMatcher{regex: regexp.MustCompile(regexStr)}
}
// AssignableToTypeOf is a Matcher that matches if the parameter to the mock
// function is assignable to the type of the parameter to this function.
//
// Example usage:
//
// var s fmt.Stringer = &bytes.Buffer{}
// AssignableToTypeOf(s).Matches(time.Second) // returns true
// AssignableToTypeOf(s).Matches(99) // returns false
//
// var ctx = reflect.TypeOf((*context.Context)(nil)).Elem()
// AssignableToTypeOf(ctx).Matches(context.Background()) // returns true
func AssignableToTypeOf(x any) Matcher {
if xt, ok := x.(reflect.Type); ok {
return assignableToTypeOfMatcher{xt}
}
return assignableToTypeOfMatcher{reflect.TypeOf(x)}
}
// InAnyOrder is a Matcher that returns true for collections of the same elements ignoring the order.
//
// Example usage:
//
// InAnyOrder([]int{1, 2, 3}).Matches([]int{1, 3, 2}) // returns true
// InAnyOrder([]int{1, 2, 3}).Matches([]int{1, 2}) // returns false
func InAnyOrder(x any) Matcher {
return inAnyOrderMatcher{x}
}

36
vendor/go.uber.org/mock/gomock/string.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package gomock
import (
"fmt"
"reflect"
)
// getString is a safe way to convert a value to a string for printing results
// If the value is a a mock, getString avoids calling the mocked String() method,
// which avoids potential deadlocks
func getString(x any) string {
if isGeneratedMock(x) {
return fmt.Sprintf("%T", x)
}
if s, ok := x.(fmt.Stringer); ok {
return s.String()
}
return fmt.Sprintf("%v", x)
}
// isGeneratedMock checks if the given type has a "isgomock" field,
// indicating it is a generated mock.
func isGeneratedMock(x any) bool {
typ := reflect.TypeOf(x)
if typ == nil {
return false
}
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
if typ.Kind() != reflect.Struct {
return false
}
_, isgomock := typ.FieldByName("isgomock")
return isgomock
}