- Tests complets pour frontend_log_handler.go (12 tests)
- Tests couvrent NewFrontendLogHandler et ReceiveLog
- Tests pour tous les niveaux de log (DEBUG, INFO, WARN, ERROR)
- Tests pour gestion des erreurs et validation JSON
- Couverture actuelle: 30.6% (objectif: 80%)
Files: veza-backend-api/internal/handlers/frontend_log_handler_test.go
VEZA_ROADMAP.json
Hours: 16 estimated, 23 actual
179 lines
5.1 KiB
Go
179 lines
5.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"veza-backend-api/internal/services"
|
|
"veza-backend-api/internal/types"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// MockAnalyticsService implements AnalyticsServiceInterface
|
|
type MockAnalyticsService struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockAnalyticsService) RecordPlay(ctx context.Context, trackID uuid.UUID, userID *uuid.UUID, duration int, device, ipAddress string) error {
|
|
args := m.Called(ctx, trackID, userID, duration, device, ipAddress)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockAnalyticsService) GetTrackStats(ctx context.Context, trackID uuid.UUID) (*types.TrackStats, error) {
|
|
args := m.Called(ctx, trackID)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*types.TrackStats), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAnalyticsService) GetTopTracks(ctx context.Context, limit int, startDate, endDate *time.Time) ([]services.TopTrack, error) {
|
|
args := m.Called(ctx, limit, startDate, endDate)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).([]services.TopTrack), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAnalyticsService) GetPlaysOverTime(ctx context.Context, trackID uuid.UUID, startDate, endDate time.Time, interval string) ([]services.PlayTimePoint, error) {
|
|
args := m.Called(ctx, trackID, startDate, endDate, interval)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).([]services.PlayTimePoint), args.Error(1)
|
|
}
|
|
|
|
func (m *MockAnalyticsService) GetUserStats(ctx context.Context, userID uuid.UUID) (*types.UserStats, error) {
|
|
args := m.Called(ctx, userID)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*types.UserStats), args.Error(1)
|
|
}
|
|
|
|
// MockAnalyticsJobWorker implements AnalyticsJobWorkerInterface
|
|
type MockAnalyticsJobWorker struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockAnalyticsJobWorker) EnqueueAnalyticsJob(eventName string, userID *uuid.UUID, payload map[string]interface{}) {
|
|
m.Called(eventName, userID, payload)
|
|
}
|
|
|
|
func setupTestAnalyticsHandler(t *testing.T) (*AnalyticsHandler, *MockAnalyticsService, *MockAnalyticsJobWorker) {
|
|
mockService := new(MockAnalyticsService)
|
|
mockJobWorker := new(MockAnalyticsJobWorker)
|
|
logger := zap.NewNop()
|
|
|
|
handler := NewAnalyticsHandlerWithInterface(mockService, logger)
|
|
handler.SetJobWorker(mockJobWorker)
|
|
|
|
return handler, mockService, mockJobWorker
|
|
}
|
|
|
|
func TestRecordPlay_Success(t *testing.T) {
|
|
handler, mockService, _ := setupTestAnalyticsHandler(t)
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
trackID := uuid.New()
|
|
c.Params = []gin.Param{{Key: "id", Value: trackID.String()}}
|
|
|
|
reqBody := RecordPlayRequest{
|
|
Duration: 120,
|
|
Device: "mobile",
|
|
}
|
|
jsonBytes, _ := json.Marshal(reqBody)
|
|
req, _ := http.NewRequest("POST", "/analytics/play/"+trackID.String(), bytes.NewBuffer(jsonBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
c.Request = req
|
|
|
|
userID := uuid.New()
|
|
c.Set("user_id", userID)
|
|
|
|
mockService.On("RecordPlay", mock.Anything, trackID, mock.AnythingOfType("*uuid.UUID"), 120, "mobile", mock.Anything).Return(nil)
|
|
|
|
handler.RecordPlay(c)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestGetTrackStats_Success(t *testing.T) {
|
|
handler, mockService, _ := setupTestAnalyticsHandler(t)
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
trackID := uuid.New()
|
|
c.Params = []gin.Param{{Key: "id", Value: trackID.String()}}
|
|
|
|
req, _ := http.NewRequest("GET", "/analytics/track/"+trackID.String()+"/stats", nil)
|
|
c.Request = req
|
|
|
|
expectedStats := &types.TrackStats{
|
|
TotalPlays: 100,
|
|
UniqueListeners: 50,
|
|
}
|
|
mockService.On("GetTrackStats", mock.Anything, trackID).Return(expectedStats, nil)
|
|
|
|
handler.GetTrackStats(c)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
// Unmarshal wrapper
|
|
var respWrapper struct {
|
|
Success bool `json:"success"`
|
|
Data struct {
|
|
Stats types.TrackStats `json:"stats"` // Handler wraps stats in gin.H{"stats": stats}
|
|
} `json:"data"`
|
|
}
|
|
err := json.Unmarshal(w.Body.Bytes(), &respWrapper)
|
|
assert.NoError(t, err)
|
|
assert.True(t, respWrapper.Success)
|
|
assert.Equal(t, int64(100), respWrapper.Data.Stats.TotalPlays)
|
|
|
|
mockService.AssertExpectations(t)
|
|
}
|
|
|
|
func TestRecordEvent_Success(t *testing.T) {
|
|
handler, _, mockJobWorker := setupTestAnalyticsHandler(t)
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
|
|
reqBody := RecordEventRequest{
|
|
EventName: "custom_event",
|
|
Payload: map[string]interface{}{"foo": "bar"},
|
|
}
|
|
jsonBytes, _ := json.Marshal(reqBody)
|
|
req, _ := http.NewRequest("POST", "/analytics/events", bytes.NewBuffer(jsonBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
c.Request = req
|
|
|
|
userID := uuid.New()
|
|
c.Set("user_id", userID)
|
|
|
|
mockJobWorker.On("EnqueueAnalyticsJob", "custom_event", mock.AnythingOfType("*uuid.UUID"), mock.MatchedBy(func(p map[string]interface{}) bool {
|
|
return p["foo"] == "bar"
|
|
}))
|
|
|
|
handler.RecordEvent(c)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
mockJobWorker.AssertExpectations(t)
|
|
}
|