Migrate from Gin to Echo framework and add comprehensive integration tests

Major changes:
- Migrate all handlers from Gin to Echo framework
- Add new apperrors, echohelpers, and validator packages
- Update middleware for Echo compatibility
- Add ArchivedHandler to task categorization chain (archived tasks go to cancelled_tasks column)
- Add 6 new integration tests:
  - RecurringTaskLifecycle: NextDueDate advancement for weekly/monthly tasks
  - MultiUserSharing: Complex sharing with user removal
  - TaskStateTransitions: All state transitions and kanban column changes
  - DateBoundaryEdgeCases: Threshold boundary testing
  - CascadeOperations: Residence deletion cascade effects
  - MultiUserOperations: Shared residence collaboration
- Add single-purpose repository functions for kanban columns (GetOverdueTasks, GetDueSoonTasks, etc.)
- Fix RemoveUser route param mismatch (userId -> user_id)
- Fix determineExpectedColumn helper to correctly prioritize in_progress over overdue

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-12-16 13:52:08 -06:00
parent c51f1ce34a
commit 6dac34e373
98 changed files with 8209 additions and 4425 deletions

View File

@@ -8,10 +8,11 @@ import (
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/treytartt/casera-api/internal/apperrors"
"github.com/treytartt/casera-api/internal/config"
"github.com/treytartt/casera-api/internal/handlers"
"github.com/treytartt/casera-api/internal/middleware"
@@ -19,19 +20,20 @@ import (
"github.com/treytartt/casera-api/internal/repositories"
"github.com/treytartt/casera-api/internal/services"
"github.com/treytartt/casera-api/internal/testutil"
"github.com/treytartt/casera-api/internal/validator"
"gorm.io/gorm"
)
// SubscriptionTestApp holds components for subscription integration testing
type SubscriptionTestApp struct {
DB *gorm.DB
Router *gin.Engine
Router *echo.Echo
SubscriptionService *services.SubscriptionService
SubscriptionRepo *repositories.SubscriptionRepository
}
func setupSubscriptionTest(t *testing.T) *SubscriptionTestApp {
gin.SetMode(gin.TestMode)
// Echo does not need test mode
db := testutil.SetupTestDB(t)
testutil.SeedLookupData(t, db)
@@ -65,10 +67,12 @@ func setupSubscriptionTest(t *testing.T) *SubscriptionTestApp {
subscriptionHandler := handlers.NewSubscriptionHandler(subscriptionService)
// Create router
router := gin.New()
e := echo.New()
e.Validator = validator.NewCustomValidator()
e.HTTPErrorHandler = apperrors.HTTPErrorHandler
// Public routes
auth := router.Group("/api/auth")
auth := e.Group("/api/auth")
{
auth.POST("/register", authHandler.Register)
auth.POST("/login", authHandler.Login)
@@ -76,7 +80,7 @@ func setupSubscriptionTest(t *testing.T) *SubscriptionTestApp {
// Protected routes
authMiddleware := middleware.NewAuthMiddleware(db, nil)
api := router.Group("/api")
api := e.Group("/api")
api.Use(authMiddleware.TokenAuth())
{
api.GET("/auth/me", authHandler.CurrentUser)
@@ -95,7 +99,7 @@ func setupSubscriptionTest(t *testing.T) *SubscriptionTestApp {
return &SubscriptionTestApp{
DB: db,
Router: router,
Router: e,
SubscriptionService: subscriptionService,
SubscriptionRepo: subscriptionRepo,
}
@@ -247,7 +251,10 @@ func TestIntegration_IsFreeBypassesCheckLimit(t *testing.T) {
// Second property should fail
err = app.SubscriptionService.CheckLimit(userID, "properties")
assert.Error(t, err, "Second property should be blocked for normal free user")
assert.Equal(t, services.ErrPropertiesLimitExceeded, err)
var appErr *apperrors.AppError
require.ErrorAs(t, err, &appErr)
assert.Equal(t, http.StatusForbidden, appErr.Code)
assert.Equal(t, "error.properties_limit_exceeded", appErr.MessageKey)
// ========== Test 2: Set IsFree=true ==========
sub.IsFree = true