mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 05:11:34 +00:00
This commit introduces a new application layer to the codebase, which decouples the GraphQL resolvers from the data layer. The resolvers now call application services, which in turn call the repositories. This change improves the separation of concerns and makes the code more testable and maintainable. Additionally, this commit introduces dataloaders to solve the N+1 problem in the GraphQL resolvers. The dataloaders are used to batch and cache database queries, which significantly improves the performance of the API. The following changes were made: - Created application services for most of the domains. - Refactored the GraphQL resolvers to use the new application services. - Implemented dataloaders for the `Author` aggregate. - Updated the `app.Application` struct to hold the application services instead of the repositories. - Fixed a large number of compilation errors in the test files that arose from these changes. There are still some compilation errors in the `internal/adapters/graphql/integration_test.go` file. These errors are due to the test files still trying to access the repositories directly from the `app.Application` struct. The remaining work is to update these tests to use the new application services.
1491 lines
49 KiB
Go
1491 lines
49 KiB
Go
package testutil
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
graph "tercul/internal/adapters/graphql"
|
|
"tercul/internal/app/auth"
|
|
auth_platform "tercul/internal/platform/auth"
|
|
"tercul/internal/app"
|
|
"tercul/internal/app/copyright"
|
|
"tercul/internal/app/localization"
|
|
"tercul/internal/app/analytics"
|
|
"tercul/internal/app/monetization"
|
|
"tercul/internal/app/search"
|
|
"tercul/internal/app/work"
|
|
"tercul/internal/data/sql"
|
|
"tercul/internal/domain"
|
|
"tercul/internal/jobs/linguistics"
|
|
"github.com/stretchr/testify/mock"
|
|
)
|
|
|
|
type MockWorkRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockUserRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockAuthorRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockCommentRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockLikeRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockBookmarkRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockCollectionRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockTagRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
type MockCategoryRepository struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockLikeRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockCollectionRepository) AddWorkToCollection(ctx context.Context, collectionID uint, workID uint) error {
|
|
args := m.Called(ctx, collectionID, workID)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockTagRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockCategoryRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockLikeRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) Create(ctx context.Context, like *domain.Like) error {
|
|
args := m.Called(ctx, like)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) Create(ctx context.Context, bookmark *domain.Bookmark) error {
|
|
args := m.Called(ctx, bookmark)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) Create(ctx context.Context, tag *domain.Tag) error {
|
|
args := m.Called(ctx, tag)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) Create(ctx context.Context, category *domain.Category) error {
|
|
args := m.Called(ctx, category)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockLikeRepository) Update(ctx context.Context, like *domain.Like) error {
|
|
args := m.Called(ctx, like)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) RemoveWorkFromCollection(ctx context.Context, collectionID uint, workID uint) error {
|
|
args := m.Called(ctx, collectionID, workID)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockTagRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Category) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockLikeRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Like) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) Update(ctx context.Context, collection *domain.Collection) error {
|
|
args := m.Called(ctx, collection)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockLikeRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Collection) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockLikeRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Like) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockLikeRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockLikeRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockLikeRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Like, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Bookmark, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) FindByName(ctx context.Context, name string) (*domain.Tag, error) {
|
|
args := m.Called(ctx, name)
|
|
return args.Get(0).(*domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) FindByName(ctx context.Context, name string) (*domain.Category, error) {
|
|
args := m.Called(ctx, name)
|
|
return args.Get(0).(*domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Like, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Bookmark, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Collection, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Tag, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Category, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) GetByID(ctx context.Context, id uint) (*domain.Like, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) GetByID(ctx context.Context, id uint) (*domain.Bookmark, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Collection, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Tag, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Category, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Like, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Bookmark, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) GetByID(ctx context.Context, id uint) (*domain.Collection, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) GetByID(ctx context.Context, id uint) (*domain.Tag, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) GetByID(ctx context.Context, id uint) (*domain.Category, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Like], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Like]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Bookmark], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Bookmark]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Collection, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Tag, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Category, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) ListAll(ctx context.Context) ([]domain.Like, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) ListAll(ctx context.Context) ([]domain.Bookmark, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Collection], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Collection]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Tag], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Tag]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Category], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Category]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) ListByCommentID(ctx context.Context, commentID uint) ([]domain.Like, error) {
|
|
args := m.Called(ctx, commentID)
|
|
return args.Get(0).([]domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) ListByUserID(ctx context.Context, userID uint) ([]domain.Bookmark, error) {
|
|
args := m.Called(ctx, userID)
|
|
return args.Get(0).([]domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) ListAll(ctx context.Context) ([]domain.Collection, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) ListAll(ctx context.Context) ([]domain.Tag, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) ListAll(ctx context.Context) ([]domain.Category, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) ListByTranslationID(ctx context.Context, translationID uint) ([]domain.Like, error) {
|
|
args := m.Called(ctx, translationID)
|
|
return args.Get(0).([]domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Bookmark, error) {
|
|
args := m.Called(ctx, workID)
|
|
return args.Get(0).([]domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) ListByUserID(ctx context.Context, userID uint) ([]domain.Collection, error) {
|
|
args := m.Called(ctx, userID)
|
|
return args.Get(0).([]domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Tag, error) {
|
|
args := m.Called(ctx, workID)
|
|
return args.Get(0).([]domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) ListByParentID(ctx context.Context, parentID *uint) ([]domain.Category, error) {
|
|
args := m.Called(ctx, parentID)
|
|
return args.Get(0).([]domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) ListByUserID(ctx context.Context, userID uint) ([]domain.Like, error) {
|
|
args := m.Called(ctx, userID)
|
|
return args.Get(0).([]domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Bookmark, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Bookmark), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Collection, error) {
|
|
args := m.Called(ctx, workID)
|
|
return args.Get(0).([]domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Tag, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Tag), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Category, error) {
|
|
args := m.Called(ctx, workID)
|
|
return args.Get(0).([]domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Like, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Bookmark) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Collection, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Tag) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) Update(ctx context.Context, category *domain.Category) error {
|
|
args := m.Called(ctx, category)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockLikeRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Like, error) {
|
|
args := m.Called(ctx, workID)
|
|
return args.Get(0).([]domain.Like), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) Update(ctx context.Context, bookmark *domain.Bookmark) error {
|
|
args := m.Called(ctx, bookmark)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) ListPublic(ctx context.Context) ([]domain.Collection, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Collection), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) Update(ctx context.Context, tag *domain.Tag) error {
|
|
args := m.Called(ctx, tag)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Category, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Category), args.Error(1)
|
|
}
|
|
|
|
func (m *MockLikeRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockTagRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockTagRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Collection) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockTagRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Bookmark) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) Create(ctx context.Context, collection *domain.Collection) error {
|
|
args := m.Called(ctx, collection)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockTagRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Tag) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Category) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockTagRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockBookmarkRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCollectionRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockTagRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCategoryRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) Reset() {
|
|
m.Mock = mock.Mock{}
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) AddWork(work *domain.Work) {
|
|
// Not implemented for mock
|
|
}
|
|
|
|
func (m *MockCommentRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockCommentRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) Create(ctx context.Context, comment *domain.Comment) error {
|
|
args := m.Called(ctx, comment)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCommentRepository) GetByID(ctx context.Context, id uint) (*domain.Comment, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) Update(ctx context.Context, comment *domain.Comment) error {
|
|
args := m.Called(ctx, comment)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCommentRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCommentRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Comment], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Comment]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Comment, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) ListAll(ctx context.Context) ([]domain.Comment, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Comment, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Comment, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockCommentRepository) ListByUserID(ctx context.Context, userID uint) ([]domain.Comment, error) {
|
|
args := m.Called(ctx, userID)
|
|
return args.Get(0).([]domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Comment, error) {
|
|
args := m.Called(ctx, workID)
|
|
return args.Get(0).([]domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) ListByTranslationID(ctx context.Context, translationID uint) ([]domain.Comment, error) {
|
|
args := m.Called(ctx, translationID)
|
|
return args.Get(0).([]domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) ListByParentID(ctx context.Context, parentID uint) ([]domain.Comment, error) {
|
|
args := m.Called(ctx, parentID)
|
|
return args.Get(0).([]domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Comment, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Comment), args.Error(1)
|
|
}
|
|
|
|
func (m *MockCommentRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Comment) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCommentRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Comment) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockCommentRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockAuthorRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) Create(ctx context.Context, author *domain.Author) error {
|
|
args := m.Called(ctx, author)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) GetByID(ctx context.Context, id uint) (*domain.Author, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) Update(ctx context.Context, author *domain.Author) error {
|
|
args := m.Called(ctx, author)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Author], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Author]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Author, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) ListAll(ctx context.Context) ([]domain.Author, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Author, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Author, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Author, error) {
|
|
args := m.Called(ctx, workID)
|
|
return args.Get(0).([]domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) ListByBookID(ctx context.Context, bookID uint) ([]domain.Author, error) {
|
|
args := m.Called(ctx, bookID)
|
|
return args.Get(0).([]domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) ListByCountryID(ctx context.Context, countryID uint) ([]domain.Author, error) {
|
|
args := m.Called(ctx, countryID)
|
|
return args.Get(0).([]domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) GetByIDs(ctx context.Context, ids []uint) ([]domain.Author, error) {
|
|
args := m.Called(ctx, ids)
|
|
return args.Get(0).([]domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Author, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Author), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Author) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Author) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockAuthorRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockUserRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *MockUserRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) Create(ctx context.Context, user *domain.User) error {
|
|
args := m.Called(ctx, user)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockUserRepository) GetByID(ctx context.Context, id uint) (*domain.User, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) Update(ctx context.Context, user *domain.User) error {
|
|
args := m.Called(ctx, user)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockUserRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockUserRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.User], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.User]), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.User, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) ListAll(ctx context.Context) ([]domain.User, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.User, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.User, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *MockUserRepository) FindByUsername(ctx context.Context, username string) (*domain.User, error) {
|
|
args := m.Called(ctx, username)
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) FindByEmail(ctx context.Context, email string) (*domain.User, error) {
|
|
args := m.Called(ctx, email)
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) ListByRole(ctx context.Context, role domain.UserRole) ([]domain.User, error) {
|
|
args := m.Called(ctx, role)
|
|
return args.Get(0).([]domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) GetByIDs(ctx context.Context, ids []uint) ([]domain.User, error) {
|
|
args := m.Called(ctx, ids)
|
|
return args.Get(0).([]domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.User, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.User), args.Error(1)
|
|
}
|
|
|
|
func (m *MockUserRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.User) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockUserRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.User) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockUserRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
type UnifiedMockWorkRepository struct {
|
|
mock.Mock
|
|
MockWorkRepository
|
|
}
|
|
|
|
// IntegrationTestSuite provides a comprehensive test environment with either in-memory SQLite or mock repositories
|
|
type IntegrationTestSuite struct {
|
|
suite.Suite
|
|
App *app.Application
|
|
DB *gorm.DB
|
|
WorkRepo domain.WorkRepository
|
|
UserRepo domain.UserRepository
|
|
AuthorRepo domain.AuthorRepository
|
|
TranslationRepo domain.TranslationRepository
|
|
CommentRepo domain.CommentRepository
|
|
LikeRepo domain.LikeRepository
|
|
BookmarkRepo domain.BookmarkRepository
|
|
CollectionRepo domain.CollectionRepository
|
|
TagRepo domain.TagRepository
|
|
CategoryRepo domain.CategoryRepository
|
|
BookRepo domain.BookRepository
|
|
MonetizationRepo domain.MonetizationRepository
|
|
PublisherRepo domain.PublisherRepository
|
|
SourceRepo domain.SourceRepository
|
|
CopyrightRepo domain.CopyrightRepository
|
|
AnalyticsRepo domain.AnalyticsRepository
|
|
AnalysisRepo linguistics.AnalysisRepository
|
|
// Services
|
|
WorkCommands *work.WorkCommands
|
|
WorkQueries *work.WorkQueries
|
|
Localization localization.Service
|
|
AuthCommands *auth.AuthCommands
|
|
AuthQueries *auth.AuthQueries
|
|
AnalyticsService analytics.Service
|
|
|
|
// Test data
|
|
TestWorks []*domain.Work
|
|
TestUsers []*domain.User
|
|
TestAuthors []*domain.Author
|
|
TestTranslations []*domain.Translation
|
|
}
|
|
|
|
// TestConfig holds configuration for the test environment
|
|
type TestConfig struct {
|
|
UseInMemoryDB bool // If true, use SQLite in-memory, otherwise use mock repositories
|
|
DBPath string // Path for SQLite file (only used if UseInMemoryDB is false)
|
|
LogLevel logger.LogLevel
|
|
}
|
|
|
|
// DefaultTestConfig returns a default test configuration
|
|
func DefaultTestConfig() *TestConfig {
|
|
return &TestConfig{
|
|
UseInMemoryDB: true,
|
|
DBPath: "",
|
|
LogLevel: logger.Silent,
|
|
}
|
|
}
|
|
|
|
// SetupSuite sets up the test suite with the specified configuration
|
|
func (s *IntegrationTestSuite) SetupSuite(config *TestConfig) {
|
|
if config == nil {
|
|
config = DefaultTestConfig()
|
|
}
|
|
|
|
if config.UseInMemoryDB {
|
|
s.setupInMemoryDB(config)
|
|
} else {
|
|
s.setupMockRepositories()
|
|
}
|
|
|
|
s.setupServices()
|
|
s.setupTestData()
|
|
}
|
|
|
|
// setupInMemoryDB sets up an in-memory SQLite database for testing
|
|
func (s *IntegrationTestSuite) setupInMemoryDB(config *TestConfig) {
|
|
var dbPath string
|
|
if config.DBPath != "" {
|
|
// Ensure directory exists
|
|
dir := filepath.Dir(config.DBPath)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
s.T().Fatalf("Failed to create database directory: %v", err)
|
|
}
|
|
dbPath = config.DBPath
|
|
} else {
|
|
// Use in-memory database
|
|
dbPath = ":memory:"
|
|
}
|
|
|
|
// Custom logger for tests
|
|
newLogger := logger.New(
|
|
log.New(os.Stdout, "\r\n", log.LstdFlags),
|
|
logger.Config{
|
|
SlowThreshold: time.Second,
|
|
LogLevel: config.LogLevel,
|
|
IgnoreRecordNotFoundError: true,
|
|
Colorful: false,
|
|
},
|
|
)
|
|
|
|
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
|
Logger: newLogger,
|
|
})
|
|
if err != nil {
|
|
s.T().Fatalf("Failed to connect to test database: %v", err)
|
|
}
|
|
|
|
s.DB = db
|
|
|
|
// Run migrations
|
|
if err := db.AutoMigrate(
|
|
&domain.Work{},
|
|
&domain.User{},
|
|
&domain.Author{},
|
|
&domain.Translation{},
|
|
&domain.Comment{},
|
|
&domain.Like{},
|
|
&domain.Bookmark{},
|
|
&domain.Collection{},
|
|
&domain.Tag{},
|
|
&domain.Category{},
|
|
&domain.Country{},
|
|
&domain.City{},
|
|
&domain.Place{},
|
|
&domain.Address{},
|
|
&domain.Copyright{},
|
|
&domain.CopyrightClaim{},
|
|
&domain.Monetization{},
|
|
&domain.Book{},
|
|
&domain.Publisher{},
|
|
&domain.Source{},
|
|
&domain.WorkCopyright{},
|
|
&domain.AuthorCopyright{},
|
|
&domain.BookCopyright{},
|
|
&domain.PublisherCopyright{},
|
|
&domain.SourceCopyright{},
|
|
&domain.WorkMonetization{},
|
|
&domain.AuthorMonetization{},
|
|
&domain.BookMonetization{},
|
|
&domain.PublisherMonetization{},
|
|
&domain.SourceMonetization{},
|
|
&domain.WorkStats{},
|
|
&domain.TranslationStats{},
|
|
// &domain.WorkAnalytics{}, // Commented out as it's not in models package
|
|
&domain.ReadabilityScore{},
|
|
&domain.WritingStyle{},
|
|
&domain.Emotion{},
|
|
&domain.TopicCluster{},
|
|
&domain.Mood{},
|
|
&domain.Concept{},
|
|
&domain.LinguisticLayer{},
|
|
&domain.WorkStats{},
|
|
&domain.TranslationStats{},
|
|
&domain.UserEngagement{},
|
|
&domain.Trending{},
|
|
&domain.TextMetadata{},
|
|
&domain.PoeticAnalysis{},
|
|
&domain.LanguageAnalysis{},
|
|
&domain.TranslationField{},
|
|
&TestEntity{}, // Add TestEntity for generic repository tests
|
|
); err != nil {
|
|
s.T().Fatalf("Failed to run migrations: %v", err)
|
|
}
|
|
|
|
// Create repository instances
|
|
s.WorkRepo = sql.NewWorkRepository(db)
|
|
s.UserRepo = sql.NewUserRepository(db)
|
|
s.AuthorRepo = sql.NewAuthorRepository(db)
|
|
s.TranslationRepo = sql.NewTranslationRepository(db)
|
|
s.CommentRepo = sql.NewCommentRepository(db)
|
|
s.LikeRepo = sql.NewLikeRepository(db)
|
|
s.BookmarkRepo = sql.NewBookmarkRepository(db)
|
|
s.CollectionRepo = sql.NewCollectionRepository(db)
|
|
s.TagRepo = sql.NewTagRepository(db)
|
|
s.CategoryRepo = sql.NewCategoryRepository(db)
|
|
s.BookRepo = sql.NewBookRepository(db)
|
|
s.MonetizationRepo = sql.NewMonetizationRepository(db)
|
|
s.PublisherRepo = sql.NewPublisherRepository(db)
|
|
s.SourceRepo = sql.NewSourceRepository(db)
|
|
s.CopyrightRepo = sql.NewCopyrightRepository(db)
|
|
s.AnalyticsRepo = sql.NewAnalyticsRepository(db)
|
|
s.AnalysisRepo = linguistics.NewGORMAnalysisRepository(db)
|
|
}
|
|
|
|
// setupMockRepositories sets up mock repositories for testing
|
|
func (s *IntegrationTestSuite) setupMockRepositories() {
|
|
s.WorkRepo = NewUnifiedMockWorkRepository()
|
|
s.UserRepo = NewMockUserRepository()
|
|
s.AuthorRepo = NewMockAuthorRepository()
|
|
s.TranslationRepo = NewMockTranslationRepository()
|
|
s.CommentRepo = NewMockCommentRepository()
|
|
s.LikeRepo = NewMockLikeRepository()
|
|
s.BookmarkRepo = NewMockBookmarkRepository()
|
|
s.CollectionRepo = NewMockCollectionRepository()
|
|
s.TagRepo = NewMockTagRepository()
|
|
s.CategoryRepo = NewMockCategoryRepository()
|
|
}
|
|
|
|
// Mock repository constructors
|
|
func NewMockUserRepository() *MockUserRepository {
|
|
return &MockUserRepository{}
|
|
}
|
|
|
|
func NewMockAuthorRepository() *MockAuthorRepository {
|
|
return &MockAuthorRepository{}
|
|
}
|
|
|
|
func NewMockCommentRepository() *MockCommentRepository {
|
|
return &MockCommentRepository{}
|
|
}
|
|
|
|
func NewMockLikeRepository() *MockLikeRepository {
|
|
return &MockLikeRepository{}
|
|
}
|
|
|
|
func NewMockBookmarkRepository() *MockBookmarkRepository {
|
|
return &MockBookmarkRepository{}
|
|
}
|
|
|
|
func NewMockCollectionRepository() *MockCollectionRepository {
|
|
return &MockCollectionRepository{}
|
|
}
|
|
|
|
func NewMockTagRepository() *MockTagRepository {
|
|
return &MockTagRepository{}
|
|
}
|
|
|
|
func NewMockCategoryRepository() *MockCategoryRepository {
|
|
return &MockCategoryRepository{}
|
|
}
|
|
|
|
func NewUnifiedMockWorkRepository() *UnifiedMockWorkRepository {
|
|
return &UnifiedMockWorkRepository{}
|
|
}
|
|
|
|
// setupServices sets up service instances
|
|
func (s *IntegrationTestSuite) setupServices() {
|
|
mockAnalyzer := &MockAnalyzer{}
|
|
s.WorkCommands = work.NewWorkCommands(s.WorkRepo, mockAnalyzer)
|
|
s.WorkQueries = work.NewWorkQueries(s.WorkRepo)
|
|
s.Localization = localization.NewService(s.TranslationRepo)
|
|
jwtManager := auth_platform.NewJWTManager()
|
|
s.AuthCommands = auth.NewAuthCommands(s.UserRepo, jwtManager)
|
|
s.AuthQueries = auth.NewAuthQueries(s.UserRepo, jwtManager)
|
|
sentimentProvider, _ := linguistics.NewGoVADERSentimentProvider()
|
|
s.AnalyticsService = analytics.NewService(s.AnalyticsRepo, s.AnalysisRepo, s.TranslationRepo, s.WorkRepo, sentimentProvider)
|
|
|
|
copyrightCommands := copyright.NewCopyrightCommands(s.CopyrightRepo)
|
|
copyrightQueries := copyright.NewCopyrightQueries(s.CopyrightRepo, s.WorkRepo, s.AuthorRepo, s.BookRepo, s.PublisherRepo, s.SourceRepo)
|
|
|
|
monetizationCommands := monetization.NewMonetizationCommands(s.MonetizationRepo)
|
|
monetizationQueries := monetization.NewMonetizationQueries(s.MonetizationRepo, s.WorkRepo, s.AuthorRepo, s.BookRepo, s.PublisherRepo, s.SourceRepo)
|
|
|
|
s.App = &app.Application{
|
|
AnalyticsService: s.AnalyticsService,
|
|
WorkCommands: s.WorkCommands,
|
|
WorkQueries: s.WorkQueries,
|
|
AuthCommands: s.AuthCommands,
|
|
AuthQueries: s.AuthQueries,
|
|
CopyrightCommands: copyrightCommands,
|
|
CopyrightQueries: copyrightQueries,
|
|
Localization: s.Localization,
|
|
Search: search.NewIndexService(s.Localization, &MockWeaviateWrapper{}),
|
|
MonetizationCommands: monetizationCommands,
|
|
MonetizationQueries: monetizationQueries,
|
|
}
|
|
}
|
|
|
|
// setupTestData creates initial test data
|
|
func (s *IntegrationTestSuite) setupTestData() {
|
|
// Create test users
|
|
s.TestUsers = []*domain.User{
|
|
{Username: "testuser1", Email: "test1@example.com", FirstName: "Test", LastName: "User1"},
|
|
{Username: "testuser2", Email: "test2@example.com", FirstName: "Test", LastName: "User2"},
|
|
}
|
|
|
|
for _, user := range s.TestUsers {
|
|
if err := s.UserRepo.Create(context.Background(), user); err != nil {
|
|
s.T().Logf("Warning: Failed to create test user: %v", err)
|
|
}
|
|
}
|
|
|
|
// Create test authors
|
|
s.TestAuthors = []*domain.Author{
|
|
{Name: "Test Author 1", TranslatableModel: domain.TranslatableModel{Language: "en"}},
|
|
{Name: "Test Author 2", TranslatableModel: domain.TranslatableModel{Language: "fr"}},
|
|
}
|
|
|
|
for _, author := range s.TestAuthors {
|
|
if err := s.AuthorRepo.Create(context.Background(), author); err != nil {
|
|
s.T().Logf("Warning: Failed to create test author: %v", err)
|
|
}
|
|
}
|
|
|
|
// Create test works
|
|
s.TestWorks = []*domain.Work{
|
|
{Title: "Test Work 1", TranslatableModel: domain.TranslatableModel{Language: "en"}},
|
|
{Title: "Test Work 2", TranslatableModel: domain.TranslatableModel{Language: "en"}},
|
|
{Title: "Test Work 3", TranslatableModel: domain.TranslatableModel{Language: "fr"}},
|
|
}
|
|
|
|
for _, work := range s.TestWorks {
|
|
if err := s.WorkRepo.Create(context.Background(), work); err != nil {
|
|
s.T().Logf("Warning: Failed to create test work: %v", err)
|
|
}
|
|
}
|
|
|
|
// Create test translations
|
|
s.TestTranslations = []*domain.Translation{
|
|
{
|
|
Title: "Test Work 1",
|
|
Content: "Test content for work 1",
|
|
Language: "en",
|
|
TranslatableID: s.TestWorks[0].ID,
|
|
TranslatableType: "Work",
|
|
IsOriginalLanguage: true,
|
|
},
|
|
{
|
|
Title: "Test Work 2",
|
|
Content: "Test content for work 2",
|
|
Language: "en",
|
|
TranslatableID: s.TestWorks[1].ID,
|
|
TranslatableType: "Work",
|
|
IsOriginalLanguage: true,
|
|
},
|
|
{
|
|
Title: "Test Work 3",
|
|
Content: "Test content for work 3",
|
|
Language: "fr",
|
|
TranslatableID: s.TestWorks[2].ID,
|
|
TranslatableType: "Work",
|
|
IsOriginalLanguage: true,
|
|
},
|
|
}
|
|
|
|
for _, translation := range s.TestTranslations {
|
|
if err := s.TranslationRepo.Create(context.Background(), translation); err != nil {
|
|
s.T().Logf("Warning: Failed to create test translation: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TearDownSuite cleans up the test suite
|
|
func (s *IntegrationTestSuite) TearDownSuite() {
|
|
if s.DB != nil {
|
|
sqlDB, err := s.DB.DB()
|
|
if err == nil {
|
|
sqlDB.Close()
|
|
}
|
|
}
|
|
}
|
|
|
|
// SetupTest resets test data for each test
|
|
func (s *IntegrationTestSuite) SetupTest() {
|
|
if s.DB != nil {
|
|
// Reset database for each test
|
|
s.DB.Exec("DELETE FROM translations")
|
|
s.DB.Exec("DELETE FROM works")
|
|
s.DB.Exec("DELETE FROM authors")
|
|
s.DB.Exec("DELETE FROM users")
|
|
s.DB.Exec("DELETE FROM trendings")
|
|
s.DB.Exec("DELETE FROM work_stats")
|
|
s.DB.Exec("DELETE FROM translation_stats")
|
|
} else {
|
|
// Reset mock repositories
|
|
if mockRepo, ok := s.WorkRepo.(*UnifiedMockWorkRepository); ok {
|
|
mockRepo.Reset()
|
|
}
|
|
// Add similar reset logic for other mock repositories
|
|
}
|
|
}
|
|
|
|
// GetResolver returns a properly configured GraphQL resolver for testing
|
|
func (s *IntegrationTestSuite) GetResolver() *graph.Resolver {
|
|
return &graph.Resolver{
|
|
App: s.App,
|
|
}
|
|
}
|
|
|
|
// CreateTestWork creates a test work with optional content
|
|
func (s *IntegrationTestSuite) CreateTestWork(title, language string, content string) *domain.Work {
|
|
work := &domain.Work{
|
|
Title: title,
|
|
TranslatableModel: domain.TranslatableModel{Language: language},
|
|
}
|
|
|
|
if err := s.WorkRepo.Create(context.Background(), work); err != nil {
|
|
s.T().Fatalf("Failed to create test work: %v", err)
|
|
}
|
|
|
|
if content != "" {
|
|
translation := &domain.Translation{
|
|
Title: title,
|
|
Content: content,
|
|
Language: language,
|
|
TranslatableID: work.ID,
|
|
TranslatableType: "Work",
|
|
IsOriginalLanguage: true,
|
|
}
|
|
|
|
if err := s.TranslationRepo.Create(context.Background(), translation); err != nil {
|
|
s.T().Logf("Warning: Failed to create test translation: %v", err)
|
|
}
|
|
}
|
|
|
|
return work
|
|
}
|
|
|
|
// CleanupTestData removes all test data
|
|
func (s *IntegrationTestSuite) CleanupTestData() {
|
|
if s.DB != nil {
|
|
s.DB.Exec("DELETE FROM translations")
|
|
s.DB.Exec("DELETE FROM works")
|
|
s.DB.Exec("DELETE FROM authors")
|
|
s.DB.Exec("DELETE FROM users")
|
|
}
|
|
}
|
|
|
|
// CreateAuthenticatedUser creates a user and returns the user and an auth token
|
|
func (s *IntegrationTestSuite) CreateAuthenticatedUser(username, email string, role domain.UserRole) (*domain.User, string) {
|
|
user := &domain.User{
|
|
Username: username,
|
|
Email: email,
|
|
Role: role,
|
|
Password: "password", // Not used for token generation, but good to have
|
|
}
|
|
err := s.UserRepo.Create(context.Background(), user)
|
|
s.Require().NoError(err)
|
|
|
|
jwtManager := auth_platform.NewJWTManager()
|
|
token, err := jwtManager.GenerateToken(user)
|
|
s.Require().NoError(err)
|
|
|
|
return user, token
|
|
}
|
|
|
|
// CreateTestTranslation creates a test translation for a work
|
|
func (s *IntegrationTestSuite) CreateTestTranslation(workID uint, language, content string) *domain.Translation {
|
|
translation := &domain.Translation{
|
|
Title: "Test Translation",
|
|
Content: content,
|
|
Language: language,
|
|
TranslatableID: workID,
|
|
TranslatableType: "Work",
|
|
}
|
|
err := s.TranslationRepo.Create(context.Background(), translation)
|
|
s.Require().NoError(err)
|
|
return translation
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) GetByIDs(ctx context.Context, ids []uint) ([]domain.Work, error) {
|
|
args := m.Called(ctx, ids)
|
|
return args.Get(0).([]domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) BeginTx(ctx context.Context) (*gorm.DB, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) Count(ctx context.Context) (int64, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).(int64), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) Create(ctx context.Context, work *domain.Work) error {
|
|
args := m.Called(ctx, work)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) GetByID(ctx context.Context, id uint) (*domain.Work, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) Update(ctx context.Context, work *domain.Work) error {
|
|
args := m.Called(ctx, work)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) Delete(ctx context.Context, id uint) error {
|
|
args := m.Called(ctx, id)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Work], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Work]), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Work, error) {
|
|
args := m.Called(ctx, options)
|
|
return args.Get(0).([]domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) ListAll(ctx context.Context) ([]domain.Work, error) {
|
|
args := m.Called(ctx)
|
|
return args.Get(0).([]domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Work, error) {
|
|
args := m.Called(ctx, preloads, id)
|
|
return args.Get(0).(*domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Work, error) {
|
|
args := m.Called(ctx, batchSize, offset)
|
|
return args.Get(0).([]domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Bool(0), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
|
return fn(nil)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) FindByTitle(ctx context.Context, title string) ([]domain.Work, error) {
|
|
args := m.Called(ctx, title)
|
|
return args.Get(0).([]domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) FindByAuthor(ctx context.Context, authorID uint) ([]domain.Work, error) {
|
|
args := m.Called(ctx, authorID)
|
|
return args.Get(0).([]domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) FindByCategory(ctx context.Context, categoryID uint) ([]domain.Work, error) {
|
|
args := m.Called(ctx, categoryID)
|
|
return args.Get(0).([]domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) FindByLanguage(ctx context.Context, language string, page, pageSize int) (*domain.PaginatedResult[domain.Work], error) {
|
|
args := m.Called(ctx, language, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Work]), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) GetWithTranslations(ctx context.Context, id uint) (*domain.Work, error) {
|
|
args := m.Called(ctx, id)
|
|
return args.Get(0).(*domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) ListWithTranslations(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Work], error) {
|
|
args := m.Called(ctx, page, pageSize)
|
|
return args.Get(0).(*domain.PaginatedResult[domain.Work]), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) GetByIDWithOptions(ctx context.Context, id uint, options *domain.QueryOptions) (*domain.Work, error) {
|
|
args := m.Called(ctx, id, options)
|
|
return args.Get(0).(*domain.Work), args.Error(1)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) CreateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Work) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) UpdateInTx(ctx context.Context, tx *gorm.DB, entity *domain.Work) error {
|
|
args := m.Called(ctx, tx, entity)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *UnifiedMockWorkRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uint) error {
|
|
args := m.Called(ctx, tx, id)
|
|
return args.Error(0)
|
|
}
|