mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 02:51:34 +00:00
This commit marks the completion of a major refactoring effort to stabilize the codebase, improve its structure, and prepare it for production. The key changes include: - **Domain Layer Consolidation:** The `Work` entity and its related types, along with all other domain entities and repository interfaces, have been consolidated into the main `internal/domain` package. This eliminates import cycles and provides a single, coherent source of truth for the domain model. - **Data Access Layer Refactoring:** The repository implementations in `internal/data/sql` have been updated to align with the new domain layer. The `BaseRepositoryImpl` has been corrected to use pointer receivers, and all concrete repositories now correctly embed it, ensuring consistent and correct behavior. - **Application Layer Stabilization:** All application services in `internal/app` have been updated to use the new domain types and repository interfaces. Dependency injection has been corrected throughout the application, ensuring that all services are initialized with the correct dependencies. - **GraphQL Adapter Fixes:** The GraphQL resolver implementation in `internal/adapters/graphql` has been updated to correctly handle the new domain types and service methods. The auto-generated GraphQL code has been regenerated to ensure it is in sync with the schema and runtime. - **Test Suite Overhaul:** All test suites have been fixed to correctly implement their respective interfaces and use the updated domain model. Mock repositories and test suites have been corrected to properly embed the `testify` base types, resolving numerous build and linter errors. - **Dependency Management:** The Go modules have been tidied, and the module cache has been cleaned to ensure a consistent and correct dependency graph. - **Code Quality and Verification:** The entire codebase now passes all builds, tests, and linter checks, ensuring a high level of quality and stability. This comprehensive effort has resulted in a more robust, maintainable, and production-ready application.
263 lines
8.1 KiB
Go
263 lines
8.1 KiB
Go
package analytics_test
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"tercul/internal/app/analytics"
|
|
"tercul/internal/data/sql"
|
|
"tercul/internal/domain"
|
|
"tercul/internal/jobs/linguistics"
|
|
"tercul/internal/platform/config"
|
|
"tercul/internal/testutil"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type AnalyticsServiceTestSuite struct {
|
|
testutil.IntegrationTestSuite
|
|
service analytics.Service
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) SetupSuite() {
|
|
s.IntegrationTestSuite.SetupSuite(testutil.DefaultTestConfig())
|
|
cfg, err := config.LoadConfig()
|
|
s.Require().NoError(err)
|
|
analyticsRepo := sql.NewAnalyticsRepository(s.DB, cfg)
|
|
analysisRepo := linguistics.NewGORMAnalysisRepository(s.DB)
|
|
translationRepo := sql.NewTranslationRepository(s.DB, cfg)
|
|
workRepo := sql.NewWorkRepository(s.DB, cfg)
|
|
sentimentProvider, _ := linguistics.NewGoVADERSentimentProvider()
|
|
s.service = analytics.NewService(analyticsRepo, analysisRepo, translationRepo, workRepo, sentimentProvider)
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) SetupTest() {
|
|
s.IntegrationTestSuite.SetupTest()
|
|
s.DB.Exec("DELETE FROM trendings")
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestIncrementWorkViews() {
|
|
s.Run("should increment the view count for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
|
|
// Act
|
|
err := s.service.IncrementWorkViews(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(int64(1), stats.Views)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestIncrementWorkLikes() {
|
|
s.Run("should increment the like count for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
|
|
// Act
|
|
err := s.service.IncrementWorkLikes(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(int64(1), stats.Likes)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestIncrementWorkComments() {
|
|
s.Run("should increment the comment count for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
|
|
// Act
|
|
err := s.service.IncrementWorkComments(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(int64(1), stats.Comments)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestIncrementWorkBookmarks() {
|
|
s.Run("should increment the bookmark count for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
|
|
// Act
|
|
err := s.service.IncrementWorkBookmarks(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(int64(1), stats.Bookmarks)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestIncrementWorkShares() {
|
|
s.Run("should increment the share count for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
|
|
// Act
|
|
err := s.service.IncrementWorkShares(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(int64(1), stats.Shares)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestIncrementWorkTranslationCount() {
|
|
s.Run("should increment the translation count for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
|
|
// Act
|
|
err := s.service.IncrementWorkTranslationCount(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(int64(1), stats.TranslationCount)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestUpdateWorkReadingTime() {
|
|
s.Run("should update the reading time for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
s.DB.Create(&domain.ReadabilityScore{WorkID: work.ID})
|
|
s.DB.Create(&domain.LanguageAnalysis{WorkID: work.ID, Analysis: domain.JSONB{}})
|
|
textMetadata := &domain.TextMetadata{
|
|
WorkID: work.ID,
|
|
WordCount: 1000,
|
|
}
|
|
s.DB.Create(textMetadata)
|
|
|
|
// Act
|
|
err := s.service.UpdateWorkReadingTime(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(5, stats.ReadingTime) // 1000 words / 200 wpm = 5 minutes
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestUpdateTranslationReadingTime() {
|
|
s.Run("should update the reading time for a translation", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
translation := s.CreateTestTranslation(work.ID, "es", strings.Repeat("Contenido de prueba con quinientas palabras. ", 100))
|
|
|
|
// Act
|
|
err := s.service.UpdateTranslationReadingTime(context.Background(), translation.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateTranslationStats(context.Background(), translation.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(3, stats.ReadingTime) // 500 words / 200 wpm = 2.5 -> 3 minutes
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestUpdateWorkComplexity() {
|
|
s.Run("should update the complexity for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
s.DB.Create(&domain.TextMetadata{WorkID: work.ID})
|
|
s.DB.Create(&domain.LanguageAnalysis{WorkID: work.ID, Analysis: domain.JSONB{}})
|
|
readabilityScore := &domain.ReadabilityScore{
|
|
WorkID: work.ID,
|
|
Score: 12.34,
|
|
}
|
|
s.DB.Create(readabilityScore)
|
|
|
|
// Act
|
|
err := s.service.UpdateWorkComplexity(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(12.34, stats.Complexity)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestUpdateWorkSentiment() {
|
|
s.Run("should update the sentiment for a work", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
s.DB.Create(&domain.TextMetadata{WorkID: work.ID})
|
|
s.DB.Create(&domain.ReadabilityScore{WorkID: work.ID})
|
|
languageAnalysis := &domain.LanguageAnalysis{
|
|
WorkID: work.ID,
|
|
Analysis: domain.JSONB{
|
|
"sentiment": 0.5678,
|
|
},
|
|
}
|
|
s.DB.Create(languageAnalysis)
|
|
|
|
// Act
|
|
err := s.service.UpdateWorkSentiment(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateWorkStats(context.Background(), work.ID)
|
|
s.Require().NoError(err)
|
|
s.Equal(0.5678, stats.Sentiment)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestUpdateTranslationSentiment() {
|
|
s.Run("should update the sentiment for a translation", func() {
|
|
// Arrange
|
|
work := s.CreateTestWork("Test Work", "en", "Test content")
|
|
translation := s.CreateTestTranslation(work.ID, "en", "This is a wonderfully positive and uplifting sentence.")
|
|
|
|
// Act
|
|
err := s.service.UpdateTranslationSentiment(context.Background(), translation.ID)
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
stats, err := s.service.GetOrCreateTranslationStats(context.Background(), translation.ID)
|
|
s.Require().NoError(err)
|
|
s.True(stats.Sentiment > 0.5)
|
|
})
|
|
}
|
|
|
|
func (s *AnalyticsServiceTestSuite) TestUpdateTrending() {
|
|
s.Run("should update the trending works", func() {
|
|
// Arrange
|
|
work1 := s.CreateTestWork("Work 1", "en", "content")
|
|
work2 := s.CreateTestWork("Work 2", "en", "content")
|
|
s.DB.Create(&domain.WorkStats{WorkID: work1.ID, Views: 100, Likes: 10, Comments: 1})
|
|
s.DB.Create(&domain.WorkStats{WorkID: work2.ID, Views: 10, Likes: 100, Comments: 10})
|
|
|
|
// Act
|
|
err := s.service.UpdateTrending(context.Background())
|
|
s.Require().NoError(err)
|
|
|
|
// Assert
|
|
var trendingWorks []*domain.Trending
|
|
s.DB.Order("rank asc").Find(&trendingWorks)
|
|
s.Require().Len(trendingWorks, 2)
|
|
s.Equal(work2.ID, trendingWorks[0].EntityID)
|
|
s.Equal(work1.ID, trendingWorks[1].EntityID)
|
|
})
|
|
}
|
|
|
|
func TestAnalyticsService(t *testing.T) {
|
|
suite.Run(t, new(AnalyticsServiceTestSuite))
|
|
} |