272 lines
6.9 KiB
Go
272 lines
6.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"go.uber.org/zap/zaptest"
|
|
|
|
"veza-backend-api/internal/models"
|
|
"veza-backend-api/internal/services"
|
|
)
|
|
|
|
// MockPlaybackAnalyticsService is a mock implementation of PlaybackAnalyticsService
|
|
type MockPlaybackAnalyticsService struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *MockPlaybackAnalyticsService) RecordPlayback(ctx context.Context, analytics *models.PlaybackAnalytics) error {
|
|
args := m.Called(ctx, analytics)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (m *MockPlaybackAnalyticsService) GetTrackStats(ctx context.Context, trackID uuid.UUID) (*services.PlaybackStats, error) {
|
|
args := m.Called(ctx, trackID)
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*services.PlaybackStats), args.Error(1)
|
|
}
|
|
|
|
func TestNewPlaybackWebSocketHandler(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
|
|
// Execute
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
// Assert
|
|
assert.NotNil(t, handler)
|
|
assert.NotNil(t, handler.analyticsService)
|
|
assert.NotNil(t, handler.logger)
|
|
assert.NotNil(t, handler.clients)
|
|
assert.NotNil(t, handler.broadcast)
|
|
assert.Equal(t, 0, handler.GetTotalConnectedClientsCount())
|
|
}
|
|
|
|
func TestNewPlaybackWebSocketHandler_NilLogger(t *testing.T) {
|
|
// Setup
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
|
|
// Execute
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, nil)
|
|
|
|
// Assert
|
|
assert.NotNil(t, handler)
|
|
assert.NotNil(t, handler.logger)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_GetConnectedClientsCount(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
// Execute - No clients connected
|
|
count := handler.GetConnectedClientsCount(123)
|
|
|
|
// Assert
|
|
assert.Equal(t, 0, count)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_GetTotalConnectedClientsCount(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
// Execute
|
|
total := handler.GetTotalConnectedClientsCount()
|
|
|
|
// Assert
|
|
assert.Equal(t, 0, total)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_BroadcastAnalyticsUpdate(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
trackID := int64(123)
|
|
trackUUID := uuid.New()
|
|
analytics := &models.PlaybackAnalytics{
|
|
TrackID: trackUUID,
|
|
UserID: uuid.New(),
|
|
PlayTime: 45,
|
|
PauseCount: 2,
|
|
SeekCount: 1,
|
|
CompletionRate: 50.0,
|
|
StartedAt: time.Now(),
|
|
}
|
|
|
|
// Execute - Should not panic even with no clients
|
|
handler.BroadcastAnalyticsUpdate(trackID, analytics)
|
|
|
|
// Assert - No error should occur
|
|
assert.True(t, true)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_BroadcastAnalyticsUpdate_NilAnalytics(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
// Execute - Should not panic with nil analytics
|
|
handler.BroadcastAnalyticsUpdate(123, nil)
|
|
|
|
// Assert - No error should occur
|
|
assert.True(t, true)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_BroadcastStatsUpdate(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
stats := &services.PlaybackStats{
|
|
TotalSessions: 100,
|
|
TotalPlayTime: 3000,
|
|
AveragePlayTime: 30.0,
|
|
TotalPauses: 50,
|
|
AveragePauses: 0.5,
|
|
TotalSeeks: 25,
|
|
AverageSeeks: 0.25,
|
|
AverageCompletion: 75.0,
|
|
CompletionRate: 60.0,
|
|
}
|
|
|
|
// Execute - Should not panic even with no clients
|
|
handler.BroadcastStatsUpdate(123, stats)
|
|
|
|
// Assert - No error should occur
|
|
assert.True(t, true)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_BroadcastStatsUpdate_NilStats(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
// Execute - Should not panic with nil stats
|
|
handler.BroadcastStatsUpdate(123, nil)
|
|
|
|
// Assert - No error should occur
|
|
assert.True(t, true)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_WebSocketHandler_Unauthorized(t *testing.T) {
|
|
// Setup
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.New()
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
router.GET("/ws", handler.WebSocketHandler)
|
|
|
|
// Execute - Request without user ID
|
|
req, _ := http.NewRequest("GET", "/ws", nil)
|
|
w := httptest.NewRecorder()
|
|
router.ServeHTTP(w, req)
|
|
|
|
// Assert
|
|
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestBroadcastMessage_MarshalJSON(t *testing.T) {
|
|
// Setup
|
|
msg := &BroadcastMessage{
|
|
TrackID: 123,
|
|
Type: "analytics_update",
|
|
Data: gin.H{"test": "data"},
|
|
Timestamp: time.Now(),
|
|
}
|
|
|
|
// Execute
|
|
data, err := json.Marshal(msg)
|
|
|
|
// Assert
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, data)
|
|
|
|
var unmarshaled BroadcastMessage
|
|
err = json.Unmarshal(data, &unmarshaled)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, msg.TrackID, unmarshaled.TrackID)
|
|
assert.Equal(t, msg.Type, unmarshaled.Type)
|
|
}
|
|
|
|
func TestIncomingWebSocketMessage_MarshalJSON(t *testing.T) {
|
|
// Setup
|
|
msg := IncomingWebSocketMessage{
|
|
Type: "subscribe",
|
|
TrackID: "123",
|
|
Data: json.RawMessage(`{"test": "data"}`),
|
|
}
|
|
|
|
// Execute
|
|
data, err := json.Marshal(msg)
|
|
|
|
// Assert
|
|
assert.NoError(t, err)
|
|
assert.NotEmpty(t, data)
|
|
|
|
var unmarshaled IncomingWebSocketMessage
|
|
err = json.Unmarshal(data, &unmarshaled)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, msg.Type, unmarshaled.Type)
|
|
assert.Equal(t, msg.TrackID, unmarshaled.TrackID)
|
|
}
|
|
|
|
func TestPlaybackWebSocketHandler_BroadcastChannelFull(t *testing.T) {
|
|
// Setup
|
|
logger := zaptest.NewLogger(t)
|
|
mockService := &MockPlaybackAnalyticsService{}
|
|
handler := NewPlaybackWebSocketHandlerWithInterface(mockService, logger)
|
|
|
|
// Fill the broadcast channel
|
|
trackID := int64(123)
|
|
for i := 0; i < 257; i++ {
|
|
msg := &BroadcastMessage{
|
|
TrackID: trackID,
|
|
Type: "test",
|
|
Data: gin.H{"index": i},
|
|
Timestamp: time.Now(),
|
|
}
|
|
select {
|
|
case handler.broadcast <- msg:
|
|
default:
|
|
// Channel is full, this is expected
|
|
}
|
|
}
|
|
|
|
trackUUID := uuid.New()
|
|
analytics := &models.PlaybackAnalytics{
|
|
TrackID: trackUUID,
|
|
UserID: uuid.New(),
|
|
PlayTime: 45,
|
|
PauseCount: 2,
|
|
SeekCount: 1,
|
|
CompletionRate: 50.0,
|
|
StartedAt: time.Now(),
|
|
}
|
|
|
|
// Execute - Should not panic even when channel is full
|
|
handler.BroadcastAnalyticsUpdate(123, analytics)
|
|
|
|
// Assert - No error should occur
|
|
assert.True(t, true)
|
|
}
|