package handler import ( "baron-sso-backend/internal/domain" "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/gofiber/fiber/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) // --- Local Mocks for Signup Test --- type MockRedisForSignup struct { mock.Mock } func (m *MockRedisForSignup) Set(key string, value string, ttl time.Duration) error { return m.Called(key, value, ttl).Error(0) } func (m *MockRedisForSignup) Get(key string) (string, error) { args := m.Called(key) return args.String(0), args.Error(1) } func (m *MockRedisForSignup) Delete(key string) error { return m.Called(key).Error(0) } func (m *MockRedisForSignup) StoreVerificationCode(phone, code string) error { return nil } func (m *MockRedisForSignup) GetVerificationCode(phone string) (string, error) { return "", nil } func (m *MockRedisForSignup) DeleteVerificationCode(phone string) error { return nil } func (m *MockRedisForSignup) Ping(ctx context.Context) error { return nil } type MockIdpForSignup struct { mock.Mock } func (m *MockIdpForSignup) Name() string { return "mock-idp" } func (m *MockIdpForSignup) GetMetadata() (*domain.IDPMetadata, error) { return &domain.IDPMetadata{SupportedFields: []string{"email", "name", "phoneNumber", "grade", "department"}}, nil } func (m *MockIdpForSignup) CreateUser(user *domain.BrokerUser, password string) (string, error) { args := m.Called(user, password) return args.String(0), args.Error(1) } func (m *MockIdpForSignup) SignIn(loginID, password string) (*domain.AuthInfo, error) { return nil, nil } func (m *MockIdpForSignup) UserExists(loginID string) (bool, error) { return false, nil } func (m *MockIdpForSignup) IssueSession(loginID string) (*domain.AuthInfo, error) { return nil, nil } func (m *MockIdpForSignup) InitiateLinkLogin(loginID, returnTo string) (*domain.LinkLoginInit, error) { return nil, nil } func (m *MockIdpForSignup) VerifyLoginCode(loginID, flowID, code string) (*domain.AuthInfo, error) { return nil, nil } func (m *MockIdpForSignup) GetPasswordPolicy() (*domain.PasswordPolicy, error) { return &domain.PasswordPolicy{MinLength: 12}, nil } func (m *MockIdpForSignup) InitiatePasswordReset(loginID, redirectUrl string) error { return nil } func (m *MockIdpForSignup) VerifyPasswordResetToken(token string) (*domain.AuthInfo, error) { return nil, nil } func (m *MockIdpForSignup) UpdateUserPassword(loginID, newPassword string, r *http.Request) error { return nil } func TestSignup_TenantSlugValidation(t *testing.T) { app := fiber.New() mockTenantSvc := new(MockTenantService) mockRedis := new(MockRedisForSignup) mockIdp := new(MockIdpForSignup) h := &AuthHandler{ TenantService: mockTenantSvc, RedisService: mockRedis, IdpProvider: mockIdp, } app.Post("/signup", h.Signup) // Prepare mock state (already verified email/phone) verifiedState, _ := json.Marshal(map[string]any{ "verified": true, "expires_at": time.Now().Add(time.Hour).Unix(), }) mockRedis.On("Get", mock.Anything).Return(string(verifiedState), nil) t.Run("Rejects legacy CompanyCode", func(t *testing.T) { reqBody := domain.SignupRequest{ Email: "user@gmail.com", Password: "StrongPass123!", Name: "Test User", Phone: "010-1234-5678", TermsAccepted: true, CompanyCode: "new-slug", } body, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", "/signup", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, _ := app.Test(req) assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) t.Run("Active Tenant Slug", func(t *testing.T) { reqBody := domain.SignupRequest{ Email: "user@hanmaceng.co.kr", Password: "StrongPass123!", Name: "Test User", Phone: "010-1234-5678", TermsAccepted: true, TenantSlug: "hanmac", } body, _ := json.Marshal(reqBody) validTenant := &domain.Tenant{ID: "t1", Slug: "hanmac", Status: domain.TenantStatusActive} mockTenantSvc.On("GetTenantByDomain", mock.Anything, "hanmaceng.co.kr").Return(&domain.Tenant{Slug: "hanmac"}, nil).Once() mockTenantSvc.On("ProvisionTenantByDomain", mock.Anything, "hanmaceng.co.kr").Return(validTenant, nil).Maybe() mockTenantSvc.On("GetTenantBySlug", mock.Anything, "hanmac").Return(validTenant, nil).Once() mockTenantSvc.On("GetTenant", mock.Anything, "t1").Return(validTenant, nil).Once() mockIdp.On("CreateUser", mock.Anything, mock.Anything).Return("user-id", nil).Once() mockRedis.On("Delete", mock.Anything).Return(nil) req := httptest.NewRequest("POST", "/signup", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") resp, _ := app.Test(req) assert.Equal(t, http.StatusOK, resp.StatusCode) }) }