//go:build integration // +build integration package repositoryimp_test import ( "context" "errors" "testing" "time" "git.sendico.io/tech/sxchnge/shared/database/internal/builder" "git.sendico.io/tech/sxchnge/shared/database/internal/repository" "git.sendico.io/tech/sxchnge/shared/database/record" "git.sendico.io/tech/sxchnge/shared/database/repository/builder" "git.sendico.io/tech/sxchnge/shared/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/modules/mongodb" "github.com/testcontainers/testcontainers-go/wait" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" ) type TestObject struct { storable.Base `bson:",inline" json:",inline"` Name string `bson:"name"` Tags []string `bson:"tags"` } func (t *TestObject) Collection() string { return "testObject" } type AnotherObject struct { storable.Base `bson:",inline" json:",inline"` Description string `bson:"description"` } func (a *AnotherObject) Collection() string { return "anotherObject" } func terminate(ctx context.Context, t *testing.T, container *mongodb.MongoDBContainer) { err := container.Terminate(ctx) require.NoError(t, err, "failed to terminate MongoDB container") } func disconnect(ctx context.Context, t *testing.T, client *mongo.Client) { err := client.Disconnect(ctx) require.NoError(t, err, "failed to disconnect from MongoDB") } func TestMongoRepository_Get(t *testing.T) { // Use a context with timeout, so if container spinning or DB ops hang, // the test won't run indefinitely. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() mongoContainer, err := mongodb.Run(ctx, "mongo:latest", mongodb.WithUsername("root"), mongodb.WithPassword("password"), testcontainers.WithWaitStrategy(wait.ForLog("Waiting for connections")), ) require.NoError(t, err, "failed to start MongoDB container") defer terminate(ctx, t, mongoContainer) mongoURI, err := mongoContainer.ConnectionString(ctx) require.NoError(t, err, "failed to get MongoDB connection string") clientOptions := options.Client().ApplyURI(mongoURI) client, err := mongo.Connect(clientOptions) require.NoError(t, err, "failed to connect to MongoDB") defer disconnect(ctx, t, client) db := client.Database("testdb") repository := repositoryimp.NewMongoRepository(db, "testcollection") t.Run("Get_Success", func(t *testing.T) { testObj := &TestObject{Name: "testName"} err := repository.Insert(ctx, testObj, nil) require.NoError(t, err) result := &TestObject{} err = repository.Get(ctx, testObj.ID, result) require.NoError(t, err) assert.Equal(t, testObj.Name, result.Name) assert.Equal(t, testObj.ID, result.ID) }) t.Run("Get_NotFound", func(t *testing.T) { nonExistentID := bson.NewObjectID() result := &TestObject{} err := repository.Get(ctx, nonExistentID, result) assert.Error(t, err) assert.True(t, errors.Is(err, merrors.ErrNoData)) }) t.Run("Get_InvalidID", func(t *testing.T) { invalidID := bson.ObjectID{} // zero value result := &TestObject{} err := repository.Get(ctx, invalidID, result) assert.Error(t, err) assert.True(t, errors.Is(err, merrors.ErrInvalidArg)) }) t.Run("Get_DifferentTypes", func(t *testing.T) { anotherObj := &AnotherObject{Description: "testDescription"} err := repository.Insert(ctx, anotherObj, nil) require.NoError(t, err) result := &AnotherObject{} err = repository.Get(ctx, anotherObj.ID, result) require.NoError(t, err) assert.Equal(t, anotherObj.Description, result.Description) assert.Equal(t, anotherObj.ID, result.ID) }) } func TestMongoRepository_ListIDs(t *testing.T) { // Use a context with timeout, so if container spinning or DB ops hang, // the test won't run indefinitely. ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() mongoContainer, err := mongodb.Run(ctx, "mongo:latest", mongodb.WithUsername("root"), mongodb.WithPassword("password"), testcontainers.WithWaitStrategy(wait.ForLog("Waiting for connections")), ) require.NoError(t, err, "failed to start MongoDB container") defer terminate(ctx, t, mongoContainer) mongoURI, err := mongoContainer.ConnectionString(ctx) require.NoError(t, err, "failed to get MongoDB connection string") clientOptions := options.Client().ApplyURI(mongoURI) client, err := mongo.Connect(clientOptions) require.NoError(t, err, "failed to connect to MongoDB") defer disconnect(ctx, t, client) db := client.Database("testdb") repository := repositoryimp.NewMongoRepository(db, "testcollection") t.Run("ListIDs_Success", func(t *testing.T) { // Insert test data testObjs := []*TestObject{ {Name: "testName1"}, {Name: "testName2"}, {Name: "testName3"}, } for _, obj := range testObjs { err := repository.Insert(ctx, obj, nil) require.NoError(t, err) } // Define a query to match all objects query := builderimp.NewQueryImp() // Call ListIDs ids, err := repository.ListIDs(ctx, query) require.NoError(t, err) // Assert the IDs are correct require.Len(t, ids, len(testObjs)) for _, obj := range testObjs { assert.Contains(t, ids, obj.ID) } }) t.Run("ListIDs_EmptyResult", func(t *testing.T) { // Define a query that matches no objects query := builderimp.NewQueryImp().Comparison(builderimp.NewFieldImp("name"), builder.Eq, "nonExistentName") // Call ListIDs ids, err := repository.ListIDs(ctx, query) require.NoError(t, err) // Assert no IDs are returned assert.Empty(t, ids) }) }