- Add subscription module (models, service, tests) - Plans: Free, Creator ($9.99/mo), Premium ($19.99/mo) - Features: subscribe, cancel, reactivate, change billing cycle - 14-day trial for Premium plan - Upgrade immediate, downgrade at period end - Invoice tracking and history - Handler tests for auth and validation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
148 lines
4.1 KiB
Go
148 lines
4.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"go.uber.org/zap"
|
|
|
|
"veza-backend-api/internal/core/subscription"
|
|
)
|
|
|
|
func TestNewSubscriptionHandler(t *testing.T) {
|
|
logger := zap.NewNop()
|
|
svc := subscription.NewService(nil, logger)
|
|
handler := NewSubscriptionHandler(svc, logger)
|
|
|
|
if handler == nil {
|
|
t.Fatal("expected non-nil handler")
|
|
}
|
|
if handler.service == nil {
|
|
t.Error("expected non-nil service")
|
|
}
|
|
if handler.logger == nil {
|
|
t.Error("expected non-nil logger")
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionHandler_GetMySubscription_NoAuth(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
logger := zap.NewNop()
|
|
svc := subscription.NewService(nil, logger)
|
|
handler := NewSubscriptionHandler(svc, logger)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest(http.MethodGet, "/subscriptions/me", nil)
|
|
|
|
handler.GetMySubscription(c)
|
|
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected 401, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionHandler_Subscribe_NoAuth(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
logger := zap.NewNop()
|
|
svc := subscription.NewService(nil, logger)
|
|
handler := NewSubscriptionHandler(svc, logger)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest(http.MethodPost, "/subscriptions/subscribe", strings.NewReader(`{}`))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
handler.Subscribe(c)
|
|
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected 401, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionHandler_Subscribe_InvalidBody(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
logger := zap.NewNop()
|
|
svc := subscription.NewService(nil, logger)
|
|
handler := NewSubscriptionHandler(svc, logger)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Set("user_id", uuid.New())
|
|
c.Request = httptest.NewRequest(http.MethodPost, "/subscriptions/subscribe", strings.NewReader(`{}`))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
handler.Subscribe(c)
|
|
|
|
// Should get validation error since plan_id and billing_cycle are missing
|
|
var resp map[string]interface{}
|
|
if err := json.NewDecoder(w.Body).Decode(&resp); err != nil {
|
|
t.Fatalf("failed to decode response: %v", err)
|
|
}
|
|
|
|
if resp["success"] != false {
|
|
t.Error("expected success=false for invalid request")
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionHandler_CancelSubscription_NoAuth(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
logger := zap.NewNop()
|
|
svc := subscription.NewService(nil, logger)
|
|
handler := NewSubscriptionHandler(svc, logger)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest(http.MethodPost, "/subscriptions/cancel", nil)
|
|
|
|
handler.CancelSubscription(c)
|
|
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected 401, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionHandler_GetPlan_InvalidID(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
logger := zap.NewNop()
|
|
svc := subscription.NewService(nil, logger)
|
|
handler := NewSubscriptionHandler(svc, logger)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{{Key: "id", Value: "not-a-uuid"}}
|
|
c.Request = httptest.NewRequest(http.MethodGet, "/subscriptions/plans/not-a-uuid", nil)
|
|
|
|
handler.GetPlan(c)
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.NewDecoder(w.Body).Decode(&resp); err != nil {
|
|
t.Fatalf("failed to decode response: %v", err)
|
|
}
|
|
if resp["success"] != false {
|
|
t.Error("expected success=false for invalid plan ID")
|
|
}
|
|
}
|
|
|
|
func TestSubscriptionHandler_ChangeBillingCycle_NoAuth(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
logger := zap.NewNop()
|
|
svc := subscription.NewService(nil, logger)
|
|
handler := NewSubscriptionHandler(svc, logger)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest(http.MethodPut, "/subscriptions/billing-cycle", strings.NewReader(`{"billing_cycle":"yearly"}`))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
handler.ChangeBillingCycle(c)
|
|
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected 401, got %d", w.Code)
|
|
}
|
|
}
|