Skip to content

Commit

Permalink
use test suite for Gin testing
Browse files Browse the repository at this point in the history
  • Loading branch information
sbpann committed Jun 16, 2024
1 parent 9779f6c commit cff0f8b
Show file tree
Hide file tree
Showing 11 changed files with 1,342 additions and 1,170 deletions.
2 changes: 1 addition & 1 deletion context.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var ErrNoRedis = errors.New("*redis.Client is not present in this context")
var ErrNoSQL = errors.New("*sql.DB is not present in this context")
var ErrNoSQLX = errors.New("*sqlx.DB is not present in this context")

func AddValuesToContext(ctx Context, values map[string]any) Context {
func UpdateContextValue(ctx Context, values map[string]any) Context {
for key, value := range values {
ctx.SetValue(key, value)
}
Expand Down
2 changes: 1 addition & 1 deletion context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestAddValuesToContext(t *testing.T) {
key2 := "key2"
value2 := 2

ctx = AddValuesToContext(NewContextWithOptions(&ContextOptions{Parent: ctx}), map[string]any{
ctx = UpdateContextValue(NewContextWithOptions(&ContextOptions{Parent: ctx}), map[string]any{
key1: value1,
key2: value2,
})
Expand Down
50 changes: 31 additions & 19 deletions gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func defaultHttpContextWithGin(ctx Context, g *gin.Context) *httpContextWithGin
return &httpContextWithGin{
Context: ctx,
gin: g,
ginHandlerInfo: ginHandlerInfo{gin: g},
ginRequest: ginRequest{gin: g},
ginHandlerControl: ginHandlerControl{gin: g},
ginSetterAndGetter: ginSetterAndGetter{gin: g},
Expand All @@ -30,18 +29,35 @@ func defaultHttpContextWithGin(ctx Context, g *gin.Context) *httpContextWithGin
}
}

func NewGinHandlerFunc(ctx Context, handlerFunc HandlerFunc) gin.HandlerFunc {
return func(g *gin.Context) {
httpError := handlerFunc(defaultHttpContextWithGin(ctx, g))
if httpError != nil {
g.JSON(httpError.GetStatus(), httpError.GetJSON())
}
}
type NewHandlerPayload struct {
Ctx Context
Func HandlerFunc
Data map[string]any
Name *string
}

func NewGinHandlerFuncWithData(ctx Context, handlerFunc HandlerFuncWithData, data map[string]any) gin.HandlerFunc {
func NewGinHandlerFunc(payload *NewHandlerPayload) gin.HandlerFunc {
if payload.Data == nil {
payload.Data = make(map[string]any)
}
var handlerNames []string
if payload.Ctx.Value("HandlerNames") == nil {
handlerNames = make([]string, 0)
} else {
handlerNames = payload.Ctx.Value("HandlerNames").([]string)
}

if payload.Name == nil {
unamedHandler := "UnamedHandler"
payload.Name = &unamedHandler
}
handlerNames = append(handlerNames, *payload.Name)

payload.Data["HandlerNames"] = handlerNames
UpdateContextValue(payload.Ctx, payload.Data)

return func(g *gin.Context) {
httpError := handlerFunc(defaultHttpContextWithGin(ctx, g), data)
httpError := payload.Func(defaultHttpContextWithGin(payload.Ctx, g))
if httpError != nil {
g.JSON(httpError.GetStatus(), httpError.GetJSON())
}
Expand All @@ -51,7 +67,6 @@ func NewGinHandlerFuncWithData(ctx Context, handlerFunc HandlerFuncWithData, dat
type httpContextWithGin struct {
Context
gin *gin.Context
ginHandlerInfo
ginRequest
ginHandlerControl
ginSetterAndGetter
Expand All @@ -63,16 +78,13 @@ type httpContextWithGin struct {
ginResponseBody
}

type ginHandlerInfo struct {
gin *gin.Context
}

func (hi *ginHandlerInfo) HandlerName() string {
return hi.gin.HandlerName()
func (ctx *httpContextWithGin) HandlerName() string {
handlerNames := ctx.HandlerNames()
return handlerNames[len(handlerNames)-1]
}

func (hi *ginHandlerInfo) HandlerNames() []string {
return hi.gin.HandlerNames()
func (ctx *httpContextWithGin) HandlerNames() []string {
return ctx.Value("HandlerNames").([]string)
}

type ginRequest struct {
Expand Down
130 changes: 130 additions & 0 deletions gin_base_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package bucharest_test

import (
"errors"
"fmt"
"net/http"
"time"

. "github.com/argonlab-io/bucharest"
"github.com/argonlab-io/bucharest/utils"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

type binderTest struct {
Foo string `form:"foo" json:"foo" xml:"foo" binding:"required"`
}

type GinTestSuite struct {
suite.Suite
Port int
Server *http.Server
Paths []string
Ctx Context
}

func (suite *GinTestSuite) SetupSuite() {
suite.Port = 9000
}

func (suite *GinTestSuite) SetupTest() {
suite.Port++
}

func (suite *GinTestSuite) TearDownTest() {

suite.shutdownTestServer()
}

type testHandlers struct {
function gin.HandlerFunc
method string
}

type testServerOption struct {
handlers []*testHandlers
middlewares []gin.HandlerFunc
}

func (suite *GinTestSuite) createTestServer(option *testServerOption) {
g := gin.New()
gin.SetMode(gin.TestMode)
g.GET("/", func(ctx *gin.Context) {
ctx.Status(http.StatusNoContent)
})

if len(option.middlewares) > 0 {
for _, middleware := range option.middlewares {
g.Use(middleware)
}
}

paths := make([]string, 0)
port := fmt.Sprint(suite.Port)

for _, handler := range option.handlers {
randomPath := uuid.New().String()
paths = append(paths, fmt.Sprintf("http://0.0.0.0:%s/%s", port, randomPath))
switch handler.method {
case http.MethodGet:
{
g.GET(fmt.Sprintf("/%s", randomPath), handler.function)
}
case http.MethodPost:
{
g.POST(fmt.Sprintf("/%s", randomPath), handler.function)
}
default:
{
panic("not implemented")
}
}
}

server := &http.Server{
Addr: fmt.Sprintf("0.0.0.0:%s", port),
Handler: g.Handler(),
}

suite.Server = server
suite.Paths = paths
}

func (suite *GinTestSuite) startTestServer() {
go func() {
if err := suite.Server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
assert.NoError(suite.T(), err)
}
}()
}

func (suite *GinTestSuite) shutdownTestServer() {
err := suite.Server.Shutdown(suite.Ctx)
assert.NoError(suite.T(), err)
assert.NoError(suite.T(), suite.Ctx.Err())
}

func (suite *GinTestSuite) assertServerHealthy() {
assert.NoError(suite.T(), utils.Await(&utils.AwaitOptions{
Condition: func() bool {
res, err := http.Get(fmt.Sprintf("http://%s", suite.Server.Addr))
return err == nil && res.StatusCode == http.StatusNoContent
},
Timeout: 5 * time.Second,
}))
}

func (suite *GinTestSuite) assertNoContentResponse(resp *http.Response, err error) {
assert.NoError(suite.T(), err)
assert.NotNil(suite.T(), resp)
assert.Equal(suite.T(), http.StatusNoContent, resp.StatusCode)
}

func (suite *GinTestSuite) assertOkResponse(resp *http.Response, err error) {
assert.NoError(suite.T(), err)
assert.NotNil(suite.T(), resp)
assert.Equal(suite.T(), http.StatusOK, resp.StatusCode)
}
Loading

0 comments on commit cff0f8b

Please sign in to comment.