veza/veza-backend-api/internal/handlers/marketplace_test.go
senke 8e9ee2f3a5 fix: stabilize builds, tests, and lint across all stacks
Complete stabilization pass bringing all 3 stacks to green:

Frontend (apps/web/):
- Fix TypeScript nullability in useSeason.ts, useTimeOfDay.ts hooks
- Disable no-undef in ESLint config (TypeScript handles it; JSX misidentified)
- Rename 306 story imports from @storybook/react to @storybook/react-vite
- Fix conditional hook call in useMediaQuery.ts useIsTablet
- Move useQuery to top of LoginPage.tsx component
- Remove useless try/catch in GearFormModal.tsx
- Fix stale closure in ResetPasswordPage.tsx handleChange
- Make Storybook decorators (withRouter, withQueryClient, withToast, withAudio)
  no-ops since global StorybookDecorator already provides these — prevents
  nested Router / duplicate provider crashes in vitest-browser
- Fix nested MemoryRouter in 3 page stories (TrackDetail, PlaylistDetail, UserProfile)
- Update i18n initialization in test setup (await init before changeLanguage)
- Update ~30 test assertions from English to French to match i18n translations
- Update test assertions to match SUMI V3 design changes (shadow vs border)
- Fix remaining story type errors (PlayerError, PlaylistBatchActions,
  TrackFilters, VirtualizedChatMessages)

Backend (veza-backend-api/):
- Fix response_test.go RespondWithAppError signature (2 args, not 3)
- Fix TestErrorContractAuthEndpoints expected error codes
  (ErrCodeUnauthorized vs ErrCodeInvalidCredentials)
- Fix TestTrackHandler_GetTrackLikes_Success missing auth middleware setup
- Fix TestPlaybackAnalyticsService_GetTrackStats k-anonymity threshold
  (needs 5 unique users, not 1)
- Replace NOW() PostgreSQL function with time.Now() parameter in marketplace
  service for SQLite test compatibility
- Add missing AutoMigrate entries in marketplace_test.go
  (ProductImage, ProductPreview, ProductLicense, ProductReview)

Results:
- Frontend TypeCheck: 617 errors -> 0 errors
- Frontend ESLint: 349 errors -> 0 errors
- Frontend Vitest: 196 failing tests -> 1 skipped (3396/3397 passing)
- Backend go vet: 1 error -> 0 errors
- Backend tests: 5 failing -> all 13 packages passing
- Rust: 150/150 tests passing (unchanged)
- Storybook audit: 0 errors across 1244 stories

Triage report: docs/TRIAGE_REPORT.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:48:07 +02:00

574 lines
17 KiB
Go

package handlers
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
"veza-backend-api/internal/core/marketplace"
"veza-backend-api/internal/models"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// MockStorageService is a mock implementation of StorageService
type MockStorageService struct {
GetDownloadURLFunc func(ctx context.Context, filePath string) (string, error)
}
func (m *MockStorageService) GetDownloadURL(ctx context.Context, filePath string) (string, error) {
if m.GetDownloadURLFunc != nil {
return m.GetDownloadURLFunc(ctx, filePath)
}
return fmt.Sprintf("/download/%s", filePath), nil
}
// setupTestMarketplaceHandler creates a test handler with real services and in-memory database
func setupTestMarketplaceHandler(t *testing.T) (*MarketplaceHandler, *gorm.DB, *gin.Engine, func()) {
gin.SetMode(gin.TestMode)
logger := zaptest.NewLogger(t)
// Setup in-memory SQLite database
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err)
db.Exec("PRAGMA foreign_keys = ON")
// Auto-migrate models
err = db.AutoMigrate(
&models.User{},
&models.Track{},
&marketplace.Product{},
&marketplace.ProductPreview{},
&marketplace.ProductImage{},
&marketplace.ProductLicense{},
&marketplace.ProductReview{},
&marketplace.Order{},
&marketplace.OrderItem{},
&marketplace.License{},
)
require.NoError(t, err)
// Setup storage service
storageService := &MockStorageService{}
// Setup marketplace service
marketService := marketplace.NewService(db, logger, storageService)
handler := NewMarketplaceHandler(marketService, logger, "uploads")
router := gin.New()
router.Use(func(c *gin.Context) {
// Mock auth middleware - set user_id from header if present
userIDStr := c.GetHeader("X-User-ID")
if userIDStr != "" {
uid, err := uuid.Parse(userIDStr)
if err == nil {
c.Set("user_id", uid)
}
}
c.Next()
})
cleanup := func() {
// Database cleanup handled by test
}
return handler, db, router, cleanup
}
// Helper to create a test user
func createTestUserForMarketplace(id uuid.UUID, username string) *models.User {
return &models.User{
ID: id,
Username: username,
Email: fmt.Sprintf("%s@example.com", username),
IsActive: true,
IsVerified: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
}
// Helper to create a test track
func createTestTrackForMarketplace(id uuid.UUID, userID uuid.UUID) *models.Track {
return &models.Track{
ID: id,
UserID: userID,
Title: "Test Track",
Artist: "Test Artist",
FilePath: "/tmp/test-uploads/test.mp3",
Format: "mp3",
FileSize: 1024,
Duration: 180,
IsPublic: true,
Status: models.TrackStatusCompleted,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
}
// TestMarketplaceHandler_CreateProduct_Success tests successful product creation
func TestMarketplaceHandler_CreateProduct_Success(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user and track
userID := uuid.New()
user := createTestUserForMarketplace(userID, "seller")
err := db.Create(user).Error
require.NoError(t, err)
trackID := uuid.New()
track := createTestTrackForMarketplace(trackID, userID)
err = db.Create(track).Error
require.NoError(t, err)
router.POST("/marketplace/products", handler.CreateProduct)
createReq := CreateProductRequest{
Title: "My Product",
Description: "A test product",
Price: 9.99,
ProductType: "track",
TrackID: trackID.String(),
LicenseType: "standard",
}
body, _ := json.Marshal(createReq)
req := httptest.NewRequest(http.MethodPost, "/marketplace/products", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", userID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
}
// TestMarketplaceHandler_CreateProduct_InvalidTrack tests product creation with invalid track
func TestMarketplaceHandler_CreateProduct_InvalidTrack(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
userID := uuid.New()
user := createTestUserForMarketplace(userID, "seller")
err := db.Create(user).Error
require.NoError(t, err)
router.POST("/marketplace/products", handler.CreateProduct)
createReq := CreateProductRequest{
Title: "My Product",
Description: "A test product",
Price: 9.99,
ProductType: "track",
TrackID: uuid.New().String(), // Non-existent track
LicenseType: "standard",
}
body, _ := json.Marshal(createReq)
req := httptest.NewRequest(http.MethodPost, "/marketplace/products", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", userID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
// TestMarketplaceHandler_ListProducts_Success tests successful product listing
func TestMarketplaceHandler_ListProducts_Success(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
userID := uuid.New()
user := createTestUserForMarketplace(userID, "seller")
err := db.Create(user).Error
require.NoError(t, err)
// Create test products
for i := 0; i < 3; i++ {
product := &marketplace.Product{
ID: uuid.New(),
SellerID: userID,
Title: fmt.Sprintf("Product %d", i+1),
Description: "Test product",
Price: 9.99,
ProductType: "track",
Status: marketplace.ProductStatusActive,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = db.Create(product).Error
require.NoError(t, err)
}
router.GET("/marketplace/products", handler.ListProducts)
req := httptest.NewRequest(http.MethodGet, "/marketplace/products", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.True(t, response["success"].(bool))
}
// TestMarketplaceHandler_UpdateProduct_Success tests successful product update
func TestMarketplaceHandler_UpdateProduct_Success(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
userID := uuid.New()
user := createTestUserForMarketplace(userID, "seller")
err := db.Create(user).Error
require.NoError(t, err)
// Create test product
productID := uuid.New()
product := &marketplace.Product{
ID: productID,
SellerID: userID,
Title: "Original Title",
Description: "Original Description",
Price: 9.99,
ProductType: "track",
Status: marketplace.ProductStatusActive,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = db.Create(product).Error
require.NoError(t, err)
router.PUT("/marketplace/products/:id", handler.UpdateProduct)
title := "Updated Title"
updateReq := UpdateProductRequest{
Title: &title,
}
body, _ := json.Marshal(updateReq)
req := httptest.NewRequest(http.MethodPut, fmt.Sprintf("/marketplace/products/%s", productID.String()), bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", userID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.True(t, response["success"].(bool))
}
// TestMarketplaceHandler_UpdateProduct_NotFound tests product update with non-existent product
func TestMarketplaceHandler_UpdateProduct_NotFound(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
userID := uuid.New()
user := createTestUserForMarketplace(userID, "seller")
err := db.Create(user).Error
require.NoError(t, err)
router.PUT("/marketplace/products/:id", handler.UpdateProduct)
title := "Updated Title"
updateReq := UpdateProductRequest{
Title: &title,
}
body, _ := json.Marshal(updateReq)
nonExistentID := uuid.New()
req := httptest.NewRequest(http.MethodPut, fmt.Sprintf("/marketplace/products/%s", nonExistentID.String()), bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", userID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
// TestMarketplaceHandler_CreateOrder_Success tests successful order creation
func TestMarketplaceHandler_CreateOrder_Success(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test users
sellerID := uuid.New()
seller := createTestUserForMarketplace(sellerID, "seller")
err := db.Create(seller).Error
require.NoError(t, err)
buyerID := uuid.New()
buyer := createTestUserForMarketplace(buyerID, "buyer")
err = db.Create(buyer).Error
require.NoError(t, err)
// Create test product
productID := uuid.New()
product := &marketplace.Product{
ID: productID,
SellerID: sellerID,
Title: "Test Product",
Description: "Test Description",
Price: 9.99,
ProductType: "track",
Status: marketplace.ProductStatusActive,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = db.Create(product).Error
require.NoError(t, err)
router.POST("/marketplace/orders", handler.CreateOrder)
createReq := CreateOrderRequest{
Items: []struct {
ProductID string `json:"product_id" binding:"required" validate:"required,uuid"`
}{
{ProductID: productID.String()},
},
}
body, _ := json.Marshal(createReq)
req := httptest.NewRequest(http.MethodPost, "/marketplace/orders", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", buyerID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusCreated, w.Code)
}
// TestMarketplaceHandler_CreateOrder_InvalidProduct tests order creation with invalid product
func TestMarketplaceHandler_CreateOrder_InvalidProduct(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
buyerID := uuid.New()
buyer := createTestUserForMarketplace(buyerID, "buyer")
err := db.Create(buyer).Error
require.NoError(t, err)
router.POST("/marketplace/orders", handler.CreateOrder)
createReq := CreateOrderRequest{
Items: []struct {
ProductID string `json:"product_id" binding:"required" validate:"required,uuid"`
}{
{ProductID: uuid.New().String()}, // Non-existent product
},
}
body, _ := json.Marshal(createReq)
req := httptest.NewRequest(http.MethodPost, "/marketplace/orders", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", buyerID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
// TestMarketplaceHandler_ListOrders_Success tests successful order listing
func TestMarketplaceHandler_ListOrders_Success(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
buyerID := uuid.New()
buyer := createTestUserForMarketplace(buyerID, "buyer")
err := db.Create(buyer).Error
require.NoError(t, err)
// Create test orders
for i := 0; i < 2; i++ {
order := &marketplace.Order{
ID: uuid.New(),
BuyerID: buyerID,
TotalAmount: 9.99,
Currency: "EUR",
Status: "paid",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = db.Create(order).Error
require.NoError(t, err)
}
router.GET("/marketplace/orders", handler.ListOrders)
req := httptest.NewRequest(http.MethodGet, "/marketplace/orders", nil)
req.Header.Set("X-User-ID", buyerID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.True(t, response["success"].(bool))
}
// TestMarketplaceHandler_GetOrder_Success tests successful order retrieval
func TestMarketplaceHandler_GetOrder_Success(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
buyerID := uuid.New()
buyer := createTestUserForMarketplace(buyerID, "buyer")
err := db.Create(buyer).Error
require.NoError(t, err)
// Create test order
orderID := uuid.New()
order := &marketplace.Order{
ID: orderID,
BuyerID: buyerID,
TotalAmount: 9.99,
Currency: "EUR",
Status: "paid",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = db.Create(order).Error
require.NoError(t, err)
router.GET("/marketplace/orders/:id", handler.GetOrder)
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/marketplace/orders/%s", orderID.String()), nil)
req.Header.Set("X-User-ID", buyerID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var response map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &response)
require.NoError(t, err)
assert.True(t, response["success"].(bool))
}
// TestMarketplaceHandler_GetOrder_NotFound tests order retrieval with non-existent order
func TestMarketplaceHandler_GetOrder_NotFound(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
buyerID := uuid.New()
buyer := createTestUserForMarketplace(buyerID, "buyer")
err := db.Create(buyer).Error
require.NoError(t, err)
router.GET("/marketplace/orders/:id", handler.GetOrder)
nonExistentID := uuid.New()
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/marketplace/orders/%s", nonExistentID.String()), nil)
req.Header.Set("X-User-ID", buyerID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusNotFound, w.Code)
}
// TestMarketplaceHandler_GetDownloadURL_NoLicense tests download URL retrieval without license
func TestMarketplaceHandler_GetDownloadURL_NoLicense(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
userID := uuid.New()
user := createTestUserForMarketplace(userID, "user")
err := db.Create(user).Error
require.NoError(t, err)
// Create test product
productID := uuid.New()
product := &marketplace.Product{
ID: productID,
SellerID: uuid.New(),
Title: "Test Product",
Description: "Test Description",
Price: 9.99,
ProductType: "track",
Status: marketplace.ProductStatusActive,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = db.Create(product).Error
require.NoError(t, err)
router.GET("/marketplace/download/:product_id", handler.GetDownloadURL)
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/marketplace/download/%s", productID.String()), nil)
req.Header.Set("X-User-ID", userID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
// Should fail because user doesn't have a license
assert.Equal(t, http.StatusForbidden, w.Code)
}
// TestMarketplaceHandler_CreateProduct_InvalidTrackID tests product creation with invalid track ID format
func TestMarketplaceHandler_CreateProduct_InvalidTrackID(t *testing.T) {
handler, db, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
// Create test user
userID := uuid.New()
user := createTestUserForMarketplace(userID, "seller")
err := db.Create(user).Error
require.NoError(t, err)
router.POST("/marketplace/products", handler.CreateProduct)
createReq := CreateProductRequest{
Title: "My Product",
Description: "A test product",
Price: 9.99,
ProductType: "track",
TrackID: "invalid-uuid", // Invalid UUID format
LicenseType: "standard",
}
body, _ := json.Marshal(createReq)
req := httptest.NewRequest(http.MethodPost, "/marketplace/products", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", userID.String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
// TestMarketplaceHandler_UpdateProduct_InvalidID tests product update with invalid ID format
func TestMarketplaceHandler_UpdateProduct_InvalidID(t *testing.T) {
handler, _, router, cleanup := setupTestMarketplaceHandler(t)
defer cleanup()
router.PUT("/marketplace/products/:id", handler.UpdateProduct)
title := "Updated Title"
updateReq := UpdateProductRequest{
Title: &title,
}
body, _ := json.Marshal(updateReq)
req := httptest.NewRequest(http.MethodPut, "/marketplace/products/invalid-id", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-User-ID", uuid.New().String())
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
}