package net.siegeln.cameleer.saas.tenant; import net.siegeln.cameleer.saas.audit.AuditAction; import net.siegeln.cameleer.saas.audit.AuditService; import net.siegeln.cameleer.saas.environment.EnvironmentService; import net.siegeln.cameleer.saas.identity.LogtoManagementClient; import net.siegeln.cameleer.saas.tenant.dto.CreateTenantRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Optional; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class TenantServiceTest { @Mock private TenantRepository tenantRepository; @Mock private AuditService auditService; @Mock private LogtoManagementClient logtoClient; @Mock private EnvironmentService environmentService; private TenantService tenantService; @BeforeEach void setUp() { tenantService = new TenantService(tenantRepository, auditService, logtoClient, environmentService); } @Test void create_savesNewTenantWithCorrectFields() { var request = new CreateTenantRequest("Acme Corp", "acme-corp", "MID"); var actorId = UUID.randomUUID(); when(tenantRepository.existsBySlug("acme-corp")).thenReturn(false); when(tenantRepository.save(any(TenantEntity.class))).thenAnswer(inv -> inv.getArgument(0)); var result = tenantService.create(request, actorId); assertThat(result.getName()).isEqualTo("Acme Corp"); assertThat(result.getSlug()).isEqualTo("acme-corp"); assertThat(result.getTier()).isEqualTo(Tier.MID); assertThat(result.getStatus()).isEqualTo(TenantStatus.PROVISIONING); } @Test void create_throwsForDuplicateSlug() { var request = new CreateTenantRequest("Acme Corp", "acme-corp", null); when(tenantRepository.existsBySlug("acme-corp")).thenReturn(true); assertThatThrownBy(() -> tenantService.create(request, UUID.randomUUID())) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("Slug already taken"); } @Test void create_logsAuditEvent() { var request = new CreateTenantRequest("Acme Corp", "acme-corp", null); var actorId = UUID.randomUUID(); when(tenantRepository.existsBySlug("acme-corp")).thenReturn(false); when(tenantRepository.save(any(TenantEntity.class))).thenAnswer(inv -> inv.getArgument(0)); tenantService.create(request, actorId); var actionCaptor = ArgumentCaptor.forClass(AuditAction.class); verify(auditService).log(any(), any(), any(), actionCaptor.capture(), any(), any(), any(), any(), any()); assertThat(actionCaptor.getValue()).isEqualTo(AuditAction.TENANT_CREATE); } @Test void create_defaultsToLowTier() { var request = new CreateTenantRequest("Acme Corp", "acme-corp", null); when(tenantRepository.existsBySlug("acme-corp")).thenReturn(false); when(tenantRepository.save(any(TenantEntity.class))).thenAnswer(inv -> inv.getArgument(0)); var result = tenantService.create(request, UUID.randomUUID()); assertThat(result.getTier()).isEqualTo(Tier.LOW); } @Test void getById_returnsTenant() { var id = UUID.randomUUID(); var entity = new TenantEntity(); entity.setName("Test"); entity.setSlug("test"); when(tenantRepository.findById(id)).thenReturn(Optional.of(entity)); var result = tenantService.getById(id); assertThat(result).isPresent(); assertThat(result.get().getName()).isEqualTo("Test"); } @Test void getBySlug_returnsTenant() { var entity = new TenantEntity(); entity.setName("Test"); entity.setSlug("test"); when(tenantRepository.findBySlug("test")).thenReturn(Optional.of(entity)); var result = tenantService.getBySlug("test"); assertThat(result).isPresent(); assertThat(result.get().getSlug()).isEqualTo("test"); } }