mirror of
				https://github.com/3ybactuk/marketplace-go-service-project.git
				synced 2025-10-30 05:53:45 +03:00 
			
		
		
		
	[hw-8] add: integration tests
This commit is contained in:
		| @@ -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
	 3ybacTuK
					3ybacTuK