From c34621ee9479d5448006bb03931d9d2a7f3660cb Mon Sep 17 00:00:00 2001 From: mehdihadeli Date: Wed, 20 Sep 2023 16:02:58 +0330 Subject: [PATCH] fix: :bug: fix in tests --- internal/pkg/go.mod | 3 + internal/pkg/go.sum | 13 ++ .../contracts/rabbitmq_container.go | 9 ++ .../rabbitmq/rabbitmq_container.go | 81 +++++++++-- .../integration/integration_test_fixture.go | 55 +++++--- .../v1/commands/delete_product_test.go | 34 +++-- .../v1/events/product_updated_test.go | 128 +++++++++++------- .../integration/integration_test_fixture.go | 21 +-- .../integration/integration_test_fixture.go | 43 ++++-- 9 files changed, 279 insertions(+), 108 deletions(-) diff --git a/internal/pkg/go.mod b/internal/pkg/go.mod index 679cb619..ffb1bcb7 100644 --- a/internal/pkg/go.mod +++ b/internal/pkg/go.mod @@ -34,6 +34,7 @@ require ( github.com/lib/pq v1.10.9 github.com/mcuadros/go-defaults v1.2.0 github.com/mehdihadeli/go-mediatr v1.1.10 + github.com/michaelklishin/rabbit-hole v1.5.0 github.com/mitchellh/mapstructure v1.5.0 github.com/nolleh/caption_json_formatter v0.2.2 github.com/orlangure/gnomock v0.30.0 @@ -138,6 +139,7 @@ require ( github.com/moby/term v0.5.0 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/nxadm/tail v1.4.8 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc4 // indirect github.com/opencontainers/runc v1.1.9 // indirect @@ -158,6 +160,7 @@ require ( github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/streadway/amqp v1.1.0 // indirect github.com/stretchr/objx v0.5.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect diff --git a/internal/pkg/go.sum b/internal/pkg/go.sum index 2cf62db2..fb555b42 100644 --- a/internal/pkg/go.sum +++ b/internal/pkg/go.sum @@ -175,6 +175,7 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= @@ -449,6 +450,8 @@ github.com/mcuadros/go-defaults v1.2.0 h1:FODb8WSf0uGaY8elWJAkoLL0Ri6AlZ1bFlenk5 github.com/mcuadros/go-defaults v1.2.0/go.mod h1:WEZtHEVIGYVDqkKSWBdWKUVdRyKlMfulPaGDWIVeCWY= github.com/mehdihadeli/go-mediatr v1.1.10 h1:NAzg4065c90lgYeb+Vzbd2WKH0tUFpxzL0mpx6hkU/A= github.com/mehdihadeli/go-mediatr v1.1.10/go.mod h1:lwgZl7qVL/RKomObBblhG3uEte/r4nJDV95Vd+nGrMw= +github.com/michaelklishin/rabbit-hole v1.5.0 h1:Bex27BiFDsijCM9D0ezSHqyy0kehpYHuNKaPqq/a4RM= +github.com/michaelklishin/rabbit-hole v1.5.0/go.mod h1:vvI1uOitYZi0O5HEGXhaWC1XT80Gy+HvFheJ+5Krlhk= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -468,9 +471,15 @@ github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nolleh/caption_json_formatter v0.2.2 h1:EKsOr/fCllNQF2ZoajfbSDlV73BNV1bDu1aTTSRrlN0= github.com/nolleh/caption_json_formatter v0.2.2/go.mod h1:5FYofZA8NAej/eFxa12FvyQKosU1LfyKizZPlY0JojU= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -572,6 +581,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= +github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -854,6 +865,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1108,6 +1120,7 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/pkg/test/containers/contracts/rabbitmq_container.go b/internal/pkg/test/containers/contracts/rabbitmq_container.go index 268ef396..5f012fa5 100644 --- a/internal/pkg/test/containers/contracts/rabbitmq_container.go +++ b/internal/pkg/test/containers/contracts/rabbitmq_container.go @@ -2,6 +2,7 @@ package contracts import ( "context" + "fmt" "testing" "github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/core/serializer" @@ -23,6 +24,14 @@ type RabbitMQContainerOptions struct { Tag string } +func (h *RabbitMQContainerOptions) AmqpEndPoint() string { + return fmt.Sprintf("amqp://%s:%s@%s:%d", h.UserName, h.Password, h.Host, h.HostPort) +} + +func (h *RabbitMQContainerOptions) HttpEndPoint() string { + return fmt.Sprintf("http://%s:%d", h.Host, h.HttpPort) +} + type RabbitMQContainer interface { Start(ctx context.Context, t *testing.T, diff --git a/internal/pkg/test/containers/testcontainer/rabbitmq/rabbitmq_container.go b/internal/pkg/test/containers/testcontainer/rabbitmq/rabbitmq_container.go index 5baf874a..9c3af822 100644 --- a/internal/pkg/test/containers/testcontainer/rabbitmq/rabbitmq_container.go +++ b/internal/pkg/test/containers/testcontainer/rabbitmq/rabbitmq_container.go @@ -18,6 +18,7 @@ import ( "emperror.dev/errors" "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" + rabbithole "github.com/michaelklishin/rabbit-hole" "github.com/rabbitmq/amqp091-go" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" @@ -79,7 +80,10 @@ func (g *rabbitmqTestContainers) CreatingContainerOptions( }) // get a free random host port for rabbitmq `Tcp Port` - hostPort, err := dbContainer.MappedPort(ctx, nat.Port(g.defaultOptions.Ports[0])) + hostPort, err := dbContainer.MappedPort( + ctx, + nat.Port(g.defaultOptions.Ports[0]), + ) if err != nil { return nil, err } @@ -88,7 +92,10 @@ func (g *rabbitmqTestContainers) CreatingContainerOptions( // https://github.com/michaelklishin/rabbit-hole/issues/74 // get a free random host port for rabbitmq UI `Http Port` - uiHttpPort, err := dbContainer.MappedPort(ctx, nat.Port(g.defaultOptions.Ports[1])) + uiHttpPort, err := dbContainer.MappedPort( + ctx, + nat.Port(g.defaultOptions.Ports[1]), + ) if err != nil { return nil, err } @@ -136,7 +143,9 @@ func (g *rabbitmqTestContainers) Start( rabbitHostOptions.AmqpEndPoint(), ) - rabbitmqConfig := &config.RabbitmqOptions{RabbitmqHostOptions: rabbitHostOptions} + rabbitmqConfig := &config.RabbitmqOptions{ + RabbitmqHostOptions: rabbitHostOptions, + } conn, err := types.NewRabbitMQConnection(rabbitmqConfig) if err != nil { return nil, err @@ -189,9 +198,15 @@ func (g *rabbitmqTestContainers) getRunOptions( } } containerReq := testcontainers.ContainerRequest{ - Image: fmt.Sprintf("%s:%s", g.defaultOptions.ImageName, g.defaultOptions.Tag), + Image: fmt.Sprintf( + "%s:%s", + g.defaultOptions.ImageName, + g.defaultOptions.Tag, + ), ExposedPorts: g.defaultOptions.Ports, - WaitingFor: wait.ForListeningPort(nat.Port(g.defaultOptions.Ports[0])), + WaitingFor: wait.ForListeningPort( + nat.Port(g.defaultOptions.Ports[0]), + ), HostConfigModifier: func(hostConfig *container.HostConfig) { hostConfig.AutoRemove = true }, @@ -205,12 +220,19 @@ func (g *rabbitmqTestContainers) getRunOptions( return containerReq } -func IsConnectable(logger logger.Logger, options *contracts.RabbitMQContainerOptions) bool { - conn, err := amqp091.Dial( - fmt.Sprintf("amqp://%s:%s@%s:%d", options.UserName, options.Password, options.Host, options.HostPort), - ) +func IsConnectable( + logger logger.Logger, + options *contracts.RabbitMQContainerOptions, +) bool { + conn, err := amqp091.Dial(options.AmqpEndPoint()) if err != nil { - logError(logger, options.UserName, options.Password, options.Host, options.HostPort) + logError( + logger, + options.UserName, + options.Password, + options.Host, + options.HostPort, + ) return false } @@ -218,10 +240,33 @@ func IsConnectable(logger logger.Logger, options *contracts.RabbitMQContainerOpt defer conn.Close() if err != nil || (conn != nil && conn.IsClosed()) { - logError(logger, options.UserName, options.Password, options.Host, options.HostPort) + logError( + logger, + options.UserName, + options.Password, + options.Host, + options.HostPort, + ) return false } + + // https://github.com/michaelklishin/rabbit-hole + rmqc, err := rabbithole.NewClient( + options.HttpEndPoint(), + options.UserName, + options.Password, + ) + _, err = rmqc.ListExchanges() + if err != nil { + logger.Errorf( + "Error in creating rabbitmq connection with http host: %s", + options.HttpEndPoint(), + ) + + return false + } + logger.Infof( "Opened rabbitmq connection on host: amqp://%s:%s@%s:%d", options.UserName, @@ -233,9 +278,19 @@ func IsConnectable(logger logger.Logger, options *contracts.RabbitMQContainerOpt return true } -func logError(logger logger.Logger, userName string, password string, host string, hostPort int) { +func logError( + logger logger.Logger, + userName string, + password string, + host string, + hostPort int, +) { // we should not use `t.Error` or `t.Errorf` for logging errors because it will `fail` our test at the end and, we just should use logs without error like log.Error (not log.Fatal) logger.Errorf( - "Error in creating rabbitmq connection with host: amqp://%s:%s@%s:%d", userName, password, host, hostPort, + "Error in creating rabbitmq connection with amqp host: amqp://%s:%s@%s:%d", + userName, + password, + host, + hostPort, ) } diff --git a/internal/services/catalog_read_service/internal/shared/test_fixture/integration/integration_test_fixture.go b/internal/services/catalog_read_service/internal/shared/test_fixture/integration/integration_test_fixture.go index 93501cca..2dbb824a 100644 --- a/internal/services/catalog_read_service/internal/shared/test_fixture/integration/integration_test_fixture.go +++ b/internal/services/catalog_read_service/internal/shared/test_fixture/integration/integration_test_fixture.go @@ -2,7 +2,6 @@ package integration import ( "context" - "fmt" "testing" "time" @@ -21,7 +20,6 @@ import ( "github.com/brianvoe/gofakeit/v6" rabbithole "github.com/michaelklishin/rabbit-hole" uuid "github.com/satori/go.uuid" - "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.opentelemetry.io/otel/trace" @@ -43,16 +41,19 @@ type IntegrationTestSharedFixture struct { Tracer trace.Tracer } -func NewIntegrationTestSharedFixture(t *testing.T) *IntegrationTestSharedFixture { +func NewIntegrationTestSharedFixture( + t *testing.T, +) *IntegrationTestSharedFixture { result := test.NewTestApp().Run(t) // https://github.com/michaelklishin/rabbit-hole rmqc, err := rabbithole.NewClient( - fmt.Sprintf(result.RabbitmqOptions.RabbitmqHostOptions.HttpEndPoint()), + result.RabbitmqOptions.RabbitmqHostOptions.HttpEndPoint(), result.RabbitmqOptions.RabbitmqHostOptions.UserName, result.RabbitmqOptions.RabbitmqHostOptions.Password) - - require.NoError(t, err) + if err != nil { + result.Logger.Error(errors.WrapIf(err, "error in creating rabbithole client")) + } shared := &IntegrationTestSharedFixture{ Log: result.Logger, @@ -78,8 +79,9 @@ func (i *IntegrationTestSharedFixture) InitializeTest() { // seed data in each test res, err := seedData(i.mongoClient, i.MongoOptions.Database) if err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in seeding mongodb data")) } + i.Items = res } @@ -88,15 +90,18 @@ func (i *IntegrationTestSharedFixture) DisposeTest() { // cleanup test containers with their hooks if err := i.cleanupRabbitmqData(); err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in cleanup rabbitmq data")) } if err := i.cleanupMongoData(); err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in cleanup mongodb data")) } } -func seedData(db *mongo.Client, databaseName string) ([]*models.Product, error) { +func seedData( + db *mongo.Client, + databaseName string, +) ([]*models.Product, error) { ctx := context.Background() products := []*models.Product{ @@ -119,13 +124,18 @@ func seedData(db *mongo.Client, databaseName string) ([]*models.Product, error) } //// https://go.dev/doc/faq#convert_slice_of_interface - data := make([]interface{}, len(products)) + productsData := make([]interface{}, len(products)) + for i, v := range products { - data[i] = v + productsData[i] = v } collection := db.Database(databaseName).Collection("products") - _, err := collection.InsertMany(context.Background(), data, &options.InsertManyOptions{}) + _, err := collection.InsertMany( + context.Background(), + productsData, + &options.InsertManyOptions{}, + ) if err != nil { return nil, errors.WrapIf(err, "error in seed database") } @@ -136,13 +146,16 @@ func seedData(db *mongo.Client, databaseName string) ([]*models.Product, error) collection, nil, ) + return result.Items, nil } func (i *IntegrationTestSharedFixture) cleanupRabbitmqData() error { // https://github.com/michaelklishin/rabbit-hole // Get all queues - queues, err := i.RabbitmqCleaner.ListQueuesIn(i.rabbitmqOptions.RabbitmqHostOptions.VirtualHost) + queues, err := i.RabbitmqCleaner.ListQueuesIn( + i.rabbitmqOptions.RabbitmqHostOptions.VirtualHost, + ) if err != nil { return err } @@ -153,6 +166,7 @@ func (i *IntegrationTestSharedFixture) cleanupRabbitmqData() error { i.rabbitmqOptions.RabbitmqHostOptions.VirtualHost, queue.Name, ) + return err } @@ -161,11 +175,20 @@ func (i *IntegrationTestSharedFixture) cleanupRabbitmqData() error { func (i *IntegrationTestSharedFixture) cleanupMongoData() error { collections := []string{"products"} - err := cleanupCollections(i.mongoClient, collections, i.MongoOptions.Database) + err := cleanupCollections( + i.mongoClient, + collections, + i.MongoOptions.Database, + ) + return err } -func cleanupCollections(db *mongo.Client, collections []string, databaseName string) error { +func cleanupCollections( + db *mongo.Client, + collections []string, + databaseName string, +) error { database := db.Database(databaseName) ctx := context.Background() diff --git a/internal/services/catalog_read_service/test/integration/products/features/deleting_product/v1/commands/delete_product_test.go b/internal/services/catalog_read_service/test/integration/products/features/deleting_product/v1/commands/delete_product_test.go index d8464dfb..7deae9de 100644 --- a/internal/services/catalog_read_service/test/integration/products/features/deleting_product/v1/commands/delete_product_test.go +++ b/internal/services/catalog_read_service/test/integration/products/features/deleting_product/v1/commands/delete_product_test.go @@ -17,7 +17,9 @@ import ( ) func TestDeleteProduct(t *testing.T) { - integrationTestSharedFixture := integration.NewIntegrationTestSharedFixture(t) + integrationTestSharedFixture := integration.NewIntegrationTestSharedFixture( + t, + ) Convey("Deleting Product Feature", t, func() { ctx := context.Background() @@ -27,7 +29,9 @@ func TestDeleteProduct(t *testing.T) { // scenario Convey("Deleting an existing product from the database", func() { Convey("Given an existing product in the mongo database", func() { - productId, err := uuid.FromString(integrationTestSharedFixture.Items[0].ProductId) + productId, err := uuid.FromString( + integrationTestSharedFixture.Items[0].ProductId, + ) So(err, ShouldBeNil) command, err := commands.NewDeleteProduct(productId) @@ -39,18 +43,24 @@ func TestDeleteProduct(t *testing.T) { command, ) - Convey("Then the product should be deleted successfully in mongo database", func() { - So(err, ShouldBeNil) - So(result, ShouldNotBeNil) + Convey( + "Then the product should be deleted successfully in mongo database", + func() { + So(err, ShouldBeNil) + So(result, ShouldNotBeNil) - Convey("And the product should no longer exist in the system", func() { - deletedProduct, _ := integrationTestSharedFixture.ProductRepository.GetProductById( - ctx, - productId.String(), + Convey( + "And the product should no longer exist in the system", + func() { + deletedProduct, _ := integrationTestSharedFixture.ProductRepository.GetProductByProductId( + ctx, + productId.String(), + ) + So(deletedProduct, ShouldBeNil) + }, ) - So(deletedProduct, ShouldBeNil) - }) - }) + }, + ) }) }) }) diff --git a/internal/services/catalog_read_service/test/integration/products/features/updating_product/v1/events/product_updated_test.go b/internal/services/catalog_read_service/test/integration/products/features/updating_product/v1/events/product_updated_test.go index 6f7186ac..37282c39 100644 --- a/internal/services/catalog_read_service/test/integration/products/features/updating_product/v1/events/product_updated_test.go +++ b/internal/services/catalog_read_service/test/integration/products/features/updating_product/v1/events/product_updated_test.go @@ -23,7 +23,9 @@ import ( func TestProductUpdatedConsumer(t *testing.T) { // Setup and initialization code here. - integrationTestSharedFixture := integration.NewIntegrationTestSharedFixture(t) + integrationTestSharedFixture := integration.NewIntegrationTestSharedFixture( + t, + ) // in test mode we set rabbitmq `AutoStart=false` in configuration in rabbitmqOptions, so we should run rabbitmq bus manually integrationTestSharedFixture.Bus.Start(context.Background()) // wait for consumers ready to consume before publishing messages, preparation background workers takes a bit time (for preventing messages lost) @@ -52,62 +54,94 @@ func TestProductUpdatedConsumer(t *testing.T) { } Convey("When a ProductUpdated event consumed", func() { - err := integrationTestSharedFixture.Bus.PublishMessage(ctx, fakeUpdateProduct, nil) + err := integrationTestSharedFixture.Bus.PublishMessage( + ctx, + fakeUpdateProduct, + nil, + ) So(err, ShouldBeNil) - Convey("Then it should consume the ProductUpdated event", func() { - hypothesis.Validate(ctx, "there is no consumed message", 30*time.Second) - }) + Convey( + "Then it should consume the ProductUpdated event", + func() { + hypothesis.Validate( + ctx, + "there is no consumed message", + 30*time.Second, + ) + }, + ) }) }) // https://specflow.org/learn/gherkin/#learn-gherkin // scenario - Convey("Update product in mongo database when a ProductDeleted event consumed", func() { - fakeUpdateProduct := &externalEvents.ProductUpdatedV1{ - Message: types.NewMessage(uuid.NewV4().String()), - ProductId: integrationTestSharedFixture.Items[0].ProductId, - Name: gofakeit.Name(), - Price: gofakeit.Price(100, 1000), - Description: gofakeit.EmojiDescription(), - UpdatedAt: time.Now(), - } - - Convey("When a ProductUpdated event consumed", func() { - err := integrationTestSharedFixture.Bus.PublishMessage(ctx, fakeUpdateProduct, nil) - So(err, ShouldBeNil) - - Convey("It should update product in the mongo database", func() { - ctx := context.Background() - productUpdated := &externalEvents.ProductUpdatedV1{ - Message: types.NewMessage(uuid.NewV4().String()), - ProductId: integrationTestSharedFixture.Items[0].ProductId, - Name: gofakeit.Name(), - Description: gofakeit.AdjectiveDescriptive(), - Price: gofakeit.Price(150, 6000), - UpdatedAt: time.Now(), - } - - err := integrationTestSharedFixture.Bus.PublishMessage(ctx, productUpdated, nil) + Convey( + "Update product in mongo database when a ProductDeleted event consumed", + func() { + fakeUpdateProduct := &externalEvents.ProductUpdatedV1{ + Message: types.NewMessage(uuid.NewV4().String()), + ProductId: integrationTestSharedFixture.Items[0].ProductId, + Name: gofakeit.Name(), + Price: gofakeit.Price(100, 1000), + Description: gofakeit.EmojiDescription(), + UpdatedAt: time.Now(), + } + + Convey("When a ProductUpdated event consumed", func() { + err := integrationTestSharedFixture.Bus.PublishMessage( + ctx, + fakeUpdateProduct, + nil, + ) So(err, ShouldBeNil) - var product *models.Product - - err = testUtils.WaitUntilConditionMet(func() bool { - product, err = integrationTestSharedFixture.ProductRepository.GetProductByProductId( - ctx, - integrationTestSharedFixture.Items[0].ProductId, - ) - - return product != nil && product.Name == productUpdated.Name - }) - - So(err, ShouldBeNil) - So(product, ShouldNotBeNil) - So(productUpdated.ProductId, ShouldEqual, product.ProductId) + Convey( + "Then It should update product in the mongo database", + func() { + ctx := context.Background() + productUpdated := &externalEvents.ProductUpdatedV1{ + Message: types.NewMessage( + uuid.NewV4().String(), + ), + ProductId: integrationTestSharedFixture.Items[0].ProductId, + Name: gofakeit.Name(), + Description: gofakeit.AdjectiveDescriptive(), + Price: gofakeit.Price(150, 6000), + UpdatedAt: time.Now(), + } + + err := integrationTestSharedFixture.Bus.PublishMessage( + ctx, + productUpdated, + nil, + ) + So(err, ShouldBeNil) + + var product *models.Product + + err = testUtils.WaitUntilConditionMet(func() bool { + product, err = integrationTestSharedFixture.ProductRepository.GetProductByProductId( + ctx, + integrationTestSharedFixture.Items[0].ProductId, + ) + + return product != nil && + product.Name == productUpdated.Name + }) + + So(err, ShouldBeNil) + So(product, ShouldNotBeNil) + So( + productUpdated.ProductId, + ShouldEqual, + product.ProductId, + ) + }, + ) }) - }) - }) + }, + ) integrationTestSharedFixture.DisposeTest() }) diff --git a/internal/services/catalog_write_service/internal/shared/test_fixtures/integration/integration_test_fixture.go b/internal/services/catalog_write_service/internal/shared/test_fixtures/integration/integration_test_fixture.go index 6e346743..5eb2ced3 100644 --- a/internal/services/catalog_write_service/internal/shared/test_fixtures/integration/integration_test_fixture.go +++ b/internal/services/catalog_write_service/internal/shared/test_fixtures/integration/integration_test_fixture.go @@ -2,7 +2,6 @@ package integration import ( "context" - "fmt" "testing" "time" @@ -45,16 +44,20 @@ type IntegrationTestSharedFixture struct { ProductServiceClient productsService.ProductsServiceClient } -func NewIntegrationTestSharedFixture(t *testing.T) *IntegrationTestSharedFixture { +func NewIntegrationTestSharedFixture( + t *testing.T, +) *IntegrationTestSharedFixture { result := test.NewTestApp().Run(t) // https://github.com/michaelklishin/rabbit-hole rmqc, err := rabbithole.NewClient( - fmt.Sprintf(result.RabbitmqOptions.RabbitmqHostOptions.HttpEndPoint()), + result.RabbitmqOptions.RabbitmqHostOptions.HttpEndPoint(), result.RabbitmqOptions.RabbitmqHostOptions.UserName, result.RabbitmqOptions.RabbitmqHostOptions.Password) if err != nil { - result.Logger.Fatalf("error in initializing rabbithole, err: %s", err) + result.Logger.Error( + errors.WrapIf(err, "error in creating rabbithole client"), + ) } shared := &IntegrationTestSharedFixture{ @@ -82,7 +85,7 @@ func (i *IntegrationTestSharedFixture) InitializeTest() { // seed data in each test res, err := seedData(i.Gorm) if err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in seeding data in postgres")) } i.Items = res @@ -93,18 +96,20 @@ func (i *IntegrationTestSharedFixture) DisposeTest() { // cleanup test containers with their hooks if err := i.cleanupRabbitmqData(); err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in cleanup rabbitmq data")) } if err := i.cleanupPostgresData(); err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in cleanup postgres data")) } } func (i *IntegrationTestSharedFixture) cleanupRabbitmqData() error { // https://github.com/michaelklishin/rabbit-hole // Get all queues - queues, err := i.RabbitmqCleaner.ListQueuesIn(i.rabbitmqOptions.RabbitmqHostOptions.VirtualHost) + queues, err := i.RabbitmqCleaner.ListQueuesIn( + i.rabbitmqOptions.RabbitmqHostOptions.VirtualHost, + ) if err != nil { return err } diff --git a/internal/services/order_service/internal/shared/test_fixtures/integration/integration_test_fixture.go b/internal/services/order_service/internal/shared/test_fixtures/integration/integration_test_fixture.go index 6161416f..91032d12 100644 --- a/internal/services/order_service/internal/shared/test_fixtures/integration/integration_test_fixture.go +++ b/internal/services/order_service/internal/shared/test_fixtures/integration/integration_test_fixture.go @@ -2,7 +2,6 @@ package integration import ( "context" - "fmt" "testing" "github.com/mehdihadeli/go-ecommerce-microservices/internal/pkg/es/contracts/store" @@ -52,15 +51,21 @@ type IntegrationTestSharedFixture struct { OrdersServiceClient ordersService.OrdersServiceClient } -func NewIntegrationTestSharedFixture(t *testing.T) *IntegrationTestSharedFixture { +func NewIntegrationTestSharedFixture( + t *testing.T, +) *IntegrationTestSharedFixture { result := test.NewTestApp().Run(t) // https://github.com/michaelklishin/rabbit-hole - rmqc, _ := rabbithole.NewClient( - fmt.Sprintf(result.RabbitmqOptions.RabbitmqHostOptions.HttpEndPoint()), + rmqc, err := rabbithole.NewClient( + result.RabbitmqOptions.RabbitmqHostOptions.HttpEndPoint(), result.RabbitmqOptions.RabbitmqHostOptions.UserName, result.RabbitmqOptions.RabbitmqHostOptions.Password) - + if err != nil { + result.Logger.Error( + errors.WrapIf(err, "error in creating rabbithole client"), + ) + } shared := &IntegrationTestSharedFixture{ Log: result.Logger, Container: result.Container, @@ -86,7 +91,7 @@ func (i *IntegrationTestSharedFixture) InitializeTest() { // seed data in each test res, err := seedReadModelData(i.mongoClient, i.MongoDbOptions.Database) if err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in seeding mongodb data")) } i.Items = res } @@ -96,18 +101,20 @@ func (i *IntegrationTestSharedFixture) DisposeTest() { // cleanup test containers with their hooks if err := i.cleanupRabbitmqData(); err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in cleanup rabbitmq data")) } if err := i.cleanupMongoData(); err != nil { - i.Log.Fatal(err) + i.Log.Error(errors.WrapIf(err, "error in cleanup mongodb data")) } } func (i *IntegrationTestSharedFixture) cleanupRabbitmqData() error { // https://github.com/michaelklishin/rabbit-hole // Get all queues - queues, err := i.RabbitmqCleaner.ListQueuesIn(i.rabbitmqOptions.RabbitmqHostOptions.VirtualHost) + queues, err := i.RabbitmqCleaner.ListQueuesIn( + i.rabbitmqOptions.RabbitmqHostOptions.VirtualHost, + ) if err != nil { return err } @@ -126,11 +133,19 @@ func (i *IntegrationTestSharedFixture) cleanupRabbitmqData() error { func (i *IntegrationTestSharedFixture) cleanupMongoData() error { collections := []string{orderCollection} - err := cleanupCollections(i.mongoClient, collections, i.MongoDbOptions.Database) + err := cleanupCollections( + i.mongoClient, + collections, + i.MongoDbOptions.Database, + ) return err } -func cleanupCollections(db *mongo.Client, collections []string, databaseName string) error { +func cleanupCollections( + db *mongo.Client, + collections []string, + databaseName string, +) error { database := db.Database(databaseName) ctx := context.Background() @@ -196,7 +211,11 @@ func seedReadModelData( } collection := db.Database(databaseName).Collection("orders") - _, err := collection.InsertMany(context.Background(), data, &options.InsertManyOptions{}) + _, err := collection.InsertMany( + context.Background(), + data, + &options.InsertManyOptions{}, + ) if err != nil { return nil, errors.WrapIf(err, "error in seed database") }