Skip to content
This repository has been archived by the owner on Dec 27, 2023. It is now read-only.

Feat/find by slug #85

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion controllers/v1/rulesheets.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func (rc *rulesheets) GetRulesheets() gin.HandlerFunc {
}

// GetRulesheet godoc
// @Summary Obter Folha de Regra por ID
// @Summary Obter Folha de Regra por ID ou Slug
// @Description Para se obter a folha de regra por ID, basta clicar em **Try it out** e colocar o ID desejado em *id*. Em seguida, clique em **Execute** e caso o ID exista retornará a folha de regra com o número de ID desejado.
// @Tags Rulesheet
// @Accept json
Expand Down
92 changes: 92 additions & 0 deletions controllers/v1/rulesheets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/bancodobrasil/featws-api/dtos"
mock_services "github.com/bancodobrasil/featws-api/mocks/services"
payloads "github.com/bancodobrasil/featws-api/payloads/v1"
responses "github.com/bancodobrasil/featws-api/responses/v1"
"github.com/bancodobrasil/featws-api/services"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -374,6 +375,97 @@ func TestRulesheet_CreateRulesheet(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, w.Code)
})

t.Run("Error on validate required Name field", func(t *testing.T) {
gin.SetMode(gin.TestMode)

w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

c.Request = &http.Request{
Header: make(http.Header),
}

payload := &payloads.Rulesheet{}

bytedPayload, _ := json.Marshal(payload)

c.Request.Body = ioutil.NopCloser(bytes.NewReader(bytedPayload))

srv := new(mock_services.Rulesheets)

createdRulesheet := &dtos.Rulesheet{}

srv.On("Create", mock.Anything, createdRulesheet).Return(nil)
v1.NewRulesheets(srv).CreateRulesheet()(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
response := &responses.Error{}
json.Unmarshal(w.Body.Bytes(), response)
assert.Equal(t, "Name", response.ValidationErrors[0].Field)
assert.Equal(t, "required", response.ValidationErrors[0].Tag)
})

t.Run("Error on validate Name field does not start with digit", func(t *testing.T) {
gin.SetMode(gin.TestMode)

w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

c.Request = &http.Request{
Header: make(http.Header),
}

payload := &payloads.Rulesheet{
Name: "123Test",
}

bytedPayload, _ := json.Marshal(payload)

c.Request.Body = ioutil.NopCloser(bytes.NewReader(bytedPayload))

srv := new(mock_services.Rulesheets)

createdRulesheet := &dtos.Rulesheet{}

srv.On("Create", mock.Anything, createdRulesheet).Return(nil)
v1.NewRulesheets(srv).CreateRulesheet()(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
response := &responses.Error{}
json.Unmarshal(w.Body.Bytes(), response)
assert.Equal(t, "Name", response.ValidationErrors[0].Field)
assert.Equal(t, "doesNotStartWithDigit", response.ValidationErrors[0].Tag)
})

t.Run("Error on validate Name field must contain letter", func(t *testing.T) {
gin.SetMode(gin.TestMode)

w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

c.Request = &http.Request{
Header: make(http.Header),
}

payload := &payloads.Rulesheet{
Name: "#$%&*()",
}

bytedPayload, _ := json.Marshal(payload)

c.Request.Body = ioutil.NopCloser(bytes.NewReader(bytedPayload))

srv := new(mock_services.Rulesheets)

createdRulesheet := &dtos.Rulesheet{}

srv.On("Create", mock.Anything, createdRulesheet).Return(nil)
v1.NewRulesheets(srv).CreateRulesheet()(c)
assert.Equal(t, http.StatusBadRequest, w.Code)
response := &responses.Error{}
json.Unmarshal(w.Body.Bytes(), response)
assert.Equal(t, "Name", response.ValidationErrors[0].Field)
assert.Equal(t, "mustContainLetter", response.ValidationErrors[0].Tag)
})

// t.Run("Error on define rulesheet entity", func(t *testing.T) {
// gin.SetMode(gin.TestMode)

Expand Down
23 changes: 21 additions & 2 deletions controllers/v1/v1.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package v1

import (
"unicode"

responses "github.com/bancodobrasil/featws-api/responses/v1"
"github.com/go-playground/validator/v10"
)

var validate = validator.New()

// validatePayload validates a payload using a validator library and returns any validation errors as a
// custom error response.
func validatePayload(payload interface{}) *responses.Error {
validate := validator.New()
validate.RegisterValidation("doesNotStartWithDigit", validateDoesNotStartWithDigit)
validate.RegisterValidation("mustContainLetter", validateMustContainLetter)
if validationErr := validate.Struct(payload); validationErr != nil {
err2, ok := validationErr.(validator.ValidationErrors)

Expand All @@ -35,3 +38,19 @@ func validatePayload(payload interface{}) *responses.Error {

return nil
}

func validateDoesNotStartWithDigit(fl validator.FieldLevel) bool {
if unicode.IsDigit(rune(fl.Field().String()[0])) {
return false
}
return true
}

func validateMustContainLetter(fl validator.FieldLevel) bool {
for _, r := range fl.Field().String() {
if unicode.IsLetter(r) {
return true
}
}
return false
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ func main() {
routes.SetupRoutes(router)
configCors := cors.DefaultConfig()
configCors.AllowOrigins = strings.Split(cfg.AllowOrigins, ",")
configCors.AllowHeaders = append(configCors.AllowHeaders, "X-API-Key")
router.Use(cors.New(configCors))

// Setup API routers
Expand Down
2 changes: 1 addition & 1 deletion payloads/v1/rulesheet.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ package v1
// - Rules: a pointer to a map of string keys and interface values. This is likely where the actual rules for the rulesheet are stored. The keys in the map would likely correspond to some sort of rule identifier or name, and the values would contain the logic or conditions for.
type Rulesheet struct {
ID uint `json:"id,omitempty"`
Name string `json:"name,omitempty" validate:"required"`
Name string `json:"name,omitempty" validate:"required,doesNotStartWithDigit,mustContainLetter"`
Description string `json:"description,omitempty"`
Slug string `json:"slug,omitempty"`
Version string `json:"version,omitempty"`
Expand Down
27 changes: 23 additions & 4 deletions services/rulesheets.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package services
import (
"context"
"fmt"
"unicode"

"github.com/bancodobrasil/featws-api/dtos"
"github.com/bancodobrasil/featws-api/models"
Expand Down Expand Up @@ -152,12 +153,30 @@ func (rs rulesheets) Count(ctx context.Context, entity interface{}) (count int64
// returns it.
func (rs rulesheets) Get(ctx context.Context, id string) (result *dtos.Rulesheet, err error) {

entity, err := rs.repository.Get(ctx, id)
if err != nil {
log.Errorf("Error on fetch rulesheet(get): %v", err)
return
isSlug := true
if unicode.IsDigit(rune(id[0])) {
isSlug = false
}

var entity *models.Rulesheet

if isSlug {
findResult, err2 := rs.repository.Find(ctx, map[string]interface{}{"slug": id}, nil)
if err2 != nil {
log.Errorf("Error on fetch rulesheet(get): %v", err2)
return
}
if len(findResult) == 0 {
return nil, nil
}
entity = findResult[0]
} else {
entity, err = rs.repository.Get(ctx, id)
if err != nil {
log.Errorf("Error on fetch rulesheet(get): %v", err)
return
}
}
result = newRulesheetDTO(entity)

if result != nil {
Expand Down
24 changes: 24 additions & 0 deletions services/rulesheets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ func TestGetSucess(t *testing.T) {
}
}

// This test function tests the successful retrieval (by slug) of a rulesheet entity from a
// repository and its filling with data from a Gitlab service.
func TestGetBySlugSucess(t *testing.T) {

ctx := context.Background()
dto := &dtos.Rulesheet{
Slug: "test",
}
entity, err := models.NewRulesheetV1(*dto)
if err != nil {
t.Error("unexpected error on model creation")
}
var opts *repository.FindOptions = nil
repository := new(mocks_repository.Rulesheets)
repository.On("Find", ctx, map[string]interface{}{"slug": "test"}, opts).Return([]*models.Rulesheet{&entity}, nil)
gitlabService := new(mocks_services.Gitlab)
gitlabService.On("Fill", dto).Return(nil)
service := services.NewRulesheets(repository, gitlabService)
_, err = service.Get(ctx, "test")
if err != nil {
t.Error("unexpected error on get")
}
}

// This's a Get function of a Rulesheets service, which tests for an error on
// model creation.
func TestGetWithErrorOnCreateModel(t *testing.T) {
Expand Down
Loading