Mock lister: move utils to uti.go, rm useless mocks

Signed-off-by: Maël Valais <mael@vls.dev>
This commit is contained in:
Maël Valais 2021-01-22 18:56:34 +01:00
parent 38919b7eb2
commit 077f4ee66e
3 changed files with 120 additions and 154 deletions

View File

@ -6,6 +6,7 @@ go_library(
"certificaterequest.go",
"order.go",
"secret.go",
"util.go",
],
importpath = "github.com/jetstack/cert-manager/test/unit/listers",
visibility = ["//visibility:public"],

View File

@ -17,10 +17,6 @@ limitations under the License.
package listers
import (
"bufio"
"bytes"
"runtime"
"strings"
"sync"
"testing"
@ -64,21 +60,13 @@ func MockCertificateRequestLister(t *testing.T) *CertificateRequestListerMock {
return &CertificateRequestListerMock{t: t}
}
// The expectSelector is a label selector of the form:
// "partition in (customerA, customerB),environment!=qa"
// as detailed in
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels
func (mock *CertificateRequestListerMock) CallList(expectSelector string) *CertificateRequestListerMock {
mock.t.Cleanup(assertWasCalled(mock.t, &mock.gotListCalled, "lister.List", assert.CallerInfo()))
mock.expectListCalled = true
mock.expectListSelector = expectSelector
return mock
}
type CertificateRequestListerMock struct {
t *testing.T
mu sync.Mutex
func (mock *CertificateRequestListerMock) ReturnList(returnList []*cmapi.CertificateRequest, returnErr error) *CertificateRequestListerMock {
mock.returnList = returnList
mock.returnListErr = returnErr
return mock
expectNamespaceCalled, gotNamespaceCalled bool
expectNamespace string
returnNamespaceLister *CertificateRequestListerNamespacedMock
}
// This mock function does not have a matching ReturnCertificateRequests
@ -92,6 +80,44 @@ func (mock *CertificateRequestListerMock) CallCertificateRequests(expectNamespac
return mock.returnNamespaceLister
}
func (mock *CertificateRequestListerMock) CallList(_ string) *CertificateRequestListerMock {
mock.t.Error("lister.List is not implemented in the mock, please implement it :-)")
return nil
}
func (mock *CertificateRequestListerMock) CertificateRequests(gotNamespace string) cmlist.CertificateRequestNamespaceLister {
mock.mu.Lock()
defer mock.mu.Unlock()
assertCanBeCalled(mock.t, mock.expectNamespaceCalled, mock.gotNamespaceCalled, curFuncName(), assert.CallerInfo())
assert.Equal(mock.t, mock.expectNamespace, gotNamespace)
mock.gotNamespaceCalled = true
return mock.returnNamespaceLister
}
func (mock *CertificateRequestListerMock) List(gotLabel labels.Selector) (ret []*cmapi.CertificateRequest, err error) {
mock.t.Error("lister.CertificateRequest().List is not implemented in the mock, please implement it :-)")
return nil, nil
}
type CertificateRequestListerNamespacedMock struct {
t *testing.T
mu sync.Mutex
expectListCalled, gotListCalled bool
expectListSelector string
returnList []*cmapi.CertificateRequest
returnListErr error
}
func (mock *CertificateRequestListerNamespacedMock) List(got labels.Selector) (ret []*cmapi.CertificateRequest, err error) {
mock.mu.Lock()
defer mock.mu.Unlock()
assertCanBeCalled(mock.t, mock.expectListCalled, mock.gotListCalled, curFuncName(), assert.CallerInfo())
mock.gotListCalled = true
assert.Equal(mock.t, mock.expectListSelector, got.String())
return mock.returnList, mock.returnListErr
}
// The expectSelector is a label selector of the form:
// "partition in (customerA, customerB),environment!=qa"
// as detailed in
@ -109,115 +135,33 @@ func (mock *CertificateRequestListerNamespacedMock) ReturnList(returnList []*cma
return mock
}
func (mock *CertificateRequestListerNamespacedMock) CallGet(expectName string) *CertificateRequestListerNamespacedMock {
mock.t.Cleanup(assertWasCalled(mock.t, &mock.gotGetCalled, "lister.CertificateRequest().Get", assert.CallerInfo()))
mock.expectGetCalled = true
mock.expectGetName = expectName
return mock
}
func (mock *CertificateRequestListerNamespacedMock) ReturnGet(returnGet *cmapi.CertificateRequest, returnErr error) *CertificateRequestListerNamespacedMock {
mock.returnGet = returnGet
mock.returnGetErr = returnErr
return mock
}
type CertificateRequestListerMock struct {
t *testing.T
mu sync.Mutex
expectNamespaceCalled, gotNamespaceCalled bool
expectNamespace string
returnNamespaceLister *CertificateRequestListerNamespacedMock
expectListCalled, gotListCalled bool
expectListSelector string
returnList []*cmapi.CertificateRequest
returnListErr error
}
func (mock *CertificateRequestListerMock) CertificateRequests(gotNamespace string) cmlist.CertificateRequestNamespaceLister {
mock.mu.Lock()
defer mock.mu.Unlock()
assertCanBeCalled(mock.t, mock.expectNamespaceCalled, mock.gotNamespaceCalled, curFuncName(), assert.CallerInfo())
assert.Equal(mock.t, mock.expectNamespace, gotNamespace)
mock.gotNamespaceCalled = true
return mock.returnNamespaceLister
}
func (mock *CertificateRequestListerMock) List(gotLabel labels.Selector) (ret []*cmapi.CertificateRequest, err error) {
mock.mu.Lock()
defer mock.mu.Unlock()
assertCanBeCalled(mock.t, mock.expectListCalled, mock.gotListCalled, curFuncName(), assert.CallerInfo())
assert.Equal(mock.t, mock.expectListSelector, gotLabel.String())
mock.gotListCalled = true
return mock.returnList, mock.returnListErr
}
type CertificateRequestListerNamespacedMock struct {
t *testing.T
mu sync.Mutex
expectGetCalled, gotGetCalled bool
expectGetName string
returnGet *cmapi.CertificateRequest
returnGetErr error
expectListCalled, gotListCalled bool
expectListSelector string
returnList []*cmapi.CertificateRequest
returnListErr error
}
func (mock *CertificateRequestListerNamespacedMock) List(got labels.Selector) (ret []*cmapi.CertificateRequest, err error) {
mock.mu.Lock()
defer mock.mu.Unlock()
assertCanBeCalled(mock.t, mock.expectListCalled, mock.gotListCalled, curFuncName(), assert.CallerInfo())
mock.gotListCalled = true
assert.Equal(mock.t, mock.expectListSelector, got.String())
return mock.returnList, mock.returnListErr
}
func (mock *CertificateRequestListerNamespacedMock) Get(gotName string) (cr *cmapi.CertificateRequest, e error) {
mock.mu.Lock()
defer mock.mu.Unlock()
assertCanBeCalled(mock.t, mock.expectGetCalled, mock.gotGetCalled, curFuncName(), assert.CallerInfo())
mock.gotGetCalled = true
assert.Equal(mock.t, mock.expectGetName, gotName)
func (mock *CertificateRequestListerNamespacedMock) Get(_ string) (*cmapi.CertificateRequest, error) {
mock.t.Error("lister.CertificateRequest().List is not implemented in the mock, please implement it :-)")
return nil, nil
}
// Returns the caller's function name with the full package import path.
func curFuncName() (fnName string) {
pc, _, _, ok := runtime.Caller(1)
if !ok {
return "?"
}
return runtime.FuncForPC(pc).Name()
func (mock *CertificateRequestListerNamespacedMock) CallGet(expectName string) *CertificateRequestListerNamespacedMock {
mock.t.Error("lister.CertificateRequest().List is not implemented in the mock, please implement it :-)")
return nil
}
// Whenever a mocked function is called, we need to fail if this call was
// already made or if this call never should have happened.
func assertCanBeCalled(t *testing.T, expectCalled, gotCalled bool, funcName string, stackFrames []string) {
// No need to show the file:line of the caller of this function since
// it belongs to "testing framework".
stackFrames = stackFrames[1:]
if !expectCalled {
FailWithStack(t, stackFrames, funcName+" is not expected to be called but was called")
failWithStack(t, stackFrames, funcName+" is not expected to be called but was called")
}
if gotCalled {
FailWithStack(t, stackFrames, funcName+" was expected to run once but was run twice")
failWithStack(t, stackFrames, funcName+" was expected to run once but was run twice")
}
}
// Since this func is meant to be called with t.Cleanup, the stack frame
// information about the source of the call is lost. Testify usually gives
// us a useful file:line indication of where an assertion failed, and
// t.Cleanup makes this stack trace unreadable with tons of testing.go
// layers.
//
// Until Testify fixes this, we keep track of the caller information right
// from the start with the stackFrames argument, and we use a patched
// version of assert.Fail that can be given a stack frames.
// This function is meant to be run with t.Cleanup. During the cleanup,
// this function checks that the function named funcName has been called as
// expected.
func assertWasCalled(t *testing.T, funcWasCalled *bool, funcName string, stackFrames []string) func() {
return func() {
// We pass this boolean by reference due to the fact that this
@ -232,47 +176,6 @@ func assertWasCalled(t *testing.T, funcWasCalled *bool, funcName string, stackFr
// No need to show the file:line of the caller of this function since
// it belongs to "testing frqmework".
FailWithStack(t, stackFrames[1:], funcName+" was expected to be called but was not called")
failWithStack(t, stackFrames[1:], funcName+" was expected to be called but was not called")
}
}
// FailWithStack does the same as assert.Fail except it gives you the
// ability to give your own stack frames.
func FailWithStack(t *testing.T, stackFrames []string, msg string) {
// The following is a vendored version of Testify's assert.Fail.
type labeledContent struct{ Label, Content string }
content := []labeledContent{
{Label: "Error Trace", Content: strings.Join(stackFrames, "\n")},
{Label: "Error", Content: msg},
{Label: "Test", Content: t.Name()},
}
// Helper that re-wrap and indent the "content" fields of the above
// content array.
indentMessageLines := func(message string, longestLabelLen int) string {
buf := new(bytes.Buffer)
for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
if i != 0 {
buf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
}
buf.WriteString(scanner.Text())
}
return buf.String()
}
longestLabelLen := 0
for _, v := range content {
if len(v.Label) > longestLabelLen {
longestLabelLen = len(v.Label)
}
}
// Turn the above content slice into a nicely formatted string that
// wraps and properly indented.
var output string
for _, v := range content {
output += "\t" + v.Label + ":" + strings.Repeat(" ", longestLabelLen-len(v.Label)) + "\t" + indentMessageLines(v.Content, longestLabelLen) + "\n"
}
t.Errorf("\n%s", ""+output)
}

62
test/unit/listers/util.go Normal file
View File

@ -0,0 +1,62 @@
package listers
import (
"bufio"
"bytes"
"runtime"
"strings"
"testing"
)
// Returns the caller's function name with the full package import path.
func curFuncName() (fnName string) {
pc, _, _, _ := runtime.Caller(1)
return runtime.FuncForPC(pc).Name()
}
// failWithStack does the same as assert.Fail except it gives you the
// ability to give your own stack frames. The purpose of this function is
// just to help the developer who wants to know where a Testify assertion
// failed.
//
// We use that whenever we want to do an assertion that happens in a
// t.Cleanup function, since the t.Cleanup happens outside of the user's
// test file which means the stack frames are totally off.
func failWithStack(t *testing.T, stackFrames []string, msg string) {
// The following is a vendored version of Testify's assert.Fail.
type labeledContent struct{ Label, Content string }
content := []labeledContent{
{Label: "Error Trace", Content: strings.Join(stackFrames, "\n")},
{Label: "Error", Content: msg},
{Label: "Test", Content: t.Name()},
}
// Helper that re-wrap and indent the "content" fields of the above
// content array.
indentMessageLines := func(message string, longestLabelLen int) string {
buf := new(bytes.Buffer)
for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
if i != 0 {
buf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
}
buf.WriteString(scanner.Text())
}
return buf.String()
}
longestLabelLen := 0
for _, v := range content {
if len(v.Label) > longestLabelLen {
longestLabelLen = len(v.Label)
}
}
// Turn the above content slice into a nicely formatted string that
// wraps and properly indented.
var output string
for _, v := range content {
output += "\t" + v.Label + ":" + strings.Repeat(" ", longestLabelLen-len(v.Label)) + "\t" + indentMessageLines(v.Content, longestLabelLen) + "\n"
}
t.Errorf("\n%s", ""+output)
}