[hw-2] add tests, coverage, benchmarks

This commit is contained in:
Никита Шубин
2025-05-31 10:47:47 +00:00
parent 1a3d4892a8
commit a0e36639ca
22 changed files with 3058 additions and 48 deletions

View File

@@ -0,0 +1,193 @@
//go:build integration
// +build integration
package integration
import (
"context"
"encoding/json"
"fmt"
"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"
"route256/cart/internal/app"
"route256/cart/internal/domain/cart/repository"
cartService "route256/cart/internal/domain/cart/service"
"route256/cart/internal/domain/entity"
"route256/cart/internal/domain/model"
productsService "route256/cart/internal/domain/products/service"
)
const (
productServiceImage = "gitlab-registry.ozon.dev/go/classroom-18/students/base/products:latest"
testToken = "testToken"
testSku = 1076963
testName = "Теория нравственных чувств | Смит Адам"
testUID = entity.UID(1337)
)
type CartHandlerSuite struct {
suite.Suite
psContainer testcontainers.Container
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("init cart-service", func(sCtx provider.StepCtx) {
prodClient := productsService.NewProductService(
*http.DefaultClient,
testToken,
productURL,
)
repo := repository.NewInMemoryRepository(10)
s.cartSvc = cartService.NewCartService(repo, prodClient)
appSrv := &app.App{}
s.server = httptest.NewServer(appSrv.BootstrapHandlers(s.cartSvc))
})
}
func (s *CartHandlerSuite) AfterAll(t provider.T) {
_ = s.psContainer.Terminate(context.Background())
s.server.Close()
}
// 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")
})
}