package service import ( "baron-sso-backend/internal/domain" "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "gorm.io/gorm" ) func TestTenantService_RegisterTenant_DuplicateSlug(t *testing.T) { mockRepo := new(MockTenantRepoForSvc) svc := NewTenantService(mockRepo, nil, nil, nil) ctx := context.Background() slug := "duplicate-slug" // Mock: slug already exists mockRepo.On("FindBySlug", ctx, slug).Return(&domain.Tenant{ID: "existing-id", Slug: slug}, nil) tenant, err := svc.RegisterTenant(ctx, "New Name", slug, domain.TenantTypeCompany, "", nil, nil, "") assert.Error(t, err) assert.Contains(t, err.Error(), "already exists") assert.Nil(t, tenant) } func TestTenantService_RegisterTenant_InvalidSlug(t *testing.T) { svc := NewTenantService(nil, nil, nil, nil) ctx := context.Background() // Case 1: Too short _, err := svc.RegisterTenant(ctx, "Name", "a", domain.TenantTypeCompany, "", nil, nil, "") assert.Error(t, err) // Case 2: Invalid characters _, err = svc.RegisterTenant(ctx, "Name", "Invalid Slug!", domain.TenantTypeCompany, "", nil, nil, "") assert.Error(t, err) } func TestTenantService_RequestRegistration_EmailMismatch(t *testing.T) { svc := NewTenantService(nil, nil, nil, nil) ctx := context.Background() // admin email domain (gmail.com) != tenant domain (company.com) tenant, err := svc.RequestRegistration(ctx, "Name", "slug", "", "company.com", "admin@gmail.com") assert.Error(t, err) assert.Contains(t, err.Error(), "must match") assert.Nil(t, tenant) } func TestTenantService_ApproveTenant_NotFound(t *testing.T) { mockRepo := new(MockTenantRepoForSvc) svc := NewTenantService(mockRepo, nil, nil, nil) ctx := context.Background() id := "non-existent-id" mockRepo.On("FindByID", ctx, id).Return(nil, gorm.ErrRecordNotFound) err := svc.ApproveTenant(ctx, id) assert.Error(t, err) assert.True(t, errors.Is(err, gorm.ErrRecordNotFound)) } func TestTenantService_GetTenantByDomain_Inactive(t *testing.T) { mockRepo := new(MockTenantRepoForSvc) svc := NewTenantService(mockRepo, nil, nil, nil) ctx := context.Background() domainName := "inactive.com" mockRepo.On("FindByDomain", ctx, domainName).Return(&domain.Tenant{ ID: "t1", Status: domain.TenantStatusPending, }, nil) tenant, err := svc.GetTenantByDomain(ctx, domainName) assert.Error(t, err) assert.Contains(t, err.Error(), "not active") assert.Nil(t, tenant) } func TestTenantService_ApproveTenant_UserNotFound(t *testing.T) { mockRepo := new(MockTenantRepoForSvc) mockUserRepo := new(MockUserRepoForTenant) mockOutbox := new(MockKetoOutboxRepositoryShared) svc := NewTenantService(mockRepo, mockUserRepo, nil, mockOutbox) ctx := context.Background() tenantID := "t1" adminEmail := "notfound@tenant.com" tenant := &domain.Tenant{ ID: tenantID, Slug: "tenant-slug", Config: domain.JSONMap{"adminEmail": adminEmail}, } mockRepo.On("FindByID", ctx, tenantID).Return(tenant, nil) mockRepo.On("Update", ctx, mock.Anything).Return(nil) // User not found in DB mockUserRepo.On("FindByEmail", adminEmail).Return(nil, gorm.ErrRecordNotFound) // Outbox should not be called since user is not found err := svc.ApproveTenant(ctx, tenantID) assert.NoError(t, err) // Should succeed but just log that user is not found mockRepo.AssertExpectations(t) mockUserRepo.AssertExpectations(t) mockOutbox.AssertNotCalled(t, "Create") }