veza/veza-backend-api/tests/integration/track_quota_test.go

319 lines
9.9 KiB
Go

//go:build integration
// +build integration
package integration
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"veza-backend-api/internal/core/track"
"veza-backend-api/internal/models"
"veza-backend-api/internal/services"
"veza-backend-api/tests/testutils"
)
// TestTrackQuotaEndpoint_GetQuota tests the GET /api/v1/tracks/quota/:id endpoint
// BE-API-026: Verify GET /api/v1/tracks/quota/:id returns correct upload quota info
func TestTrackQuotaEndpoint_GetQuota(t *testing.T) {
ctx := context.Background()
gin.SetMode(gin.TestMode)
// Setup PostgreSQL via testcontainers
dsn, err := testutils.GetTestContainerDB(ctx)
if err != nil {
t.Skipf("Skipping test: PostgreSQL testcontainer not available: %v", err)
return
}
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
require.NoError(t, err)
// Create test user
userID := uuid.New()
userIDShort := userID.String()[:8]
usernameSafe := fmt.Sprintf("test_%s", userIDShort)
user := &models.User{
ID: userID,
Email: fmt.Sprintf("test_quota_%s@example.com", userIDShort),
Username: usernameSafe,
IsActive: true,
}
require.NoError(t, db.Create(user).Error)
logger := zap.NewNop()
uploadDir := t.TempDir()
trackService := track.NewTrackService(db, logger, uploadDir)
trackUploadService := services.NewTrackUploadService(db, logger)
chunkService := services.NewTrackChunkService(uploadDir+"/chunks", nil, logger)
likeService := services.NewTrackLikeService(db, logger)
streamService := services.NewStreamService("", logger)
trackHandler := track.NewTrackHandler(trackService, trackUploadService, chunkService, likeService, streamService)
// Setup router
router := gin.New()
router.Use(func(c *gin.Context) {
c.Set("user_id", userID)
c.Next()
})
api := router.Group("/api/v1")
api.GET("/tracks/quota/:id", trackHandler.GetUploadQuota)
// Test 1: Get quota for user with no tracks (empty quota)
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/tracks/quota/%s", userID.String()), nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code, "Should return 200 OK: %s", w.Body.String())
var resp map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &resp)
require.NoError(t, err)
require.True(t, resp["success"].(bool))
data := resp["data"].(map[string]interface{})
quota := data["quota"].(map[string]interface{})
// Verify initial quota (empty)
assert.Equal(t, float64(0), quota["tracks_count"], "Should have 0 tracks initially")
assert.Equal(t, float64(1000), quota["tracks_limit"], "Should have limit of 1000 tracks")
assert.Equal(t, float64(0), quota["storage_used"], "Should have 0 bytes used initially")
assert.Equal(t, float64(100*1024*1024*1024), quota["storage_limit"], "Should have limit of 100GB")
// Test 2: Create some tracks and verify quota updates
track1 := &models.Track{
ID: uuid.New(),
Title: "Test Track 1",
CreatorID: userID,
FileSize: 5 * 1024 * 1024, // 5MB
IsPublic: true,
}
require.NoError(t, db.Create(track1).Error)
track2 := &models.Track{
ID: uuid.New(),
Title: "Test Track 2",
CreatorID: userID,
FileSize: 10 * 1024 * 1024, // 10MB
IsPublic: true,
}
require.NoError(t, db.Create(track2).Error)
// Get quota again
req2 := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/tracks/quota/%s", userID.String()), nil)
w2 := httptest.NewRecorder()
router.ServeHTTP(w2, req2)
require.Equal(t, http.StatusOK, w2.Code)
var resp2 map[string]interface{}
err = json.Unmarshal(w2.Body.Bytes(), &resp2)
require.NoError(t, err)
require.True(t, resp2["success"].(bool))
data2 := resp2["data"].(map[string]interface{})
quota2 := data2["quota"].(map[string]interface{})
// Verify updated quota
assert.Equal(t, float64(2), quota2["tracks_count"], "Should have 2 tracks")
assert.Equal(t, float64(1000), quota2["tracks_limit"], "Should still have limit of 1000 tracks")
assert.Equal(t, float64(15*1024*1024), quota2["storage_used"], "Should have 15MB used (5MB + 10MB)")
assert.Equal(t, float64(100*1024*1024*1024), quota2["storage_limit"], "Should still have limit of 100GB")
}
// TestTrackQuotaEndpoint_WithMe tests the endpoint with "me" parameter
func TestTrackQuotaEndpoint_WithMe(t *testing.T) {
ctx := context.Background()
gin.SetMode(gin.TestMode)
dsn, err := testutils.GetTestContainerDB(ctx)
if err != nil {
t.Skipf("Skipping test: PostgreSQL testcontainer not available: %v", err)
return
}
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
require.NoError(t, err)
userID := uuid.New()
userIDShort := userID.String()[:8]
usernameSafe := fmt.Sprintf("test_%s", userIDShort)
user := &models.User{
ID: userID,
Email: fmt.Sprintf("test_quota_me_%s@example.com", userIDShort),
Username: usernameSafe,
IsActive: true,
}
require.NoError(t, db.Create(user).Error)
logger := zap.NewNop()
uploadDir := t.TempDir()
trackService := track.NewTrackService(db, logger, uploadDir)
trackUploadService := services.NewTrackUploadService(db, logger)
chunkService := services.NewTrackChunkService(uploadDir+"/chunks", nil, logger)
likeService := services.NewTrackLikeService(db, logger)
streamService := services.NewStreamService("", logger)
trackHandler := track.NewTrackHandler(trackService, trackUploadService, chunkService, likeService, streamService)
router := gin.New()
router.Use(func(c *gin.Context) {
c.Set("user_id", userID)
c.Next()
})
api := router.Group("/api/v1")
api.GET("/tracks/quota/:id", trackHandler.GetUploadQuota)
// Test with "me" parameter
req := httptest.NewRequest("GET", "/api/v1/tracks/quota/me", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code, "Should return 200 OK: %s", w.Body.String())
var resp map[string]interface{}
err = json.Unmarshal(w.Body.Bytes(), &resp)
require.NoError(t, err)
require.True(t, resp["success"].(bool))
data := resp["data"].(map[string]interface{})
quota := data["quota"].(map[string]interface{})
// Verify quota structure
assert.NotNil(t, quota["tracks_count"])
assert.NotNil(t, quota["tracks_limit"])
assert.NotNil(t, quota["storage_used"])
assert.NotNil(t, quota["storage_limit"])
}
// TestTrackQuotaEndpoint_Unauthorized tests that users cannot see other users' quotas
func TestTrackQuotaEndpoint_Unauthorized(t *testing.T) {
ctx := context.Background()
gin.SetMode(gin.TestMode)
dsn, err := testutils.GetTestContainerDB(ctx)
if err != nil {
t.Skipf("Skipping test: PostgreSQL testcontainer not available: %v", err)
return
}
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
require.NoError(t, err)
// Create two users
user1ID := uuid.New()
user2ID := uuid.New()
user1 := &models.User{
ID: user1ID,
Email: fmt.Sprintf("test_user1_%s@example.com", user1ID.String()[:8]),
Username: fmt.Sprintf("test_user1_%s", user1ID.String()[:8]),
IsActive: true,
}
user2 := &models.User{
ID: user2ID,
Email: fmt.Sprintf("test_user2_%s@example.com", user2ID.String()[:8]),
Username: fmt.Sprintf("test_user2_%s", user2ID.String()[:8]),
IsActive: true,
}
require.NoError(t, db.Create(user1).Error)
require.NoError(t, db.Create(user2).Error)
logger := zap.NewNop()
uploadDir := t.TempDir()
trackService := track.NewTrackService(db, logger, uploadDir)
trackUploadService := services.NewTrackUploadService(db, logger)
chunkService := services.NewTrackChunkService(uploadDir+"/chunks", nil, logger)
likeService := services.NewTrackLikeService(db, logger)
streamService := services.NewStreamService("", logger)
trackHandler := track.NewTrackHandler(trackService, trackUploadService, chunkService, likeService, streamService)
// User1 tries to access user2's quota
router := gin.New()
router.Use(func(c *gin.Context) {
c.Set("user_id", user1ID) // Authenticated as user1
c.Next()
})
api := router.Group("/api/v1")
api.GET("/tracks/quota/:id", trackHandler.GetUploadQuota)
req := httptest.NewRequest("GET", fmt.Sprintf("/api/v1/tracks/quota/%s", user2ID.String()), nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusForbidden, w.Code, "Should return 403 Forbidden for other user's quota")
}
// TestTrackQuotaEndpoint_InvalidUserID tests that invalid user ID returns 400
func TestTrackQuotaEndpoint_InvalidUserID(t *testing.T) {
ctx := context.Background()
gin.SetMode(gin.TestMode)
dsn, err := testutils.GetTestContainerDB(ctx)
if err != nil {
t.Skipf("Skipping test: PostgreSQL testcontainer not available: %v", err)
return
}
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
require.NoError(t, err)
userID := uuid.New()
userIDShort := userID.String()[:8]
usernameSafe := fmt.Sprintf("test_%s", userIDShort)
user := &models.User{
ID: userID,
Email: fmt.Sprintf("test_quota_invalid_%s@example.com", userIDShort),
Username: usernameSafe,
IsActive: true,
}
require.NoError(t, db.Create(user).Error)
logger := zap.NewNop()
uploadDir := t.TempDir()
trackService := track.NewTrackService(db, logger, uploadDir)
trackUploadService := services.NewTrackUploadService(db, logger)
chunkService := services.NewTrackChunkService(uploadDir+"/chunks", nil, logger)
likeService := services.NewTrackLikeService(db, logger)
streamService := services.NewStreamService("", logger)
trackHandler := track.NewTrackHandler(trackService, trackUploadService, chunkService, likeService, streamService)
router := gin.New()
router.Use(func(c *gin.Context) {
c.Set("user_id", userID)
c.Next()
})
api := router.Group("/api/v1")
api.GET("/tracks/quota/:id", trackHandler.GetUploadQuota)
// Test with invalid UUID
req := httptest.NewRequest("GET", "/api/v1/tracks/quota/invalid-uuid", nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code, "Should return 400 Bad Request for invalid UUID")
}