Files
3ybactuk-marketplace-go-ser…/cart/tests/integration/cart_integration_test.go
Никита Шубин 77ed9fcf85 [hw-4] add postgres db
2025-06-26 12:08:46 +00:00

233 lines
6.6 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"
"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) {
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,
)
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")
})
}