//go:build integration || marketplace // +build integration marketplace package marketplace import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" "time" "veza-backend-api/internal/core/marketplace" "veza-backend-api/internal/database" "veza-backend-api/internal/handlers" "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(filePath string) (string, error) } func (m *MockStorageService) GetDownloadURL(ctx context.Context, filePath string) (string, error) { if m.GetDownloadURLFunc != nil { return m.GetDownloadURLFunc(filePath) } return fmt.Sprintf("/download/%s", filePath), nil } // setupMarketplaceFlowTestRouter crée un router de test avec les services nécessaires pour les tests de flux marketplace func setupMarketplaceFlowTestRouter(t *testing.T) (*gin.Engine, *gorm.DB, *database.Database, *marketplace.Service, 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 (User and Track use standard GORM) err = db.AutoMigrate( &models.User{}, &models.Track{}, ) require.NoError(t, err) // Create marketplace tables manually for SQLite compatibility (gen_random_uuid() is PostgreSQL-specific) // Products table err = db.Exec(` CREATE TABLE IF NOT EXISTS products ( id TEXT PRIMARY KEY, seller_id TEXT NOT NULL, title TEXT NOT NULL, description TEXT, price REAL NOT NULL, currency TEXT DEFAULT 'EUR', status TEXT DEFAULT 'draft', product_type TEXT NOT NULL, track_id TEXT, license_type TEXT, bpm INTEGER, musical_key TEXT, category TEXT, created_at DATETIME, updated_at DATETIME, deleted_at DATETIME ) `).Error require.NoError(t, err) // Orders table err = db.Exec(` CREATE TABLE IF NOT EXISTS orders ( id TEXT PRIMARY KEY, buyer_id TEXT NOT NULL, total_amount REAL NOT NULL, currency TEXT DEFAULT 'EUR', status TEXT DEFAULT 'pending', payment_intent TEXT, hyperswitch_payment_id TEXT, payment_status TEXT DEFAULT 'pending', promo_code_id TEXT, discount_amount_cents INTEGER DEFAULT 0, created_at DATETIME, updated_at DATETIME ) `).Error require.NoError(t, err) // Product images table (for Preload in CreateProduct response) err = db.Exec(` CREATE TABLE IF NOT EXISTS product_images ( id TEXT PRIMARY KEY, product_id TEXT NOT NULL, url TEXT NOT NULL, sort_order INTEGER DEFAULT 0, created_at DATETIME, FOREIGN KEY(product_id) REFERENCES products(id) ON DELETE CASCADE ) `).Error require.NoError(t, err) // Order items table err = db.Exec(` CREATE TABLE IF NOT EXISTS order_items ( id TEXT PRIMARY KEY, order_id TEXT NOT NULL, product_id TEXT NOT NULL, price REAL NOT NULL, FOREIGN KEY(order_id) REFERENCES orders(id) ON DELETE CASCADE ) `).Error require.NoError(t, err) // Product licenses table (license types per product) err = db.Exec(` CREATE TABLE IF NOT EXISTS product_licenses ( id TEXT PRIMARY KEY, product_id TEXT NOT NULL, license_type TEXT NOT NULL, price_cents INTEGER NOT NULL, terms_text TEXT, created_at DATETIME, FOREIGN KEY(product_id) REFERENCES products(id) ON DELETE CASCADE ) `).Error require.NoError(t, err) // Licenses table (purchased licenses) err = db.Exec(` CREATE TABLE IF NOT EXISTS licenses ( id TEXT PRIMARY KEY, buyer_id TEXT NOT NULL, track_id TEXT NOT NULL, product_id TEXT NOT NULL, order_id TEXT NOT NULL, type TEXT NOT NULL, rights TEXT, downloads_left INTEGER DEFAULT 3, created_at DATETIME, expires_at DATETIME, revoked_at DATETIME ) `).Error require.NoError(t, err) // Add BeforeCreate hooks for SQLite compatibility to generate UUIDs db.Callback().Create().Before("gorm:create").Register("generate_uuid_product", func(db *gorm.DB) { if product, ok := db.Statement.Dest.(*marketplace.Product); ok && product.ID == uuid.Nil { product.ID = uuid.New() } if products, ok := db.Statement.Dest.(*[]marketplace.Product); ok { for i := range *products { if (*products)[i].ID == uuid.Nil { (*products)[i].ID = uuid.New() } } } }) db.Callback().Create().Before("gorm:create").Register("generate_uuid_order", func(db *gorm.DB) { if order, ok := db.Statement.Dest.(*marketplace.Order); ok && order.ID == uuid.Nil { order.ID = uuid.New() } if orders, ok := db.Statement.Dest.(*[]marketplace.Order); ok { for i := range *orders { if (*orders)[i].ID == uuid.Nil { (*orders)[i].ID = uuid.New() } } } }) db.Callback().Create().Before("gorm:create").Register("generate_uuid_order_item", func(db *gorm.DB) { if item, ok := db.Statement.Dest.(*marketplace.OrderItem); ok && item.ID == uuid.Nil { item.ID = uuid.New() } if items, ok := db.Statement.Dest.(*[]marketplace.OrderItem); ok { for i := range *items { if (*items)[i].ID == uuid.Nil { (*items)[i].ID = uuid.New() } } } }) db.Callback().Create().Before("gorm:create").Register("generate_uuid_license", func(db *gorm.DB) { if license, ok := db.Statement.Dest.(*marketplace.License); ok && license.ID == uuid.Nil { license.ID = uuid.New() } if licenses, ok := db.Statement.Dest.(*[]marketplace.License); ok { for i := range *licenses { if (*licenses)[i].ID == uuid.Nil { (*licenses)[i].ID = uuid.New() } } } }) // Get underlying sql.DB from GORM for raw SQL queries sqlDB, err := db.DB() require.NoError(t, err) dbWrapper := &database.Database{ DB: sqlDB, GormDB: db, Logger: logger, } // Setup storage service storageService := &MockStorageService{ GetDownloadURLFunc: func(filePath string) (string, error) { return fmt.Sprintf("https://storage.example.com/download/%s", filePath), nil }, } // Setup marketplace service marketService := marketplace.NewService(db, logger, storageService) // Setup handlers marketHandler := handlers.NewMarketplaceHandler(marketService, logger, "uploads") // Create router router := gin.New() // Mock auth middleware - set user_id from header if present router.Use(func(c *gin.Context) { if userIDStr := c.GetHeader("X-User-ID"); userIDStr != "" { if userID, err := uuid.Parse(userIDStr); err == nil { c.Set("user_id", userID) } } c.Next() }) // product_reviews table for review tests (v0.602 E2E) err = db.Exec(` CREATE TABLE IF NOT EXISTS product_reviews ( id TEXT PRIMARY KEY, product_id TEXT NOT NULL, buyer_id TEXT NOT NULL, order_id TEXT NOT NULL, rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5), comment TEXT, created_at DATETIME, UNIQUE(product_id, buyer_id), FOREIGN KEY(product_id) REFERENCES products(id), FOREIGN KEY(buyer_id) REFERENCES users(id), FOREIGN KEY(order_id) REFERENCES orders(id) ) `).Error require.NoError(t, err) // Setup marketplace routes marketplaceGroup := router.Group("/api/v1/marketplace") { marketplaceGroup.GET("/products", marketHandler.ListProducts) marketplaceGroup.POST("/products", marketHandler.CreateProduct) marketplaceGroup.PUT("/products/:id", marketHandler.UpdateProduct) marketplaceGroup.GET("/orders", marketHandler.ListOrders) marketplaceGroup.GET("/orders/:id", marketHandler.GetOrder) marketplaceGroup.POST("/orders", marketHandler.CreateOrder) marketplaceGroup.GET("/download/:product_id", marketHandler.GetDownloadURL) marketplaceGroup.POST("/products/:id/reviews", marketHandler.CreateReview) marketplaceGroup.GET("/products/:id/reviews", marketHandler.ListReviews) marketplaceGroup.GET("/orders/:id/invoice", marketHandler.GetOrderInvoice) } cleanup := func() { // Database will be closed automatically } return router, db, dbWrapper, marketService, cleanup } // createTestUser crée un utilisateur de test func createTestUser(t *testing.T, db *gorm.DB, email, username string) *models.User { user := &models.User{ ID: uuid.New(), Username: username, Email: email, PasswordHash: "hashed_password", Slug: username, IsActive: true, IsVerified: true, } err := db.Create(user).Error require.NoError(t, err) return user } // createTestTrack crée un track de test func createTestTrack(t *testing.T, db *gorm.DB, userID uuid.UUID, title string) *models.Track { track := &models.Track{ ID: uuid.New(), UserID: userID, Title: title, Artist: "Test Artist", FilePath: fmt.Sprintf("/tracks/%s.mp3", uuid.New().String()), Format: "mp3", FileSize: 5 * 1024 * 1024, Duration: 180, IsPublic: true, Status: models.TrackStatusCompleted, CreatedAt: time.Now(), UpdatedAt: time.Now(), } err := db.Create(track).Error require.NoError(t, err) return track } // TestMarketplaceFlow_CompleteFlow teste le flux complet : création produit → commande → téléchargement func TestMarketplaceFlow_CompleteFlow(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() // Create seller and buyer seller := createTestUser(t, db, "seller@example.com", "seller") buyer := createTestUser(t, db, "buyer@example.com", "buyer") // Create track owned by seller track := createTestTrack(t, db, seller.ID, "My Awesome Track") // Step 1: Seller creates a product createProductReq := handlers.CreateProductRequest{ Title: "My Product", Description: "A great track for sale", Price: 9.99, ProductType: "track", TrackID: track.ID.String(), LicenseType: "standard", } body, _ := json.Marshal(createProductReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/products", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", seller.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusCreated, w.Code) var productResponse map[string]interface{} err := json.Unmarshal(w.Body.Bytes(), &productResponse) require.NoError(t, err) assert.True(t, productResponse["success"].(bool)) // Extract product ID from response productData, ok := productResponse["data"].(map[string]interface{}) require.True(t, ok) productIDStr, ok := productData["id"].(string) require.True(t, ok) productID, err := uuid.Parse(productIDStr) require.NoError(t, err) // Step 2: Buyer creates an order for the product createOrderReq := handlers.CreateOrderRequest{ Items: []struct { ProductID string `json:"product_id" binding:"required" validate:"required,uuid"` }{ {ProductID: productID.String()}, }, } body, _ = json.Marshal(createOrderReq) req = httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/orders", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w = httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusCreated, w.Code) var orderResponse map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &orderResponse) require.NoError(t, err) assert.True(t, orderResponse["success"].(bool)) // Verify order was created with correct status (data is CreateOrderResponse with nested order) orderData, ok := orderResponse["data"].(map[string]interface{}) require.True(t, ok) order, ok := orderData["order"].(map[string]interface{}) require.True(t, ok) assert.Equal(t, "completed", order["status"]) // Step 3: Buyer gets download URL for the purchased product req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/marketplace/download/%s", productID.String()), nil) req.Header.Set("X-User-ID", buyer.ID.String()) w = httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) var downloadResponse map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &downloadResponse) require.NoError(t, err) assert.True(t, downloadResponse["success"].(bool)) // Verify download URL is present downloadData, ok := downloadResponse["data"].(map[string]interface{}) require.True(t, ok) assert.Contains(t, downloadData, "url") assert.NotEmpty(t, downloadData["url"]) } // TestMarketplaceFlow_CompleteFlowWithReviewAndInvoice tests product -> order -> review -> invoice (v0.602 E2E) func TestMarketplaceFlow_CompleteFlowWithReviewAndInvoice(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() seller := createTestUser(t, db, "seller@example.com", "seller") buyer := createTestUser(t, db, "buyer@example.com", "buyer") track := createTestTrack(t, db, seller.ID, "Track For Review") // 1. Create product createProductReq := handlers.CreateProductRequest{ Title: "Product For Review", Description: "Great track", Price: 12.99, ProductType: "track", TrackID: track.ID.String(), LicenseType: "standard", } body, _ := json.Marshal(createProductReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/products", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", seller.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) require.Equal(t, http.StatusCreated, w.Code) var productResp map[string]interface{} require.NoError(t, json.Unmarshal(w.Body.Bytes(), &productResp)) productData := productResp["data"].(map[string]interface{}) productID := productData["id"].(string) // 2. Create order (simulated payment completes immediately) orderBody, _ := json.Marshal(handlers.CreateOrderRequest{ Items: []struct { ProductID string `json:"product_id" binding:"required" validate:"required,uuid"` }{{ProductID: productID}}, }) req = httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/orders", bytes.NewBuffer(orderBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w = httptest.NewRecorder() router.ServeHTTP(w, req) require.Equal(t, http.StatusCreated, w.Code) var orderResp map[string]interface{} require.NoError(t, json.Unmarshal(w.Body.Bytes(), &orderResp)) orderData := orderResp["data"].(map[string]interface{}) order := orderData["order"].(map[string]interface{}) orderID := order["id"].(string) assert.Equal(t, "completed", order["status"]) // 3. Create review reviewBody, _ := json.Marshal(map[string]interface{}{"rating": 5, "comment": "Excellent!"}) req = httptest.NewRequest(http.MethodPost, fmt.Sprintf("/api/v1/marketplace/products/%s/reviews", productID), bytes.NewBuffer(reviewBody)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w = httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusCreated, w.Code) // 4. Download invoice (PDF) req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/marketplace/orders/%s/invoice", orderID), nil) req.Header.Set("X-User-ID", buyer.ID.String()) w = httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "application/pdf", w.Header().Get("Content-Type")) assert.NotEmpty(t, w.Body.Bytes()) } // TestMarketplaceFlow_CreateProduct_Validation teste la validation lors de la création de produit func TestMarketplaceFlow_CreateProduct_Validation(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() seller := createTestUser(t, db, "seller@example.com", "seller") t.Run("Missing required fields", func(t *testing.T) { createProductReq := handlers.CreateProductRequest{ Description: "A great track", Price: 9.99, } body, _ := json.Marshal(createProductReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/products", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", seller.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }) t.Run("Invalid price", func(t *testing.T) { createProductReq := handlers.CreateProductRequest{ Title: "My Product", Description: "A great track", Price: -5.0, // Invalid negative price ProductType: "track", } body, _ := json.Marshal(createProductReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/products", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", seller.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }) t.Run("Invalid product type", func(t *testing.T) { createProductReq := handlers.CreateProductRequest{ Title: "My Product", Description: "A great track", Price: 9.99, ProductType: "invalid_type", } body, _ := json.Marshal(createProductReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/products", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", seller.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }) } // TestMarketplaceFlow_CreateOrder_Validation teste la validation lors de la création de commande func TestMarketplaceFlow_CreateOrder_Validation(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() buyer := createTestUser(t, db, "buyer@example.com", "buyer") t.Run("Empty items", func(t *testing.T) { createOrderReq := handlers.CreateOrderRequest{ Items: []struct { ProductID string `json:"product_id" binding:"required" validate:"required,uuid"` }{}, } body, _ := json.Marshal(createOrderReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/orders", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }) t.Run("Non-existent product", func(t *testing.T) { createOrderReq := handlers.CreateOrderRequest{ Items: []struct { ProductID string `json:"product_id" binding:"required" validate:"required,uuid"` }{ {ProductID: uuid.New().String()}, }, } body, _ := json.Marshal(createOrderReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/orders", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }) } // TestMarketplaceFlow_GetDownloadURL_NoLicense teste le téléchargement sans licence func TestMarketplaceFlow_GetDownloadURL_NoLicense(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() seller := createTestUser(t, db, "seller@example.com", "seller") buyer := createTestUser(t, db, "buyer@example.com", "buyer") // Create track and product track := createTestTrack(t, db, seller.ID, "My Track") product := &marketplace.Product{ ID: uuid.New(), SellerID: seller.ID, Title: "My Product", Description: "A great track", Price: 9.99, ProductType: "track", TrackID: &track.ID, Status: marketplace.ProductStatusActive, CreatedAt: time.Now(), UpdatedAt: time.Now(), } err := db.Create(product).Error require.NoError(t, err) // Try to download without purchasing req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/marketplace/download/%s", product.ID.String()), nil) req.Header.Set("X-User-ID", buyer.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusForbidden, w.Code) } // TestMarketplaceFlow_ListOrders teste la liste des commandes func TestMarketplaceFlow_ListOrders(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() seller := createTestUser(t, db, "seller@example.com", "seller") buyer := createTestUser(t, db, "buyer@example.com", "buyer") // Create track and product track := createTestTrack(t, db, seller.ID, "My Track") product := &marketplace.Product{ ID: uuid.New(), SellerID: seller.ID, Title: "My Product", Description: "A great track", Price: 9.99, ProductType: "track", TrackID: &track.ID, Status: marketplace.ProductStatusActive, CreatedAt: time.Now(), UpdatedAt: time.Now(), } err := db.Create(product).Error require.NoError(t, err) // Create order createOrderReq := handlers.CreateOrderRequest{ Items: []struct { ProductID string `json:"product_id" binding:"required" validate:"required,uuid"` }{ {ProductID: product.ID.String()}, }, } body, _ := json.Marshal(createOrderReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/orders", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusCreated, w.Code) // List orders req = httptest.NewRequest(http.MethodGet, "/api/v1/marketplace/orders", nil) req.Header.Set("X-User-ID", buyer.ID.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)) // Verify orders list data, ok := response["data"].([]interface{}) require.True(t, ok) assert.GreaterOrEqual(t, len(data), 1) } // TestMarketplaceFlow_GetOrder teste la récupération d'une commande spécifique func TestMarketplaceFlow_GetOrder(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() seller := createTestUser(t, db, "seller@example.com", "seller") buyer := createTestUser(t, db, "buyer@example.com", "buyer") // Create track and product track := createTestTrack(t, db, seller.ID, "My Track") product := &marketplace.Product{ ID: uuid.New(), SellerID: seller.ID, Title: "My Product", Description: "A great track", Price: 9.99, ProductType: "track", TrackID: &track.ID, Status: marketplace.ProductStatusActive, CreatedAt: time.Now(), UpdatedAt: time.Now(), } err := db.Create(product).Error require.NoError(t, err) // Create order createOrderReq := handlers.CreateOrderRequest{ Items: []struct { ProductID string `json:"product_id" binding:"required" validate:"required,uuid"` }{ {ProductID: product.ID.String()}, }, } body, _ := json.Marshal(createOrderReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/orders", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusCreated, w.Code) // Extract order ID (data is CreateOrderResponse with nested order) var orderResponse map[string]interface{} err = json.Unmarshal(w.Body.Bytes(), &orderResponse) require.NoError(t, err) orderData, ok := orderResponse["data"].(map[string]interface{}) require.True(t, ok) orderObj, ok := orderData["order"].(map[string]interface{}) require.True(t, ok) orderIDStr, ok := orderObj["id"].(string) require.True(t, ok) // Get order details req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/v1/marketplace/orders/%s", orderIDStr), nil) req.Header.Set("X-User-ID", buyer.ID.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)) // Verify order details orderDetails, ok := response["data"].(map[string]interface{}) require.True(t, ok) assert.Equal(t, orderIDStr, orderDetails["id"].(string)) assert.Equal(t, "completed", orderDetails["status"]) } // TestMarketplaceFlow_CreateOrder_InactiveProduct teste la commande d'un produit inactif func TestMarketplaceFlow_CreateOrder_InactiveProduct(t *testing.T) { router, db, _, _, cleanup := setupMarketplaceFlowTestRouter(t) defer cleanup() seller := createTestUser(t, db, "seller@example.com", "seller") buyer := createTestUser(t, db, "buyer@example.com", "buyer") // Create track and inactive product track := createTestTrack(t, db, seller.ID, "My Track") product := &marketplace.Product{ ID: uuid.New(), SellerID: seller.ID, Title: "My Product", Description: "A great track", Price: 9.99, ProductType: "track", TrackID: &track.ID, Status: marketplace.ProductStatusDraft, // Inactive CreatedAt: time.Now(), UpdatedAt: time.Now(), } err := db.Create(product).Error require.NoError(t, err) // Try to create order for inactive product createOrderReq := handlers.CreateOrderRequest{ Items: []struct { ProductID string `json:"product_id" binding:"required" validate:"required,uuid"` }{ {ProductID: product.ID.String()}, }, } body, _ := json.Marshal(createOrderReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/marketplace/orders", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-User-ID", buyer.ID.String()) w := httptest.NewRecorder() router.ServeHTTP(w, req) assert.Equal(t, http.StatusBadRequest, w.Code) }