Skip to content

Commit

Permalink
Some refactoring, linting, tests
Browse files Browse the repository at this point in the history
  • Loading branch information
smgladkovskiy committed Jul 28, 2021
1 parent f87dd3b commit b24a7b2
Show file tree
Hide file tree
Showing 11 changed files with 314 additions and 97 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
vendor
.golangci.yml
c.out
coverage.html
coverage.html
tests.mk
linter.mk
.golangci*.yml
bin
38 changes: 25 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,33 @@ deps:
go mod vendor
.PHONY: deps

get_lint_config:
@[ -f ./.golangci.yml ] && echo ".golangci.yml exists" || ( echo "getting .golangci.yml" && curl -O https://raw.githubusercontent.com/microparts/docker-golang/master/lint/.golangci.yml )
.PHONY: get_lint_config
# ----
## LINTER stuff start

linter_include_check:
@[ -f linter.mk ] && echo "linter.mk include exists" || (echo "getting linter.mk from github.com" && curl -sO https://raw.githubusercontent.com/spacetab-io/makefiles/master/golang/linter.mk)

lint: get_lint_config
golangci-lint run
.PHONY: lint
lint: linter_include_check
@make -f linter.mk go_lint

## LINTER stuff end
# ----

# ----
## TESTS stuff start

tests_include_check:
@[ -f tests.mk ] && echo "tests.mk include exists" || (echo "getting tests.mk from github.com" && curl -sO https://raw.githubusercontent.com/spacetab-io/makefiles/master/golang/tests.mk)

test-unit:
go test $$(go list ./...) --race --cover -count=1 -timeout 1s -coverprofile=c.out -v
.PHONY: test-unit
tests: tests_include_check
@make -f tests.mk go_tests
.PHONY: tests

coverage-html:
go tool cover -html=c.out -o coverage.html
.PHONE: coverage-html
tests_html: tests_include_check
@make -f tests.mk go_tests_html
@open coverage.html
.PHONY: tests

test: deps test-unit coverage-html
.PHONY: test
## TESTS stuff end
# ----
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,29 @@ package main
import (
"errors"
"net/http"

"github.com/gin-gonic/gin"
"github.com/microparts/errors-go-gin"
"github.com/spacetab-io/errors-gin-go"
)

func main() {
r := gin.New()

r.GET("/", func(c*gin.Context) {c.JSON(http.StatusOK,`{"status":"ok"}`)})
r.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, `{"status":"ok"}`) })
r.GET("/err", func(c *gin.Context) { ginerrors.Response(c, errors.New("error")) })
_ = r.Run(":8080")
}
```

## Linter

Lint code with [golangci-lint](https://github.com/golangci/golangci-lint) and
[custom config](https://github.com/microparts/docker-golang/blob/master/lint/.golangci.yml) for it:
Lint code with [golangci-lint](https://github.com/golangci/golangci-lint) and
[custom config](https://github.com/spacetab-io/linter-go/blob/master/.golangci.yml) for it:

make lint

## Testing

Test code with race checking and generation coverage profile:

make test
make tests
11 changes: 6 additions & 5 deletions gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,24 @@ import (
"strings"

"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
errs "github.com/spacetab-io/errors-go"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"gopkg.in/go-playground/validator.v9"

errs "github.com/microparts/errors-go"
)

const (
validationErrorMessage = "validation error"
)

//Response makes common error response
// Response makes common error response.
func Response(c *gin.Context, err interface{}) {
errCode, data := MakeResponse(err, getLang(c))
resp := errs.Response{Error: *data}
c.AbortWithStatusJSON(errCode, resp)
}

//MakeResponse makes ErrorObject based on error type
// MakeResponse makes ErrorObject based on error type.
func MakeResponse(err interface{}, lang langName) (int, *errs.ErrorObject) {
errObj := &errs.ErrorObject{}
errCode := http.StatusBadRequest
Expand All @@ -39,9 +38,11 @@ func MakeResponse(err interface{}, lang langName) (int, *errs.ErrorObject) {
case []error:
errCode = http.StatusInternalServerError
msgs := make([]string, 0)

for _, e := range err.([]error) {
msgs = append(msgs, e.Error())
}

errObj.Message = strings.Join(msgs, "; ")
case validator.ValidationErrors:
errCode = http.StatusUnprocessableEntity
Expand Down
46 changes: 29 additions & 17 deletions gin_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package ginerrors
package ginerrors_test

import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
ginerrors "github.com/microparts/errors-go-gin"
errs "github.com/spacetab-io/errors-go"
"github.com/stretchr/testify/assert"
"gopkg.in/go-playground/validator.v9"

errs "github.com/microparts/errors-go"
)

func TestMakeResponse(t *testing.T) {
Expand All @@ -24,25 +24,32 @@ func TestMakeResponse(t *testing.T) {
}
errType := errs.ErrorTypeError

// nolint: goerr113
cases := []testCase{
{name: "common error", err: errors.New("common err"), httpCode: http.StatusBadRequest, errObject: &errs.ErrorObject{Message: "common err", Type: &errType}},

{name: "validation error", err: makeValidationError(), httpCode: http.StatusUnprocessableEntity, errObject: &errs.ErrorObject{Message: "validation error", Validation: map[errs.FieldName][]errs.ValidationError{"String": {"Ошибка валидации для свойства `String` с правилом `%!s(MISSING)`"}}, Type: &errType}},

{name: "mux err no method allowed", err: ErrNoMethod, httpCode: http.StatusMethodNotAllowed, errObject: &errs.ErrorObject{Message: ErrNoMethod.Error(), Type: &errType}},
{name: "mux err route not found", err: ErrNotFound, httpCode: http.StatusNotFound, errObject: &errs.ErrorObject{Message: ErrNotFound.Error(), Type: &errType}},
{name: "mux err no method allowed", err: ginerrors.ErrNoMethod, httpCode: http.StatusMethodNotAllowed, errObject: &errs.ErrorObject{Message: ginerrors.ErrNoMethod.Error(), Type: &errType}},
{name: "mux err route not found", err: ginerrors.ErrNotFound, httpCode: http.StatusNotFound, errObject: &errs.ErrorObject{Message: ginerrors.ErrNotFound.Error(), Type: &errType}},

{name: "errors slice", err: []error{errors.New("common err 1"), errors.New("common err 2")}, httpCode: http.StatusInternalServerError, errObject: &errs.ErrorObject{Message: "common err 1; common err 2", Type: &errType}},
{name: "map of errors", err: map[string]error{"common_err": errors.New("common err")}, httpCode: http.StatusBadRequest, errObject: &errs.ErrorObject{Message: map[string]string{"common_err": "common err"}, Type: &errType}},

{name: "record not found", err: ErrRecordNotFound, httpCode: http.StatusNotFound, errObject: &errs.ErrorObject{Message: ErrRecordNotFound.Error(), Type: &errType}},
{name: "sql error no rows", err: sql.ErrNoRows, httpCode: http.StatusNotFound, errObject: &errs.ErrorObject{Message: ErrRecordNotFound.Error(), Type: &errType}},
{name: "record not found", err: ginerrors.ErrRecordNotFound, httpCode: http.StatusNotFound, errObject: &errs.ErrorObject{Message: ginerrors.ErrRecordNotFound.Error(), Type: &errType}},
{name: "sql error no rows", err: sql.ErrNoRows, httpCode: http.StatusNotFound, errObject: &errs.ErrorObject{Message: ginerrors.ErrRecordNotFound.Error(), Type: &errType}},
{name: "sql error conn done", err: sql.ErrConnDone, httpCode: http.StatusInternalServerError, errObject: &errs.ErrorObject{Message: sql.ErrConnDone.Error(), Type: &errType}},
{name: "sql error tx done", err: sql.ErrTxDone, httpCode: http.StatusInternalServerError, errObject: &errs.ErrorObject{Message: sql.ErrTxDone.Error(), Type: &errType}},
}

t.Parallel()

for _, testCase := range cases {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
errCode, errObject := MakeResponse(testCase.err, "ru")
t.Parallel()

errCode, errObject := ginerrors.MakeResponse(testCase.err, "ru")
assert.Equal(t, testCase.errObject, errObject, testCase.name)
assert.Equal(t, testCase.httpCode, errCode, testCase.name)
})
Expand All @@ -52,23 +59,28 @@ func TestMakeResponse(t *testing.T) {
func setupRouter() *gin.Engine {
r := gin.New()

r.NoRoute(func(c *gin.Context) { Response(c, ErrNotFound) })
r.NoRoute(func(c *gin.Context) { ginerrors.Response(c, ginerrors.ErrNotFound) })
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})

return r
}

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

router := setupRouter()

t.Run("not found", func(t *testing.T) {
t.Parallel()

w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/pong", nil)
req, _ := http.NewRequestWithContext(context.Background(), "GET", "/pong", nil)
router.ServeHTTP(w, req)

assert.Equal(t, http.StatusNotFound, w.Code)
assert.Equal(t, "{\"error\":{\"message\":\"route not found\",\"type\":\"error\"}}\n", w.Body.String())
assert.Equal(t, `{"error":{"message":"route not found","type":"error"}}`, w.Body.String())
})
}

Expand All @@ -84,16 +96,16 @@ func makeValidationError() error {

s := MyStruct{String: "awesome"}

err := validate.Struct(s)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
if err := validate.Struct(s); err != nil {
return errs.Wrap("makeValidationError", "validate.Struct", err)
}

s.String = "not awesome"

return validate.Struct(s)
}

// ValidateMyVal implements validator.Func
// ValidateMyVal implements validator.Func.
func ValidateMyVal(fl validator.FieldLevel) bool {
return fl.Field().String() == "awesome"
}
14 changes: 7 additions & 7 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
module github.com/microparts/errors-go-gin

go 1.12
go 1.16

require (
github.com/gin-gonic/gin v1.6.3
github.com/microparts/errors-go v1.1.1
github.com/stretchr/testify v1.4.0
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55
google.golang.org/grpc v1.29.1
gopkg.in/go-playground/validator.v9 v9.30.0
github.com/gin-gonic/gin v1.7.2
github.com/go-playground/validator/v10 v10.8.0
github.com/spacetab-io/errors-go v1.3.0
github.com/stretchr/testify v1.7.0
google.golang.org/genproto v0.0.0-20210726200206-e7812ac95cc0
google.golang.org/grpc v1.39.0
)
Loading

0 comments on commit b24a7b2

Please sign in to comment.