//go:build integration // +build integration package archivable import ( "context" "testing" "time" "github.com/tech/sendico/pkg/db/internal/mongo/repositoryimp" "github.com/tech/sendico/pkg/db/storable" "github.com/tech/sendico/pkg/model" "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/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" ) // TestArchivableObject represents a test object with archivable functionality type TestArchivableObject struct { storable.Base `bson:",inline" json:",inline"` model.ArchivableBase `bson:",inline" json:",inline"` Name string `bson:"name" json:"name"` } func (t *TestArchivableObject) Collection() string { return "testArchivableObject" } func (t *TestArchivableObject) GetArchivable() model.Archivable { return &t.ArchivableBase } func TestArchivableDB(t *testing.T) { ctx := context.Background() // Start MongoDB container (stable) mongoContainer, err := mongodb.Run(ctx, "mongo:latest", mongodb.WithUsername("test"), mongodb.WithPassword("test"), testcontainers.WithWaitStrategy(wait.ForListeningPort("27017/tcp").WithStartupTimeout(2*time.Minute)), ) require.NoError(t, err) defer func() { termCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := mongoContainer.Terminate(termCtx); err != nil { t.Logf("Failed to terminate container: %v", err) } }() // Get MongoDB connection string mongoURI, err := mongoContainer.ConnectionString(ctx) require.NoError(t, err) // Connect to MongoDB client, err := mongo.Connect(ctx, options.Client().ApplyURI(mongoURI)) require.NoError(t, err) defer func() { if err := client.Disconnect(context.Background()); err != nil { t.Logf("Failed to disconnect from MongoDB: %v", err) } }() // Ping the database err = client.Ping(ctx, nil) require.NoError(t, err) // Create repository repo := repositoryimp.NewMongoRepository(client.Database("test_"+t.Name()), "testArchivableCollection") // Create archivable DB archivableDB := NewArchivableDB( repo, zap.NewNop(), func() *TestArchivableObject { return &TestArchivableObject{} }, func(obj *TestArchivableObject) model.Archivable { return obj.GetArchivable() }, ) t.Run("SetArchived_Success", func(t *testing.T) { obj := &TestArchivableObject{Name: "test", ArchivableBase: model.ArchivableBase{Archived: false}} err := repo.Insert(ctx, obj, nil) require.NoError(t, err) err = archivableDB.SetArchived(ctx, obj.ID, true) require.NoError(t, err) var result TestArchivableObject err = repo.Get(ctx, obj.ID, &result) require.NoError(t, err) assert.True(t, result.IsArchived()) }) t.Run("SetArchived_NoChange", func(t *testing.T) { obj := &TestArchivableObject{Name: "test", ArchivableBase: model.ArchivableBase{Archived: true}} err := repo.Insert(ctx, obj, nil) require.NoError(t, err) err = archivableDB.SetArchived(ctx, obj.ID, true) require.NoError(t, err) // Should not error, just not change anything var result TestArchivableObject err = repo.Get(ctx, obj.ID, &result) require.NoError(t, err) assert.True(t, result.IsArchived()) }) t.Run("SetArchived_Unarchive", func(t *testing.T) { obj := &TestArchivableObject{Name: "test", ArchivableBase: model.ArchivableBase{Archived: true}} err := repo.Insert(ctx, obj, nil) require.NoError(t, err) err = archivableDB.SetArchived(ctx, obj.ID, false) require.NoError(t, err) var result TestArchivableObject err = repo.Get(ctx, obj.ID, &result) require.NoError(t, err) assert.False(t, result.IsArchived()) }) t.Run("IsArchived_True", func(t *testing.T) { obj := &TestArchivableObject{Name: "test", ArchivableBase: model.ArchivableBase{Archived: true}} err := repo.Insert(ctx, obj, nil) require.NoError(t, err) isArchived, err := archivableDB.IsArchived(ctx, obj.ID) require.NoError(t, err) assert.True(t, isArchived) }) t.Run("IsArchived_False", func(t *testing.T) { obj := &TestArchivableObject{Name: "test", ArchivableBase: model.ArchivableBase{Archived: false}} err := repo.Insert(ctx, obj, nil) require.NoError(t, err) isArchived, err := archivableDB.IsArchived(ctx, obj.ID) require.NoError(t, err) assert.False(t, isArchived) }) t.Run("Archive_Success", func(t *testing.T) { obj := &TestArchivableObject{Name: "test", ArchivableBase: model.ArchivableBase{Archived: false}} err := repo.Insert(ctx, obj, nil) require.NoError(t, err) err = archivableDB.Archive(ctx, obj.ID) require.NoError(t, err) var result TestArchivableObject err = repo.Get(ctx, obj.ID, &result) require.NoError(t, err) assert.True(t, result.IsArchived()) }) t.Run("Unarchive_Success", func(t *testing.T) { obj := &TestArchivableObject{Name: "test", ArchivableBase: model.ArchivableBase{Archived: true}} err := repo.Insert(ctx, obj, nil) require.NoError(t, err) err = archivableDB.Unarchive(ctx, obj.ID) require.NoError(t, err) var result TestArchivableObject err = repo.Get(ctx, obj.ID, &result) require.NoError(t, err) assert.False(t, result.IsArchived()) }) }