INFRA-2911 | Product service, repo and handler (#373)
* INFRA-2911 | Product entity, modal and repository * INFRA-2911 | Product service and handler * INFRA-2911 | Product service test * INFRA-2911 | Optimisations * INFRA-2911 | Optimisations
This commit is contained in:
1
Makefile
1
Makefile
@@ -62,6 +62,7 @@ generatemocks:
|
||||
cd $(CURDIR)/pkg/maverick && minimock -i IMaverickClient -s _mock.go -o $(CURDIR)/mocks
|
||||
cd $(CURDIR)/service/incident_jira && minimock -i IncidentJiraService -s _mock.go -o $(CURDIR)/mocks
|
||||
cd $(CURDIR)/model/incident_jira && minimock -i IncidentJiraRepository -s _mock.go -o $(CURDIR)/mocks
|
||||
cd $(CURDIR)/model/product && minimock -i ProductRepository -s _mock.go -o $(CURDIR)/mocks
|
||||
cd $(CURDIR)/service/google && minimock -i IDriveService -s _mock.go -o $(CURDIR)/mocks
|
||||
cd $(CURDIR)/service/rca && minimock -i IRcaService -s _mock.go -o $(CURDIR)/mocks
|
||||
cd $(CURDIR)/pkg/alertClient && minimock -i AlertClient -s _mock.go -o $(CURDIR)/mocks
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"gorm.io/gorm"
|
||||
"houston/model/incident"
|
||||
"houston/model/log"
|
||||
productModel "houston/model/product"
|
||||
"houston/model/severity"
|
||||
"houston/model/tag"
|
||||
"houston/model/team"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
"houston/service/documentService"
|
||||
"houston/service/google"
|
||||
incidentService "houston/service/incident/impl"
|
||||
"houston/service/products"
|
||||
rcaService "houston/service/rca/impl"
|
||||
"houston/service/slack"
|
||||
tagService "houston/service/tag"
|
||||
@@ -45,6 +47,7 @@ type houstonServices struct {
|
||||
driveService google.IDriveService
|
||||
calendarService *conference.CalendarService
|
||||
tagService *tagService.TagService
|
||||
productsService products.ProductService
|
||||
}
|
||||
|
||||
var appContext *applicationContext
|
||||
@@ -76,6 +79,7 @@ func InitializeServices() {
|
||||
driveService: initDriveService(),
|
||||
calendarService: initCalendarService(),
|
||||
tagService: initTagService(),
|
||||
productsService: initProductsService(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +160,14 @@ func GetTagService() *tagService.TagService {
|
||||
return services.tagService
|
||||
}
|
||||
|
||||
func initProductsService() products.ProductService {
|
||||
return products.NewProductService(productModel.NewProductRepo(GetDB()))
|
||||
}
|
||||
|
||||
func GetProductsService() products.ProductService {
|
||||
return services.productsService
|
||||
}
|
||||
|
||||
func GetCalendarService() *conference.CalendarService {
|
||||
return services.calendarService
|
||||
}
|
||||
|
||||
153
cmd/app/handler/product_handler.go
Normal file
153
cmd/app/handler/product_handler.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"houston/appcontext"
|
||||
stringUtil "houston/common/util/string"
|
||||
"houston/logger"
|
||||
productModel "houston/model/product"
|
||||
"houston/service/products"
|
||||
productRequest "houston/service/request/product"
|
||||
common "houston/service/response/common"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
productHandlerLogTag = "[product_handler]"
|
||||
)
|
||||
|
||||
type ProductHandler struct {
|
||||
gin *gin.Engine
|
||||
service products.ProductService
|
||||
}
|
||||
|
||||
func NewProductHandler(
|
||||
gin *gin.Engine,
|
||||
) *ProductHandler {
|
||||
return &ProductHandler{
|
||||
gin: gin,
|
||||
service: appcontext.GetProductsService(),
|
||||
}
|
||||
}
|
||||
|
||||
func (handler *ProductHandler) HandleCreateProduct(c *gin.Context) {
|
||||
var createProductRequest productRequest.CreateOrUpdatedProductRequest
|
||||
if err := c.ShouldBindJSON(&createProductRequest); err != nil {
|
||||
c.JSON(
|
||||
http.StatusInternalServerError,
|
||||
common.ErrorResponse(
|
||||
errors.New("failed to process the request"), http.StatusInternalServerError, nil,
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if err := validateCreateOrProductRequest(createProductRequest); err != nil {
|
||||
logger.Error(fmt.Sprintf("%s received invalid request to create new product. %+v", productHandlerLogTag, err))
|
||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||
return
|
||||
}
|
||||
createdProductIds, err := handler.service.CreateProduct(createProductRequest.ProductName)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("%s failed to create product. %+v", productHandlerLogTag, err))
|
||||
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusInternalServerError, nil))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(createdProductIds, http.StatusOK))
|
||||
}
|
||||
|
||||
func (handler *ProductHandler) HandleGetAllProducts(c *gin.Context) {
|
||||
productDTOs, err := handler.service.GetAllProducts()
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("%s failed to get all products. %+v", productHandlerLogTag, err))
|
||||
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusInternalServerError, nil))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(productDTOs, http.StatusOK))
|
||||
}
|
||||
|
||||
func (handler *ProductHandler) HandleGetProductByID(c *gin.Context) {
|
||||
productId, err := getProductIdFromPath(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||
return
|
||||
}
|
||||
productDTO, err := handler.service.GetProductByID(productId)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("%s failed to get product by ID. %+v", productHandlerLogTag, err))
|
||||
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusInternalServerError, nil))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(productDTO, http.StatusOK))
|
||||
}
|
||||
|
||||
func (handler *ProductHandler) HandleUpdateProduct(c *gin.Context) {
|
||||
var updateProductRequest productRequest.CreateOrUpdatedProductRequest
|
||||
if err := c.ShouldBindJSON(&updateProductRequest); err != nil {
|
||||
c.JSON(
|
||||
http.StatusInternalServerError,
|
||||
common.ErrorResponse(
|
||||
errors.New("failed to process the request"), http.StatusInternalServerError, nil,
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if err := validateCreateOrProductRequest(updateProductRequest); err != nil {
|
||||
logger.Error(fmt.Sprintf("%s received invalid request to update product. %+v", productHandlerLogTag, err))
|
||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||
return
|
||||
}
|
||||
|
||||
productId, err := getProductIdFromPath(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||
return
|
||||
}
|
||||
productDTO := &productModel.ProductDTO{
|
||||
ProductID: productId,
|
||||
ProductName: updateProductRequest.ProductName,
|
||||
}
|
||||
err = handler.service.UpdateProduct(productDTO)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("%s failed to update product. %+v", productHandlerLogTag, err))
|
||||
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusInternalServerError, nil))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(nil, http.StatusOK))
|
||||
}
|
||||
|
||||
func (handler *ProductHandler) HandleDeleteProductByID(c *gin.Context) {
|
||||
productId, err := getProductIdFromPath(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, common.ErrorResponse(err, http.StatusBadRequest, nil))
|
||||
return
|
||||
}
|
||||
err = handler.service.DeleteProductByID(productId)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("%s failed to delete product. %+v", productHandlerLogTag, err))
|
||||
c.JSON(http.StatusInternalServerError, common.ErrorResponse(err, http.StatusInternalServerError, nil))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, common.SuccessResponse(nil, http.StatusOK))
|
||||
}
|
||||
|
||||
func validateCreateOrProductRequest(request productRequest.CreateOrUpdatedProductRequest) error {
|
||||
if strings.TrimSpace(request.ProductName) == "" {
|
||||
return errors.New("product name can not be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getProductIdFromPath(c *gin.Context) (uint, error) {
|
||||
productIdString := c.Param("id")
|
||||
productId, err := stringUtil.StringToUint(productIdString)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("%s failed to convert product id to uint. %+v", productHandlerLogTag, err))
|
||||
return 0, fmt.Errorf("%s is not a valid product ID", productIdString)
|
||||
}
|
||||
return productId, nil
|
||||
}
|
||||
@@ -55,6 +55,7 @@ func (s *Server) Handler(houstonGroup *gin.RouterGroup) {
|
||||
s.rcaHandler(houstonGroup)
|
||||
s.gin.Use(s.createMiddleware())
|
||||
s.incidentClientHandlerV2(houstonGroup)
|
||||
s.productsHandler(houstonGroup)
|
||||
s.teamHandler(houstonGroup)
|
||||
s.severityHandler(houstonGroup)
|
||||
s.incidentHandler(houstonGroup)
|
||||
@@ -142,6 +143,16 @@ func (s *Server) incidentClientHandler(houstonGroup *gin.RouterGroup) {
|
||||
houstonGroup.POST("/create-incident", incidentHandler.CreateIncident)
|
||||
}
|
||||
|
||||
func (s *Server) productsHandler(houstonGroup *gin.RouterGroup) {
|
||||
productsHandler := handler.NewProductHandler(s.gin)
|
||||
|
||||
houstonGroup.POST("/products", s.authService.IfAdmin(productsHandler.HandleCreateProduct))
|
||||
houstonGroup.PUT("/product/:id", s.authService.IfAdmin(productsHandler.HandleUpdateProduct))
|
||||
houstonGroup.DELETE("/product/:id", s.authService.IfAdmin(productsHandler.HandleDeleteProductByID))
|
||||
houstonGroup.GET("/products", productsHandler.HandleGetAllProducts)
|
||||
houstonGroup.GET("/product/:id", productsHandler.HandleGetProductByID)
|
||||
}
|
||||
|
||||
func (s *Server) incidentClientHandlerV2(houstonGroup *gin.RouterGroup) {
|
||||
houstonGroup.Use(func(c *gin.Context) {
|
||||
// Add your desired header key-value pair
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package string
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IsBlank(input string) bool {
|
||||
trimmedInput := strings.TrimSpace(input)
|
||||
@@ -19,3 +23,11 @@ func ExtractCommaSeparatedTrimmedArrayFromString(jiraText string) []string {
|
||||
|
||||
return stringArray
|
||||
}
|
||||
|
||||
func StringToUint(input string) (uint, error) {
|
||||
u64, err := strconv.ParseUint(input, 10, 32)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to convert string to uint: %s", err)
|
||||
}
|
||||
return uint(u64), nil
|
||||
}
|
||||
|
||||
15
db/migration/000014_product_table.up.sql
Normal file
15
db/migration/000014_product_table.up.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Table Definition ----------------------------------------------
|
||||
|
||||
CREATE TABLE product
|
||||
(
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name text NOT NULL UNIQUE,
|
||||
created_at timestamp with time zone,
|
||||
updated_at timestamp with time zone
|
||||
);
|
||||
|
||||
-- Indices -------------------------------------------------------
|
||||
|
||||
CREATE UNIQUE INDEX product_pkey ON product (id int8_ops);
|
||||
CREATE UNIQUE INDEX product_name_key ON product (name text_ops);
|
||||
CREATE INDEX idx_product_name ON product (name text_ops);
|
||||
10
go.mod
10
go.mod
@@ -7,8 +7,6 @@ require (
|
||||
github.com/aws/aws-sdk-go v1.44.262
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.25
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1
|
||||
github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9
|
||||
github.com/chromedp/chromedp v0.9.1
|
||||
github.com/gin-contrib/zap v0.1.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/gojuno/minimock/v3 v3.1.3
|
||||
@@ -51,20 +49,14 @@ require (
|
||||
github.com/aws/smithy-go v1.13.5 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
@@ -85,7 +77,7 @@ require (
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
|
||||
16
model/product/entity.go
Normal file
16
model/product/entity.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProductEntity struct {
|
||||
ID uint `gorm:"primarykey;column:id;autoIncrement"`
|
||||
Name string `gorm:"column:name;not null;unique;index"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;default:null"`
|
||||
}
|
||||
|
||||
func (ProductEntity) TableName() string {
|
||||
return "product"
|
||||
}
|
||||
6
model/product/model.go
Normal file
6
model/product/model.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package product
|
||||
|
||||
type ProductDTO struct {
|
||||
ProductID uint `json:"product_id"`
|
||||
ProductName string `json:"product_name"`
|
||||
}
|
||||
19
model/product/product_repository.go
Normal file
19
model/product/product_repository.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ProductRepository interface {
|
||||
InsertProduct(productName string) (uint, error)
|
||||
UpdateProduct(productEntity *ProductEntity) error
|
||||
GetAllProducts() ([]ProductEntity, error)
|
||||
GetProductById(productID uint) (*ProductEntity, error)
|
||||
GetProductByName(productName string) (*ProductEntity, error)
|
||||
DeleteProductByID(productID uint) error
|
||||
DeleteProductByName(productName string) error
|
||||
}
|
||||
|
||||
func NewProductRepo(db *gorm.DB) ProductRepository {
|
||||
return &productRepositoryImpl{db: db}
|
||||
}
|
||||
85
model/product/product_repository_impl.go
Normal file
85
model/product/product_repository_impl.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type productRepositoryImpl struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (repo *productRepositoryImpl) InsertProduct(productName string) (uint, error) {
|
||||
var record = ProductEntity{
|
||||
Name: productName,
|
||||
}
|
||||
|
||||
result := repo.db.Create(&record)
|
||||
if result.Error != nil {
|
||||
return 0, result.Error
|
||||
}
|
||||
|
||||
return record.ID, nil
|
||||
}
|
||||
|
||||
func (repo *productRepositoryImpl) UpdateProduct(productEntity *ProductEntity) error {
|
||||
result := repo.db.Save(productEntity)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *productRepositoryImpl) GetAllProducts() ([]ProductEntity, error) {
|
||||
var entities []ProductEntity
|
||||
|
||||
result := repo.db.Find(&entities)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
|
||||
if result.RowsAffected == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return entities, nil
|
||||
}
|
||||
|
||||
func (repo *productRepositoryImpl) GetProductById(productID uint) (*ProductEntity, error) {
|
||||
var entity ProductEntity
|
||||
result := repo.db.First(&entity, "id = ?", productID)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
func (repo *productRepositoryImpl) GetProductByName(productName string) (*ProductEntity, error) {
|
||||
var entity ProductEntity
|
||||
result := repo.db.First(&entity, "name = ?", productName)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &entity, nil
|
||||
}
|
||||
|
||||
func (repo *productRepositoryImpl) DeleteProductByID(productID uint) error {
|
||||
result := repo.db.Delete(&ProductEntity{}, "id = ?", productID)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (repo *productRepositoryImpl) DeleteProductByName(productName string) error {
|
||||
result := repo.db.Delete(&ProductEntity{}, "name = ?", productName)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
19
service/products/product_service.go
Normal file
19
service/products/product_service.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package products
|
||||
|
||||
import (
|
||||
productModel "houston/model/product"
|
||||
)
|
||||
|
||||
type ProductService interface {
|
||||
CreateProduct(productName string) (uint, error)
|
||||
UpdateProduct(productDTO *productModel.ProductDTO) error
|
||||
GetAllProducts() ([]productModel.ProductDTO, error)
|
||||
GetProductByID(productID uint) (*productModel.ProductDTO, error)
|
||||
GetProductByName(productName string) (*productModel.ProductDTO, error)
|
||||
DeleteProductByID(productID uint) error
|
||||
DeleteProductByName(productName string) error
|
||||
}
|
||||
|
||||
func NewProductService(repo productModel.ProductRepository) ProductService {
|
||||
return &productServiceImpl{repo}
|
||||
}
|
||||
71
service/products/product_service_impl.go
Normal file
71
service/products/product_service_impl.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package products
|
||||
|
||||
import (
|
||||
"errors"
|
||||
productModel "houston/model/product"
|
||||
)
|
||||
|
||||
type productServiceImpl struct {
|
||||
repo productModel.ProductRepository
|
||||
}
|
||||
|
||||
func (service *productServiceImpl) CreateProduct(productName string) (uint, error) {
|
||||
existingProducts, err := service.repo.GetProductByName(productName)
|
||||
if err != nil {
|
||||
return 0, errors.New("error while processing the request")
|
||||
}
|
||||
if existingProducts != nil {
|
||||
return 0, errors.New("product already exists")
|
||||
}
|
||||
return service.repo.InsertProduct(productName)
|
||||
}
|
||||
|
||||
func (service *productServiceImpl) UpdateProduct(productDTO *productModel.ProductDTO) error {
|
||||
entity, err := service.repo.GetProductById(productDTO.ProductID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entity.Name = productDTO.ProductName
|
||||
return service.repo.UpdateProduct(entity)
|
||||
}
|
||||
|
||||
func (service *productServiceImpl) GetAllProducts() ([]productModel.ProductDTO, error) {
|
||||
productEntities, err := service.repo.GetAllProducts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var productDTOs []productModel.ProductDTO
|
||||
for _, entity := range productEntities {
|
||||
productDTOs = append(productDTOs, productModel.ProductDTO{
|
||||
ProductID: entity.ID,
|
||||
ProductName: entity.Name,
|
||||
})
|
||||
}
|
||||
return productDTOs, nil
|
||||
}
|
||||
func (service *productServiceImpl) GetProductByID(productID uint) (*productModel.ProductDTO, error) {
|
||||
productEntity, err := service.repo.GetProductById(productID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &productModel.ProductDTO{
|
||||
ProductID: productEntity.ID,
|
||||
ProductName: productEntity.Name,
|
||||
}, nil
|
||||
}
|
||||
func (service *productServiceImpl) GetProductByName(productName string) (*productModel.ProductDTO, error) {
|
||||
productEntity, err := service.repo.GetProductByName(productName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &productModel.ProductDTO{
|
||||
ProductID: productEntity.ID,
|
||||
ProductName: productEntity.Name,
|
||||
}, nil
|
||||
}
|
||||
func (service *productServiceImpl) DeleteProductByID(productID uint) error {
|
||||
return service.repo.DeleteProductByID(productID)
|
||||
}
|
||||
func (service *productServiceImpl) DeleteProductByName(productName string) error {
|
||||
return service.repo.DeleteProductByName(productName)
|
||||
}
|
||||
115
service/products/product_service_test.go
Normal file
115
service/products/product_service_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package products
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gojuno/minimock/v3"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"houston/logger"
|
||||
"houston/mocks"
|
||||
repo "houston/model/product"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type ProductServiceSuite struct {
|
||||
suite.Suite
|
||||
controller *minimock.Controller
|
||||
repoMock *mocks.ProductRepositoryMock
|
||||
service ProductService
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) SetupTest() {
|
||||
logger.InitLogger()
|
||||
viper.Set("jira.link.max.length", 50)
|
||||
suite.controller = minimock.NewController(suite.T())
|
||||
suite.T().Cleanup(suite.controller.Finish)
|
||||
suite.repoMock = mocks.NewProductRepositoryMock(suite.controller)
|
||||
suite.service = NewProductService(suite.repoMock)
|
||||
}
|
||||
|
||||
func TestProductService(t *testing.T) {
|
||||
suite.Run(t, new(ProductServiceSuite))
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_CreateProduct() {
|
||||
suite.repoMock.GetProductByNameMock.Return(nil, nil)
|
||||
suite.repoMock.InsertProductMock.When("test").Then(1, nil)
|
||||
|
||||
_, err := suite.service.CreateProduct("test")
|
||||
if err != nil {
|
||||
suite.Fail("Create Product Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_UpdateProduct() {
|
||||
suite.repoMock.GetProductByIdMock.When(uint(1)).Then(&repo.ProductEntity{}, nil)
|
||||
suite.repoMock.UpdateProductMock.Return(nil)
|
||||
|
||||
err := suite.service.UpdateProduct(&repo.ProductDTO{ProductID: 1, ProductName: "test"})
|
||||
if err != nil {
|
||||
suite.Fail("Update Product Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_UpdateProductWithInvalidID() {
|
||||
suite.repoMock.GetProductByIdMock.When(uint(1)).Then(nil, errors.New("invalid ID"))
|
||||
|
||||
err := suite.service.UpdateProduct(&repo.ProductDTO{ProductID: 1, ProductName: "test"})
|
||||
if err == nil {
|
||||
suite.Fail("Update Product with invalid ID Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_GetAllProducts() {
|
||||
suite.repoMock.GetAllProductsMock.Return(&[]repo.ProductEntity{}, nil)
|
||||
|
||||
_, err := suite.service.GetAllProducts()
|
||||
if err != nil {
|
||||
suite.Fail("Get All Products Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_GetProductByID() {
|
||||
suite.repoMock.GetProductByIdMock.When(uint(1)).Then(&repo.ProductEntity{}, nil)
|
||||
|
||||
_, err := suite.service.GetProductByID(1)
|
||||
if err != nil {
|
||||
suite.Fail("Get Product By ID Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_DeleteProductByID() {
|
||||
suite.repoMock.DeleteProductByIDMock.When(uint(1)).Then(nil)
|
||||
|
||||
err := suite.service.DeleteProductByID(1)
|
||||
if err != nil {
|
||||
suite.Fail("Delete Product By ID Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_DeleteProductByName() {
|
||||
suite.repoMock.DeleteProductByNameMock.When("test").Then(nil)
|
||||
|
||||
err := suite.service.DeleteProductByName("test")
|
||||
if err != nil {
|
||||
suite.Fail("Delete Product By Name Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_GetProductByName() {
|
||||
suite.repoMock.GetProductByNameMock.When("test").Then(&repo.ProductEntity{}, nil)
|
||||
|
||||
_, err := suite.service.GetProductByName("test")
|
||||
if err != nil {
|
||||
suite.Fail("Get Product By Name Failed", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ProductServiceSuite) TestProductServiceImpl_CreateProduct_ExistingProduct() {
|
||||
suite.repoMock.GetProductByNameMock.Return(&repo.ProductEntity{ID: 1, Name: "test"}, nil)
|
||||
|
||||
_, err := suite.service.CreateProduct("test")
|
||||
if err == nil {
|
||||
suite.Fail("Create Product Failed", err)
|
||||
}
|
||||
}
|
||||
5
service/request/product/create_and_update_product.go
Normal file
5
service/request/product/create_and_update_product.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package product
|
||||
|
||||
type CreateOrUpdatedProductRequest struct {
|
||||
ProductName string `json:"productName"`
|
||||
}
|
||||
Reference in New Issue
Block a user