leaf/repository_test.go
2024-01-12 12:20:15 +03:00

196 lines
6.0 KiB
Go

package leaf
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
)
type tModel struct {
Name string `bson:"name"`
Base `bson:",inline"`
}
func tModelToBSON(model *tModel) bson.D {
raw, _ := bson.Marshal(model)
var doc bson.D
bson.Unmarshal(raw, &doc)
return doc
}
func tModelsToBSON(models []*tModel) []bson.D {
docs := make([]bson.D, len(models))
for i := range models {
docs[i] = tModelToBSON(models[i])
}
return docs
}
func TestRepository_Find(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
ctx := context.Background()
mt.Run("returns data on success", func(mt *mtest.T) {
data := []*tModel{{Name: "test1"}, {Name: "test2"}}
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
mt.AddMockResponses(mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch, tModelsToBSON(data)...))
result, err := repo.Find(ctx, bson.M{})
assert.Nil(mt, err)
assert.Equal(mt, data, result)
})
}
func TestRepository_FindOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
ctx := context.Background()
mt.Run("returns data on success", func(mt *mtest.T) {
data := &tModel{Name: "test"}
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
mt.AddMockResponses((mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch, tModelToBSON(data))))
result, err := repo.FindOne(ctx, bson.M{"name": "test"})
assert.Nil(t, err)
assert.Equal(t, data, result)
})
mt.Run("returns error on failure", func(mt *mtest.T) {
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
mt.AddMockResponses((mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch)))
_, err := repo.FindOne(ctx, bson.M{"name": "test"})
assert.NotNil(t, err)
})
}
func TestRepository_FindByID(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
ctx := context.Background()
mt.Run("returns data on success", func(mt *mtest.T) {
data := &tModel{Base: Base{ObjectID: primitive.NewObjectID()}, Name: "test"}
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
mt.AddMockResponses(mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch, tModelToBSON(data)))
result, err := repo.FindByID(ctx, data.ID().Hex())
assert.Nil(t, err)
assert.Equal(t, data, result)
})
mt.Run("returns error on failure", func(mt *mtest.T) {
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
mt.AddMockResponses(mtest.CreateCursorResponse(0, "test.foo", mtest.FirstBatch))
_, err := repo.FindByID(ctx, "invalid")
assert.NotNil(t, err)
})
}
func TestRepository_Create(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
ctx := context.Background()
mt.Run("creates a new document successfully", func(mt *mtest.T) {
data := &tModel{Name: "test"}
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
mt.AddMockResponses(mtest.CreateSuccessResponse())
result, err := repo.Create(ctx, data)
assert.Nil(t, err)
assert.NotEmpty(t, result.ObjectID)
assert.WithinDuration(t, time.Now(), result.CreatedAt, time.Second)
assert.WithinDuration(t, time.Now(), result.UpdatedAt, time.Second)
})
mt.Run("returns error on failure", func(mt *mtest.T) {
data := &tModel{Name: "test"}
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
errResponse := mtest.CreateWriteErrorsResponse(mtest.WriteError{Index: 0, Code: 11000, Message: "duplicate key error"})
mt.AddMockResponses(errResponse)
_, err := repo.Create(ctx, data)
assert.NotNil(t, err)
})
}
func TestRepository_UpdateOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
ctx := context.Background()
mt.Run("updates a document successfully", func(mt *mtest.T) {
data := &tModel{Name: "test"}
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
successResponse := mtest.CreateSuccessResponse(
bson.E{Key: "n", Value: 1},
bson.E{Key: "nModified", Value: 1},
)
mt.AddMockResponses(successResponse)
result, err := repo.UpdateOne(ctx, bson.M{"name": "test"}, data)
assert.Nil(t, err)
assert.Equal(t, data, result)
assert.WithinDuration(t, time.Now(), result.UpdatedAt, time.Second)
})
mt.Run("returns error on failure", func(mt *mtest.T) {
data := &tModel{Name: "test"}
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
errResponse := mtest.CreateWriteErrorsResponse(mtest.WriteError{Index: 0, Code: 11000, Message: "duplicate key error"})
mt.AddMockResponses(errResponse)
_, err := repo.UpdateOne(ctx, bson.M{"name": "test"}, data)
assert.NotNil(t, err)
})
}
func TestRepository_DeleteOne(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
ctx := context.Background()
mt.Run("deletes a document successfully", func(mt *mtest.T) {
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
successResponse := mtest.CreateSuccessResponse(
bson.E{Key: "n", Value: 1},
)
mt.AddMockResponses(successResponse)
err := repo.DeleteOne(ctx, bson.M{"name": "test"})
assert.Nil(t, err)
})
mt.Run("returns error on failure", func(mt *mtest.T) {
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
errResponse := mtest.CreateWriteErrorsResponse(mtest.WriteError{Index: 0, Code: 11000, Message: "delete error"})
mt.AddMockResponses(errResponse)
err := repo.DeleteOne(ctx, bson.M{"name": "test"})
assert.NotNil(t, err)
})
}
func TestRepository_CountDocuments(t *testing.T) {
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
ctx := context.Background()
mt.Run("returns count on success", func(mt *mtest.T) {
repo := NewRepository[*tModel](mt.Coll, []mongo.IndexModel{})
mt.AddMockResponses(mtest.CreateCursorResponse(1, "test.foo", mtest.FirstBatch, bson.D{bson.E{Key: "n", Value: 2}}))
count, err := repo.CountDocuments(ctx, bson.M{"name": "test"})
assert.Nil(t, err)
assert.Equal(t, 2, count)
})
}