[T0-006] test(backend): Ajout tests service job - Progression couverture
- Tests complets pour job_service (14 tests, tous passent) - Tests couvrent NewJobService, SetJobEnqueuer, EnqueueEmail, EnqueueThumbnail - Mock JobEnqueuer créé pour tester le service - Tests utilisent testify/mock pour vérifier les appels - Couverture actuelle: 30.2% (objectif: 80%) Files: - veza-backend-api/internal/services/job_service_test.go (créé) - VEZA_ROADMAP.json (mis à jour) Hours: 16 estimated, 13 actual (travail en cours)
This commit is contained in:
parent
7b5249aed2
commit
7b1d70abbd
2 changed files with 266 additions and 6 deletions
|
|
@ -3,13 +3,13 @@
|
|||
"project": "Veza/Talas",
|
||||
"version": "0.101-MVP",
|
||||
"created": "2025-01-28",
|
||||
"last_updated": "2025-12-28T18:45:00Z",
|
||||
"last_updated": "2025-12-28T19:00:00Z",
|
||||
"total_tasks": 156,
|
||||
"completed_tasks": 5,
|
||||
"in_progress_task": "T0-006",
|
||||
"current_phase": "PHASE_0",
|
||||
"estimated_total_hours": 1480,
|
||||
"hours_completed": 34
|
||||
"hours_completed": 35
|
||||
},
|
||||
|
||||
"_instructions": {
|
||||
|
|
@ -235,7 +235,7 @@
|
|||
"priority": "P0",
|
||||
"status": "in_progress",
|
||||
"estimated_hours": 16,
|
||||
"actual_hours": 12,
|
||||
"actual_hours": 13,
|
||||
"started_at": "2025-12-28T15:13:09Z",
|
||||
"completed_at": null,
|
||||
"dependencies": ["T0-001", "T0-005"],
|
||||
|
|
@ -260,14 +260,15 @@
|
|||
"veza-backend-api/internal/services/notification_service_test.go",
|
||||
"veza-backend-api/internal/services/password_service_integration_test.go",
|
||||
"veza-backend-api/internal/services/metadata_service_test.go",
|
||||
"veza-backend-api/internal/services/backup_service_test.go"
|
||||
"veza-backend-api/internal/services/backup_service_test.go",
|
||||
"veza-backend-api/internal/services/job_service_test.go"
|
||||
]
|
||||
},
|
||||
"commands": {
|
||||
"verify": ["cd veza-backend-api && ./scripts/test_coverage_one_by_one.sh"],
|
||||
"test": ["cd veza-backend-api && go test ./internal/api/handlers -run TestRBACHandlers -v", "cd veza-backend-api && go test ./internal/api/user -run TestUserHandler -v", "cd veza-backend-api && go test ./internal/services -run TestSocialService -v", "cd veza-backend-api && go test ./internal/services -run TestCacheService -v", "cd veza-backend-api && go test ./internal/services -run TestNotificationService -v", "cd veza-backend-api && go test ./internal/services -run TestPasswordService_ -v", "cd veza-backend-api && go test ./internal/services -run TestMetadataService -v", "cd veza-backend-api && go test ./internal/services -run TestBackupService -v"]
|
||||
"test": ["cd veza-backend-api && go test ./internal/api/handlers -run TestRBACHandlers -v", "cd veza-backend-api && go test ./internal/api/user -run TestUserHandler -v", "cd veza-backend-api && go test ./internal/services -run TestSocialService -v", "cd veza-backend-api && go test ./internal/services -run TestCacheService -v", "cd veza-backend-api && go test ./internal/services -run TestNotificationService -v", "cd veza-backend-api && go test ./internal/services -run TestPasswordService_ -v", "cd veza-backend-api && go test ./internal/services -run TestMetadataService -v", "cd veza-backend-api && go test ./internal/services -run TestBackupService -v", "cd veza-backend-api && go test ./internal/services -run TestJobService -v"]
|
||||
},
|
||||
"implementation_notes": "Progrès réalisés: 1) Scripts créés pour exécuter les tests par groupes/packages individuels (évite les crashes RAM), 2) Tests complets pour handlers RBAC (16 tests, tous passent), 3) Tests complets pour handlers user (16 tests, tous passent), 4) Tests complets pour service social (18 tests, tous passent), 5) Tests complets pour service cache (20 tests, tous passent), 6) Tests complets pour service notification (15 tests, tous passent), 7) Tests complets pour service password (15 tests, tous passent, certains skip car nécessitent PostgreSQL NOW()), 8) Tests complets pour service metadata (14 tests, tous passent), 9) Tests complets pour service backup (15 tests, tous passent, 1 skip car nécessite PostgreSQL pg_dump), 10) Interfaces créées (RBACServiceInterface, UserServiceInterface, DataExportServiceInterface) pour permettre le mock dans les tests, 11) Couverture actuelle: 30.2% (objectif: 80%). Prochaines étapes: Créer des tests pour les autres handlers critiques (track, playlist, search, etc.) et services manquants pour atteindre 80%. Cette tâche nécessite encore environ 4-6 heures de travail pour créer suffisamment de tests.",
|
||||
"implementation_notes": "Progrès réalisés: 1) Scripts créés pour exécuter les tests par groupes/packages individuels (évite les crashes RAM), 2) Tests complets pour handlers RBAC (16 tests, tous passent), 3) Tests complets pour handlers user (16 tests, tous passent), 4) Tests complets pour service social (18 tests, tous passent), 5) Tests complets pour service cache (20 tests, tous passent), 6) Tests complets pour service notification (15 tests, tous passent), 7) Tests complets pour service password (15 tests, tous passent, certains skip car nécessitent PostgreSQL NOW()), 8) Tests complets pour service metadata (14 tests, tous passent), 9) Tests complets pour service backup (15 tests, tous passent, 1 skip car nécessite PostgreSQL pg_dump), 10) Tests complets pour service job (14 tests, tous passent), 11) Interfaces créées (RBACServiceInterface, UserServiceInterface, DataExportServiceInterface) pour permettre le mock dans les tests, 12) Mock créé pour JobEnqueuer interface, 13) Couverture actuelle: 30.2% (objectif: 80%). Prochaines étapes: Créer des tests pour les autres handlers critiques (track, playlist, search, etc.) et services manquants pour atteindre 80%. Cette tâche nécessite encore environ 3-5 heures de travail pour créer suffisamment de tests.",
|
||||
"blockers": []
|
||||
},
|
||||
{
|
||||
|
|
|
|||
259
veza-backend-api/internal/services/job_service_test.go
Normal file
259
veza-backend-api/internal/services/job_service_test.go
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// MockJobEnqueuer is a mock implementation of JobEnqueuer interface
|
||||
type MockJobEnqueuer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *MockJobEnqueuer) EnqueueEmailJob(to, subject, body string) {
|
||||
m.Called(to, subject, body)
|
||||
}
|
||||
|
||||
func (m *MockJobEnqueuer) EnqueueEmailJobWithTemplate(to, subject, templateName string, templateData map[string]interface{}) {
|
||||
m.Called(to, subject, templateName, templateData)
|
||||
}
|
||||
|
||||
func (m *MockJobEnqueuer) EnqueueThumbnailJob(inputPath, outputPath string, width, height int) {
|
||||
m.Called(inputPath, outputPath, width, height)
|
||||
}
|
||||
|
||||
func (m *MockJobEnqueuer) EnqueueAnalyticsJob(eventName string, userID *uuid.UUID, payload map[string]interface{}) {
|
||||
m.Called(eventName, userID, payload)
|
||||
}
|
||||
|
||||
func setupTestJobService(t *testing.T) (*JobService, *MockJobEnqueuer) {
|
||||
logger := zap.NewNop()
|
||||
service := NewJobService(logger)
|
||||
mockEnqueuer := new(MockJobEnqueuer)
|
||||
service.SetJobEnqueuer(mockEnqueuer)
|
||||
return service, mockEnqueuer
|
||||
}
|
||||
|
||||
func TestJobService_NewJobService(t *testing.T) {
|
||||
logger := zap.NewNop()
|
||||
service := NewJobService(logger)
|
||||
|
||||
assert.NotNil(t, service)
|
||||
assert.NotNil(t, service.logger)
|
||||
assert.Nil(t, service.jobEnqueuer) // Should be nil initially
|
||||
}
|
||||
|
||||
func TestJobService_SetJobEnqueuer(t *testing.T) {
|
||||
logger := zap.NewNop()
|
||||
service := NewJobService(logger)
|
||||
mockEnqueuer := new(MockJobEnqueuer)
|
||||
|
||||
service.SetJobEnqueuer(mockEnqueuer)
|
||||
|
||||
assert.Equal(t, mockEnqueuer, service.jobEnqueuer)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueEmail_Success(t *testing.T) {
|
||||
service, mockEnqueuer := setupTestJobService(t)
|
||||
|
||||
ctx := context.Background()
|
||||
payload := &EmailPayload{
|
||||
To: "test@example.com",
|
||||
Subject: "Test Subject",
|
||||
Body: "Test Body",
|
||||
}
|
||||
|
||||
mockEnqueuer.On("EnqueueEmailJob", payload.To, payload.Subject, payload.Body).Return()
|
||||
|
||||
err := service.EnqueueEmail(ctx, payload)
|
||||
|
||||
assert.NoError(t, err)
|
||||
mockEnqueuer.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueEmail_NoEnqueuer(t *testing.T) {
|
||||
logger := zap.NewNop()
|
||||
service := NewJobService(logger)
|
||||
// Don't set enqueuer
|
||||
|
||||
ctx := context.Background()
|
||||
payload := &EmailPayload{
|
||||
To: "test@example.com",
|
||||
Subject: "Test Subject",
|
||||
Body: "Test Body",
|
||||
}
|
||||
|
||||
// Should not error, just log warning
|
||||
err := service.EnqueueEmail(ctx, payload)
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueEmail_EmptyPayload(t *testing.T) {
|
||||
service, mockEnqueuer := setupTestJobService(t)
|
||||
|
||||
ctx := context.Background()
|
||||
payload := &EmailPayload{
|
||||
To: "",
|
||||
Subject: "",
|
||||
Body: "",
|
||||
}
|
||||
|
||||
mockEnqueuer.On("EnqueueEmailJob", "", "", "").Return()
|
||||
|
||||
err := service.EnqueueEmail(ctx, payload)
|
||||
|
||||
assert.NoError(t, err)
|
||||
mockEnqueuer.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueThumbnail_Success(t *testing.T) {
|
||||
service, mockEnqueuer := setupTestJobService(t)
|
||||
|
||||
ctx := context.Background()
|
||||
payload := &ThumbnailPayload{
|
||||
TrackID: 123,
|
||||
FileID: "file123",
|
||||
FilePath: "/path/to/file.jpg",
|
||||
}
|
||||
|
||||
mockEnqueuer.On("EnqueueThumbnailJob", "/path/to/file.jpg", "/path/to/file.jpg.thumb", 300, 300).Return()
|
||||
|
||||
err := service.EnqueueThumbnail(ctx, payload)
|
||||
|
||||
assert.NoError(t, err)
|
||||
mockEnqueuer.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueThumbnail_NoEnqueuer(t *testing.T) {
|
||||
logger := zap.NewNop()
|
||||
service := NewJobService(logger)
|
||||
// Don't set enqueuer
|
||||
|
||||
ctx := context.Background()
|
||||
payload := &ThumbnailPayload{
|
||||
TrackID: 123,
|
||||
FileID: "file123",
|
||||
FilePath: "/path/to/file.jpg",
|
||||
}
|
||||
|
||||
// Should not error, just log warning
|
||||
err := service.EnqueueThumbnail(ctx, payload)
|
||||
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueThumbnail_EmptyFilePath(t *testing.T) {
|
||||
service, mockEnqueuer := setupTestJobService(t)
|
||||
|
||||
ctx := context.Background()
|
||||
payload := &ThumbnailPayload{
|
||||
TrackID: 123,
|
||||
FileID: "file123",
|
||||
FilePath: "", // Empty file path
|
||||
}
|
||||
|
||||
// Should not call enqueuer if FilePath is empty
|
||||
err := service.EnqueueThumbnail(ctx, payload)
|
||||
|
||||
assert.NoError(t, err)
|
||||
mockEnqueuer.AssertNotCalled(t, "EnqueueThumbnailJob")
|
||||
}
|
||||
|
||||
func TestJobService_JobTypes_Constants(t *testing.T) {
|
||||
assert.Equal(t, "email:send", TypeEmailSend)
|
||||
assert.Equal(t, "thumbnail:generate", TypeThumbnailGenerate)
|
||||
assert.Equal(t, "analytics:process", TypeAnalyticsProcess)
|
||||
assert.Equal(t, "webhook:delivery", TypeWebhookDelivery)
|
||||
}
|
||||
|
||||
func TestJobService_EmailPayload_Fields(t *testing.T) {
|
||||
payload := &EmailPayload{
|
||||
To: "test@example.com",
|
||||
Subject: "Test Subject",
|
||||
Body: "Test Body",
|
||||
}
|
||||
|
||||
assert.Equal(t, "test@example.com", payload.To)
|
||||
assert.Equal(t, "Test Subject", payload.Subject)
|
||||
assert.Equal(t, "Test Body", payload.Body)
|
||||
}
|
||||
|
||||
func TestJobService_ThumbnailPayload_Fields(t *testing.T) {
|
||||
payload := &ThumbnailPayload{
|
||||
TrackID: 123,
|
||||
FileID: "file123",
|
||||
FilePath: "/path/to/file.jpg",
|
||||
}
|
||||
|
||||
assert.Equal(t, uint(123), payload.TrackID)
|
||||
assert.Equal(t, "file123", payload.FileID)
|
||||
assert.Equal(t, "/path/to/file.jpg", payload.FilePath)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueEmail_MultipleCalls(t *testing.T) {
|
||||
service, mockEnqueuer := setupTestJobService(t)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
payload1 := &EmailPayload{
|
||||
To: "user1@example.com",
|
||||
Subject: "Subject 1",
|
||||
Body: "Body 1",
|
||||
}
|
||||
|
||||
payload2 := &EmailPayload{
|
||||
To: "user2@example.com",
|
||||
Subject: "Subject 2",
|
||||
Body: "Body 2",
|
||||
}
|
||||
|
||||
mockEnqueuer.On("EnqueueEmailJob", payload1.To, payload1.Subject, payload1.Body).Return()
|
||||
mockEnqueuer.On("EnqueueEmailJob", payload2.To, payload2.Subject, payload2.Body).Return()
|
||||
|
||||
err1 := service.EnqueueEmail(ctx, payload1)
|
||||
err2 := service.EnqueueEmail(ctx, payload2)
|
||||
|
||||
assert.NoError(t, err1)
|
||||
assert.NoError(t, err2)
|
||||
mockEnqueuer.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestJobService_EnqueueThumbnail_DifferentPaths(t *testing.T) {
|
||||
service, mockEnqueuer := setupTestJobService(t)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
filePath string
|
||||
expectedOutput string
|
||||
}{
|
||||
{"JPG", "/path/to/image.jpg", "/path/to/image.jpg.thumb"},
|
||||
{"PNG", "/path/to/image.png", "/path/to/image.png.thumb"},
|
||||
{"Nested path", "/very/deep/path/to/image.jpg", "/very/deep/path/to/image.jpg.thumb"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
payload := &ThumbnailPayload{
|
||||
TrackID: 123,
|
||||
FileID: "file123",
|
||||
FilePath: tc.filePath,
|
||||
}
|
||||
|
||||
mockEnqueuer.On("EnqueueThumbnailJob", tc.filePath, tc.expectedOutput, 300, 300).Return()
|
||||
|
||||
err := service.EnqueueThumbnail(ctx, payload)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
mockEnqueuer.AssertExpectations(t)
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue