319 lines
9.9 KiB
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")
|
|
}
|
|
|