mirror of
https://github.com/3ybactuk/marketplace-go-service-project.git
synced 2025-10-29 13:33:45 +03:00
[hw-8] add: integration tests
This commit is contained in:
5
Makefile
5
Makefile
@@ -24,8 +24,9 @@ run-all:
|
||||
|
||||
.PHONY: .integration-test
|
||||
integration-test:
|
||||
ALLURE_OUTPUT_PATH=$(shell pwd)/allure-results ALLURE_OUTPUT_FOLDER=cart go test -v -tags=$(INTEGRATION_TAG) ./cart/tests/integration
|
||||
CGO_ENABLED=0 ALLURE_OUTPUT_PATH=$(shell pwd)/allure-results ALLURE_OUTPUT_FOLDER=loms go test -v -tags=$(INTEGRATION_TAG) ./loms/tests/integration
|
||||
# ALLURE_OUTPUT_PATH=$(shell pwd)/allure-results ALLURE_OUTPUT_FOLDER=cart go test -v -tags=$(INTEGRATION_TAG) ./cart/tests/integration
|
||||
# CGO_ENABLED=0 ALLURE_OUTPUT_PATH=$(shell pwd)/allure-results ALLURE_OUTPUT_FOLDER=loms go test -v -tags=$(INTEGRATION_TAG) ./loms/tests/integration
|
||||
CGO_ENABLED=0 ALLURE_OUTPUT_PATH=$(shell pwd)/allure-results ALLURE_OUTPUT_FOLDER=comments go test -v -tags=$(INTEGRATION_TAG) ./comments/tests/integration
|
||||
|
||||
bench:
|
||||
go test -bench=BenchmarkInMemoryRepository -benchmem ./cart/internal/domain/cart/repository -benchtime 3s
|
||||
|
||||
@@ -77,8 +77,6 @@ func (r *commentsRepo) InsertComment(ctx context.Context, comment *entity.Commen
|
||||
|
||||
r.idMx.Lock()
|
||||
id := r.curID*1000 + shardID
|
||||
r.curID++
|
||||
r.idMx.Unlock()
|
||||
|
||||
req := &InsertCommentParams{
|
||||
UserID: comment.UserID,
|
||||
@@ -92,6 +90,9 @@ func (r *commentsRepo) InsertComment(ctx context.Context, comment *entity.Commen
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.curID++
|
||||
r.idMx.Unlock()
|
||||
|
||||
return mapComment(c), nil
|
||||
}
|
||||
|
||||
@@ -125,12 +126,17 @@ func (r *commentsRepo) ListCommentsByUser(ctx context.Context, userID int64) ([]
|
||||
return nil, err2
|
||||
}
|
||||
|
||||
alreadyMerged := make(map[int64]struct{}, len(l1)+len(l2))
|
||||
merged := make([]*entity.Comment, 0, len(l1)+len(l2))
|
||||
for _, com := range l1 {
|
||||
merged = append(merged, mapComment(com))
|
||||
alreadyMerged[com.Sku] = struct{}{}
|
||||
}
|
||||
for _, com := range l2 {
|
||||
merged = append(merged, mapComment(com))
|
||||
if _, ok := alreadyMerged[com.Sku]; !ok {
|
||||
merged = append(merged, mapComment(com))
|
||||
alreadyMerged[com.Sku] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
return merged, nil
|
||||
|
||||
230
comments/tests/integration/comments_integration_test.go
Normal file
230
comments/tests/integration/comments_integration_test.go
Normal file
@@ -0,0 +1,230 @@
|
||||
//go:build integration
|
||||
// +build integration
|
||||
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
_ "github.com/jackc/pgx/v5/stdlib"
|
||||
"github.com/ozontech/allure-go/pkg/framework/provider"
|
||||
"github.com/ozontech/allure-go/pkg/framework/suite"
|
||||
"github.com/pressly/goose/v3"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
"github.com/testcontainers/testcontainers-go/wait"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
repo "route256/comments/infra/repository/sqlc"
|
||||
"route256/comments/internal/app/server"
|
||||
"route256/comments/internal/domain/service"
|
||||
pb "route256/pkg/api/comments/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
migrationsDir = "../../db/migrations"
|
||||
)
|
||||
|
||||
func startPostgres(ctx context.Context, migrationsDir string) (*pgxpool.Pool, func(), error) {
|
||||
req := testcontainers.ContainerRequest{
|
||||
Image: "gitlab-registry.ozon.dev/go/classroom-18/students/base/postgres:16",
|
||||
Env: map[string]string{
|
||||
"POSTGRESQL_USERNAME": "user",
|
||||
"POSTGRESQL_PASSWORD": "postgres",
|
||||
"POSTGRESQL_DATABASE": "comments_test",
|
||||
},
|
||||
ExposedPorts: []string{"5432/tcp"},
|
||||
WaitingFor: wait.ForListeningPort("5432/tcp").WithStartupTimeout(30 * time.Second),
|
||||
}
|
||||
container, err := testcontainers.GenericContainer(ctx,
|
||||
testcontainers.GenericContainerRequest{ContainerRequest: req, Started: true})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
endpoint, err := container.PortEndpoint(ctx, "5432", "")
|
||||
if err != nil {
|
||||
container.Terminate(ctx)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dsn := fmt.Sprintf("postgresql://user:postgres@%s/comments_test?sslmode=disable", endpoint)
|
||||
|
||||
var pool *pgxpool.Pool
|
||||
for i := 0; i < 30; i++ {
|
||||
pool, err = pgxpool.New(ctx, dsn)
|
||||
if err == nil && pool.Ping(ctx) == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
if err != nil {
|
||||
container.Terminate(ctx)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
std, err := sql.Open("pgx", dsn)
|
||||
if err != nil {
|
||||
container.Terminate(ctx)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := goose.Up(std, migrationsDir); err != nil {
|
||||
container.Terminate(ctx)
|
||||
return nil, nil, err
|
||||
}
|
||||
std.Close()
|
||||
|
||||
cleanup := func() {
|
||||
pool.Close()
|
||||
_ = container.Terminate(context.Background())
|
||||
}
|
||||
return pool, cleanup, nil
|
||||
}
|
||||
|
||||
type Suite struct {
|
||||
suite.Suite
|
||||
|
||||
grpcSrv *grpc.Server
|
||||
grpcConn *grpc.ClientConn
|
||||
|
||||
client pb.CommentsClient
|
||||
|
||||
cleanup func()
|
||||
}
|
||||
|
||||
func TestLomsIntegrationSuite(t *testing.T) {
|
||||
suite.RunSuite(t, new(Suite))
|
||||
}
|
||||
|
||||
func (s *Suite) BeforeAll(t provider.T) {
|
||||
ctx := context.Background()
|
||||
t.WithNewStep("init cart-service", func(sCtx provider.StepCtx) {
|
||||
pool, cleanup, err := startPostgres(ctx, migrationsDir)
|
||||
sCtx.Require().NoError(err, "failed postgres setup")
|
||||
|
||||
s.cleanup = cleanup
|
||||
|
||||
repo := repo.NewCommentsRepository(pool, pool)
|
||||
|
||||
svc := service.NewCommentsService(repo, 1)
|
||||
|
||||
commentsServer := server.NewServer(svc)
|
||||
|
||||
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
s.grpcSrv = grpc.NewServer()
|
||||
pb.RegisterCommentsServer(s.grpcSrv, commentsServer)
|
||||
|
||||
go func() { _ = s.grpcSrv.Serve(lis) }()
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
conn, err := grpc.NewClient(lis.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
s.grpcConn = conn
|
||||
s.client = pb.NewCommentsClient(conn)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Suite) AfterAll(t provider.T) {
|
||||
s.grpcSrv.Stop()
|
||||
_ = s.grpcConn.Close()
|
||||
s.cleanup()
|
||||
}
|
||||
|
||||
func (s *Suite) TestCommentListByOneUser_Success(t provider.T) {
|
||||
t.Title("Успешное получение списка комментариев, которые оставил один юзер по SKU")
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
const (
|
||||
userID = int64(40)
|
||||
sku = int64(40)
|
||||
commentText1 = "тестовый комментарий 1"
|
||||
commentText2 = "тестовый комментарий 2"
|
||||
)
|
||||
|
||||
var (
|
||||
commentIDs []int64
|
||||
commentID int64
|
||||
)
|
||||
|
||||
t.WithNewParameters("userID", userID, "sku", sku)
|
||||
|
||||
t.WithNewStep("Создание комментария 1", func(sCtx provider.StepCtx) {
|
||||
req := &pb.CreateCommentRequest{
|
||||
UserId: userID,
|
||||
Sku: sku,
|
||||
Comment: commentText1,
|
||||
}
|
||||
resp, err := s.client.CommentAdd(ctx, req)
|
||||
sCtx.Require().NoError(err)
|
||||
commentID = resp.Id
|
||||
|
||||
commentIDs = append(commentIDs, commentID)
|
||||
})
|
||||
|
||||
t.WithNewParameters("commentID1", commentID)
|
||||
|
||||
t.WithNewStep("Получение первого созданного комментария", func(sCtx provider.StepCtx) {
|
||||
req := &pb.ListByUserRequest{
|
||||
UserId: userID,
|
||||
}
|
||||
resp, err := s.client.CommentListByUser(ctx, req)
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
sCtx.Require().Len(resp.Comments, 1)
|
||||
sCtx.Require().NotNil(resp.Comments[0])
|
||||
|
||||
resultComment := resp.Comments[0]
|
||||
|
||||
sCtx.Require().Equal(commentID, resultComment.Id)
|
||||
sCtx.Require().Equal(sku, resultComment.Sku)
|
||||
sCtx.Require().Equal(commentText1, resultComment.Text)
|
||||
})
|
||||
|
||||
t.WithNewStep("Создание комментария 2", func(sCtx provider.StepCtx) {
|
||||
req := &pb.CreateCommentRequest{
|
||||
UserId: userID,
|
||||
Sku: sku,
|
||||
Comment: commentText2,
|
||||
}
|
||||
resp, err := s.client.CommentAdd(ctx, req)
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
commentID = resp.Id
|
||||
commentIDs = append(commentIDs, commentID)
|
||||
})
|
||||
|
||||
t.WithNewParameters("commentID2", commentID)
|
||||
|
||||
t.WithNewStep("Получение созданных комментариев в обратном хронологическом порядке", func(sCtx provider.StepCtx) {
|
||||
req := &pb.ListByUserRequest{
|
||||
UserId: userID,
|
||||
}
|
||||
resp, err := s.client.CommentListByUser(ctx, req)
|
||||
sCtx.Require().NoError(err)
|
||||
|
||||
sCtx.Require().Len(resp.Comments, 2)
|
||||
sCtx.Require().NotNil(resp.Comments[0])
|
||||
sCtx.Require().NotNil(resp.Comments[1])
|
||||
|
||||
// commentIDs содержит в себе id комментариев в прямом хронологическом порядке
|
||||
sCtx.Require().Equal(commentIDs[1], resp.Comments[0].Id)
|
||||
sCtx.Require().Equal(sku, resp.Comments[0].Sku)
|
||||
sCtx.Require().Equal(commentText2, resp.Comments[0].Text)
|
||||
|
||||
sCtx.Require().Equal(commentIDs[0], resp.Comments[1].Id)
|
||||
sCtx.Require().Equal(sku, resp.Comments[1].Sku)
|
||||
sCtx.Require().Equal(commentText1, resp.Comments[1].Text)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user