Skip to content

Commit

Permalink
fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Maarten van der Heijden committed Sep 22, 2023
1 parent 43bedf7 commit ba9bc91
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 92 deletions.
8 changes: 3 additions & 5 deletions controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"io"
"net/http"
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -74,7 +75,6 @@ func TestSuccessResponse_ReturnsExpectedResult(t *testing.T) {

func TestSuccessResponse_ReturnsData(t *testing.T) {
t.Parallel()

// Arrange
testingObject := new(mockT)

Expand Down Expand Up @@ -106,8 +106,7 @@ func TestSuccessResponse_FailsOnNoBody(t *testing.T) {
// Arrange
testingObject := new(mockT)
response := &http.Response{
//nolint:mirror // Used for a test
Body: io.NopCloser(bytes.NewBuffer([]byte(""))),
Body: io.NopCloser(strings.NewReader("")),
StatusCode: http.StatusOK,
}

Expand All @@ -127,8 +126,7 @@ func TestSuccessResponse_FailsOnUnmarshall(t *testing.T) {
testingObject := new(mockT)
response := &http.Response{
StatusCode: http.StatusOK,
//nolint:mirror // Used for a test
Body: io.NopCloser(bytes.NewBuffer([]byte("test"))),
Body: io.NopCloser(strings.NewReader("test")),
}

var result testObject
Expand Down
2 changes: 0 additions & 2 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ func ExampleResponse() {
func ExampleExpectCalled_withoutVarargs() {
t := new(testing.T)

// create gin context
ginContext := gin.Default()

// create expectation
Expand Down Expand Up @@ -99,7 +98,6 @@ func ExampleExpectCalled_withoutVarargs() {
func ExampleExpectCalled_withVarargs() {
t := new(testing.T)

// create gin context
ginContext := gin.Default()

// create expectation
Expand Down
8 changes: 5 additions & 3 deletions expect.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ type calledConfig struct {
// ExpectCalled can be used on a gin endpoint to express an expectation that the endpoint will
// be called some time in the future. In combination with a test
// can wait for this expectation to be true or fail after some predetermined amount of time
func ExpectCalled(t TestingT, context *gin.Engine, path string, options ...ExpectOption) *sync.WaitGroup {
func ExpectCalled(t TestingT, ctx *gin.Engine, path string, options ...ExpectOption) *sync.WaitGroup {
t.Helper()

if context == nil {
if ctx == nil {
t.Errorf("context cannot be nil")

return nil
Expand All @@ -55,7 +55,7 @@ func ExpectCalled(t TestingT, context *gin.Engine, path string, options ...Expec

// Add middleware for provided route
var timesCalled int
context.Use(func(c *gin.Context) {
ctx.Use(func(c *gin.Context) {
c.Next()
if c.FullPath() != path {
return
Expand All @@ -64,6 +64,8 @@ func ExpectCalled(t TestingT, context *gin.Engine, path string, options ...Expec
timesCalled++
if timesCalled <= config.Times {
config.Expectation.Done()

return
}

t.Errorf("%s hook asserts called %d times but called at least %d times\n", path, config.Times, timesCalled)
Expand Down
158 changes: 76 additions & 82 deletions expect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,96 +4,90 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"

"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)

// setup prepares the tests
func setup(endpoint string, varargs ...ExpectOption) (*testing.T, chan struct{}, *sync.WaitGroup, *httptest.Server) {
testObject := new(testing.T)
const expectTimeout = 5 * time.Second

// create gin context
func TestExpectCalled_SingleCallReturnsSuccess(t *testing.T) {
t.Parallel()
// Arrange
testObject := new(testing.T)
ginContext := gin.Default()

// create expectation
expectation := ExpectCalled(testObject, ginContext, endpoint, varargs...)
// Act
expectation := ExpectCalled(testObject, ginContext, "/ping")

// create endpoints on ginContext
ginContext.GET(endpoint, func(context *gin.Context) {
context.Status(http.StatusOK)
// Assert
ginContext.GET("/ping", func(ctx *gin.Context) {
ctx.Status(http.StatusOK)
})

// channel for go-routine to signal completion
c := make(chan struct{})

// create webserver
ts := httptest.NewServer(ginContext)

return testObject, c, expectation, ts
}

func TestExpectCalled_SingleCallWithDefaultArgumentsReturnsSuccess(t *testing.T) {
t.Parallel()
_, err := http.Get(fmt.Sprintf("%s%s", ts.URL, "/ping"))

// Arrange
//nolint:goconst // Not relevant
path := "/hello-world"
testObject, c, expectation, ts := setup(path)
assert.NoError(t, err)

// Act
_, err := http.Get(fmt.Sprintf("%s%s", ts.URL, path))

// Assert
assert.Nil(t, err)
completionChannel := make(chan struct{})

go func() {
defer close(c)
expectation.Wait()
completionChannel <- struct{}{}
}()

select {
case <-c:
case <-completionChannel:
assert.False(t, testObject.Failed())
case <-time.After(15 * time.Second):
t.FailNow()
case <-time.After(expectTimeout):
t.Error("did not complete")
}
}

func TestExpectCalled_ZeroCallsWithDefaultArgumentsTimesOutAndFails(t *testing.T) {
func TestExpectCalled_ZeroCallsFails(t *testing.T) {
t.Parallel()

// arrange
path := "/hello-world"
_, c, expectation, ts := setup(path)
// Arrange
testObject := new(testing.T)
ginContext := gin.Default()

// Act
// Make a call to and endpoint which is _NOT_ path such that path is never called
_, err := http.Get(fmt.Sprintf("%s%s", ts.URL, "/something-other-than-path"))
expectation := ExpectCalled(testObject, ginContext, "/ping")

// Assert
assert.Nil(t, err)
ginContext.GET("/ping", func(ctx *gin.Context) {
ctx.Status(http.StatusOK)
})

ts := httptest.NewServer(ginContext)

_, err := http.Get(fmt.Sprintf("%s%s", ts.URL, "/pong"))

// Assert
assert.NoError(t, err)

completionChannel := make(chan struct{})

go func() {
defer close(c)
expectation.Wait()
completionChannel <- struct{}{}
}()

select {
case <-c:
t.FailNow()
case <-time.After(15 * time.Second):
// test is bounded to accept after 15 seconds
case <-completionChannel:
t.Error("should not have completed")

case <-time.After(expectTimeout):
// Success!
}
}

func TestExpectCalled_NilGinContextReturnsError(t *testing.T) {
t.Parallel()

// arrange
// Arrange
testObject := new(testing.T)
var ginContext *gin.Engine

Expand All @@ -105,76 +99,76 @@ func TestExpectCalled_NilGinContextReturnsError(t *testing.T) {
assert.Nil(t, expectation)
}

func TestExpectCalled_CalledToOftenReturnsError(t *testing.T) {
func TestExpectCalled_CalledTooOftenReturnsError(t *testing.T) {
t.Parallel()
// Arrange
testObject := new(testing.T)

// arrange
path := "/hello-world"
testObject, c, expectation, ts := setup(path)
ginContext := gin.Default()

// Act
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, path))
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, path))
expectation := ExpectCalled(testObject, ginContext, "/ping")

// Assert
ginContext.GET("/ping", func(ctx *gin.Context) {
ctx.Status(http.StatusOK)
})

ts := httptest.NewServer(ginContext)

_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, "/ping"))
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, "/ping"))

completionChannel := make(chan struct{})

go func() {
defer close(c)
expectation.Wait()
completionChannel <- struct{}{}
}()

select {
case <-c:
case <-completionChannel:
assert.True(t, testObject.Failed())
case <-time.After(15 * time.Second):
t.FailNow()
case <-time.After(expectTimeout):
t.Error("did not complete")
}
}

func TestExpectCalled_TwoTimesWithTwoEndpointsSucceeds(t *testing.T) {
t.Parallel()

// arrange
// Arrange
testObject := new(testing.T)

// create gin context
ginContext := gin.Default()

// endpoints
endpointCalledTwice := "/hello-world"
endpointCalledOnce := "/other-path"

// create expectation
expectation := ExpectCalled(testObject, ginContext, endpointCalledTwice, TimesCalled(2))
expectation = ExpectCalled(testObject, ginContext, endpointCalledOnce, Expectation(expectation))
// Act
expectation := ExpectCalled(testObject, ginContext, "/ping", TimesCalled(2))
expectation = ExpectCalled(testObject, ginContext, "/pong", Expectation(expectation))

// create endpoints on ginContext
for _, endpoint := range []string{endpointCalledTwice, endpointCalledOnce} {
// Assert
for _, endpoint := range []string{"/ping", "/pong"} {
ginContext.GET(endpoint, func(context *gin.Context) {
context.Status(http.StatusOK)
})
}

// channel for go-routine to signal completion
c := make(chan struct{})

// create webserver
ts := httptest.NewServer(ginContext)

// act
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, endpointCalledTwice))
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, endpointCalledTwice))
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, endpointCalledOnce))
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, "/ping"))
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, "/ping"))
_, _ = http.Get(fmt.Sprintf("%s%s", ts.URL, "/pong"))

completionChannel := make(chan struct{})

// Assert
go func() {
defer close(c)
expectation.Wait()
completionChannel <- struct{}{}
}()

select {
case <-c:
case <-completionChannel:
assert.False(t, testObject.Failed())
case <-time.After(15 * time.Second):
t.FailNow()
case <-time.After(expectTimeout):
t.Error("did not complete")
}
}

0 comments on commit ba9bc91

Please sign in to comment.