mirror of
https://github.com/3ybactuk/marketplace-go-service-project.git
synced 2025-10-30 05:53:45 +03:00
239 lines
6.7 KiB
Go
239 lines
6.7 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package integration
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ozontech/allure-go/pkg/framework/provider"
|
|
"github.com/ozontech/allure-go/pkg/framework/suite"
|
|
"github.com/testcontainers/testcontainers-go"
|
|
"github.com/testcontainers/testcontainers-go/wait"
|
|
"go.uber.org/goleak"
|
|
"google.golang.org/grpc"
|
|
|
|
"route256/cart/internal/app"
|
|
lomsService "route256/cart/internal/clients/loms"
|
|
productsService "route256/cart/internal/clients/products"
|
|
"route256/cart/internal/domain/entity"
|
|
"route256/cart/internal/domain/model"
|
|
"route256/cart/internal/domain/repository"
|
|
cartService "route256/cart/internal/domain/service"
|
|
|
|
pbLoms "route256/pkg/api/loms/v1"
|
|
)
|
|
|
|
const (
|
|
productServiceImage = "gitlab-registry.ozon.dev/go/classroom-18/students/base/products:latest"
|
|
testToken = "testToken"
|
|
|
|
testSku = 1076963
|
|
testName = "Теория нравственных чувств | Смит Адам"
|
|
testUID = entity.UID(1337)
|
|
)
|
|
|
|
type lomsServerMock struct {
|
|
pbLoms.UnimplementedLOMSServer
|
|
}
|
|
|
|
func (lomsServerMock) OrderCreate(_ context.Context, _ *pbLoms.OrderCreateRequest) (*pbLoms.OrderCreateResponse, error) {
|
|
return &pbLoms.OrderCreateResponse{OrderId: 1}, nil
|
|
}
|
|
|
|
func (lomsServerMock) StocksInfo(_ context.Context, _ *pbLoms.StocksInfoRequest) (*pbLoms.StocksInfoResponse, error) {
|
|
return &pbLoms.StocksInfoResponse{Count: 1000}, nil
|
|
}
|
|
|
|
type CartHandlerSuite struct {
|
|
suite.Suite
|
|
|
|
psContainer testcontainers.Container
|
|
|
|
lomsSrv *grpc.Server
|
|
lomsConn *grpc.ClientConn
|
|
|
|
server *httptest.Server
|
|
cartSvc *cartService.CartService
|
|
}
|
|
|
|
func TestCartHandlerSuite(t *testing.T) {
|
|
defer goleak.VerifyNone(t)
|
|
|
|
suite.RunSuite(t, new(CartHandlerSuite))
|
|
}
|
|
|
|
func (s *CartHandlerSuite) BeforeAll(t provider.T) {
|
|
ctx := context.Background()
|
|
|
|
t.WithNewStep("start product-service container", func(sCtx provider.StepCtx) {
|
|
req := testcontainers.ContainerRequest{
|
|
Image: productServiceImage,
|
|
ExposedPorts: []string{"8082/tcp"},
|
|
WaitingFor: wait.ForHTTP("/docs").WithStartupTimeout(10 * time.Second),
|
|
}
|
|
container, err := testcontainers.GenericContainer(ctx,
|
|
testcontainers.GenericContainerRequest{
|
|
ContainerRequest: req,
|
|
Started: true,
|
|
})
|
|
sCtx.Require().NoError(err, "create container")
|
|
s.psContainer = container
|
|
})
|
|
|
|
var productURL string
|
|
t.WithNewStep("discover product-service URL", func(sCtx provider.StepCtx) {
|
|
endpoint, err := s.psContainer.Endpoint(ctx, "")
|
|
sCtx.Require().NoError(err)
|
|
productURL = endpoint
|
|
})
|
|
|
|
t.WithNewStep("start loms grpc server", func(st provider.StepCtx) {
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
|
st.Require().NoError(err)
|
|
|
|
s.lomsSrv = grpc.NewServer()
|
|
pbLoms.RegisterLOMSServer(s.lomsSrv, &lomsServerMock{})
|
|
|
|
go s.lomsSrv.Serve(lis)
|
|
|
|
conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure(), grpc.WithBlock())
|
|
st.Require().NoError(err)
|
|
s.lomsConn = conn
|
|
})
|
|
|
|
t.WithNewStep("init cart-service", func(sCtx provider.StepCtx) {
|
|
prodClient := productsService.NewProductService(
|
|
*http.DefaultClient,
|
|
testToken,
|
|
productURL,
|
|
10,
|
|
10,
|
|
10,
|
|
)
|
|
|
|
lomsClient := pbLoms.NewLOMSClient(s.lomsConn)
|
|
|
|
repo := repository.NewInMemoryRepository(10)
|
|
s.cartSvc = cartService.NewCartService(repo, prodClient, lomsService.NewLomsService(lomsClient))
|
|
|
|
appSrv := &app.App{}
|
|
|
|
s.server = httptest.NewServer(appSrv.BootstrapHandlers(s.cartSvc))
|
|
})
|
|
}
|
|
|
|
func (s *CartHandlerSuite) AfterAll(t provider.T) {
|
|
s.server.Close()
|
|
s.lomsSrv.Stop()
|
|
s.lomsConn.Close()
|
|
|
|
_ = s.psContainer.Terminate(context.Background())
|
|
}
|
|
|
|
// DELETE /user/<user_id>/cart/<sku_id>
|
|
func (s *CartHandlerSuite) TestDeleteItemPositive(t provider.T) {
|
|
ctx := context.Background()
|
|
|
|
item := &model.Item{
|
|
Product: &model.Product{
|
|
Sku: testSku,
|
|
},
|
|
Count: 1,
|
|
}
|
|
|
|
t.WithNewStep("fill cart in usecase", func(sCtx provider.StepCtx) {
|
|
err := s.cartSvc.AddItem(context.Background(),
|
|
testUID, item)
|
|
sCtx.Require().NoError(err)
|
|
|
|
cart, err := s.cartSvc.GetItemsByUserID(ctx, testUID)
|
|
sCtx.Require().NoError(err)
|
|
|
|
sCtx.Require().Len(cart.Items, 1, "check cart contains product")
|
|
sCtx.Require().Equal(testUID, cart.UserID, "check user ID equals")
|
|
sCtx.Require().Equal(item.Product.Sku, cart.Items[0].Product.Sku, "check product sku equals")
|
|
})
|
|
|
|
t.WithNewStep("call DELETE handler", func(sCtx provider.StepCtx) {
|
|
url := fmt.Sprintf("%s/user/%d/cart/%d", s.server.URL, testUID, testSku)
|
|
|
|
req, err := http.NewRequest(http.MethodDelete, url, nil)
|
|
sCtx.Require().NoError(err)
|
|
|
|
resp, err := s.server.Client().Do(req)
|
|
sCtx.Require().NoError(err)
|
|
defer resp.Body.Close()
|
|
|
|
sCtx.Require().Equal(http.StatusNoContent, resp.StatusCode, "delete handler unexpected status code")
|
|
})
|
|
|
|
t.WithNewStep("check cart empty in usecase", func(sCtx provider.StepCtx) {
|
|
_, err := s.cartSvc.GetItemsByUserID(ctx, testUID)
|
|
sCtx.Require().Error(err)
|
|
})
|
|
}
|
|
|
|
// GET /user/<user_id>/cart
|
|
func (s *CartHandlerSuite) TestGetCartPositive(t provider.T) {
|
|
ctx := context.Background()
|
|
|
|
item := &model.Item{
|
|
Product: &model.Product{
|
|
Sku: testSku,
|
|
},
|
|
Count: 2,
|
|
}
|
|
|
|
t.WithNewStep("fill cart in usecase", func(sCtx provider.StepCtx) {
|
|
err := s.cartSvc.AddItem(context.Background(),
|
|
testUID, item)
|
|
sCtx.Require().NoError(err)
|
|
|
|
cart, err := s.cartSvc.GetItemsByUserID(ctx, testUID)
|
|
sCtx.Require().NoError(err)
|
|
|
|
sCtx.Require().Len(cart.Items, 1, "check cart contains product")
|
|
sCtx.Require().Equal(testUID, cart.UserID, "check user ID equals")
|
|
sCtx.Require().Equal(item.Product.Sku, cart.Items[0].Product.Sku, "check product sku equals")
|
|
sCtx.Require().Equal(item.Count, cart.Items[0].Count, "check product count")
|
|
})
|
|
|
|
t.WithNewStep("call GET handler", func(sCtx provider.StepCtx) {
|
|
url := fmt.Sprintf("%s/user/%d/cart", s.server.URL, testUID)
|
|
|
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
|
sCtx.Require().NoError(err)
|
|
|
|
resp, err := s.server.Client().Do(req)
|
|
sCtx.Require().NoError(err)
|
|
defer resp.Body.Close()
|
|
|
|
sCtx.Require().Equal(http.StatusOK, resp.StatusCode, "check GET status code")
|
|
sCtx.Require().Equal("application/json", resp.Header.Get("Content-Type"), "check GET content type")
|
|
|
|
var body struct {
|
|
Items []struct {
|
|
Sku int64 `json:"sku"`
|
|
Name string `json:"name"`
|
|
Count uint32 `json:"count"`
|
|
Price uint32 `json:"price"`
|
|
} `json:"items"`
|
|
TotalPrice uint32 `json:"total_price"`
|
|
}
|
|
sCtx.Require().NoError(json.NewDecoder(resp.Body).Decode(&body))
|
|
|
|
sCtx.Require().Len(body.Items, 1, "check items len")
|
|
sCtx.Require().Equal(int64(testSku), body.Items[0].Sku, "check sku")
|
|
sCtx.Require().Equal(uint32(2), body.Items[0].Count, "check item count")
|
|
sCtx.Require().Greater(body.TotalPrice, uint32(0), "check price")
|
|
})
|
|
}
|