From 8546dcc5081c4182f903fdaeed5891bd2600e565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20M=C3=BCller?= Date: Wed, 22 Jul 2026 07:42:47 +0200 Subject: [PATCH] test(iam,community): add unit tests for AuthService, AdminIamService, EnergyCommunityService - AuthServiceTest: register, login, verifyEmail (7 tests) - AdminIamServiceTest: approve, reject, getPendingUsers (7 tests) - EnergyCommunityServiceTest: CRUD, member counts, delete guards (9 tests) --- .../service/EnergyCommunityServiceTest.java | 169 ++++++++++++++++++ .../iam/service/AdminIamServiceTest.java | 127 +++++++++++++ .../backend/iam/service/AuthServiceTest.java | 160 +++++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 eeg_backend/src/test/java/at/mueller/eeg/backend/community/service/EnergyCommunityServiceTest.java create mode 100644 eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AdminIamServiceTest.java create mode 100644 eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AuthServiceTest.java diff --git a/eeg_backend/src/test/java/at/mueller/eeg/backend/community/service/EnergyCommunityServiceTest.java b/eeg_backend/src/test/java/at/mueller/eeg/backend/community/service/EnergyCommunityServiceTest.java new file mode 100644 index 0000000..e42729c --- /dev/null +++ b/eeg_backend/src/test/java/at/mueller/eeg/backend/community/service/EnergyCommunityServiceTest.java @@ -0,0 +1,169 @@ +package at.mueller.eeg.backend.community.service; + +import at.mueller.eeg.backend.community.api.dto.EnergyCommunityDto; +import at.mueller.eeg.backend.community.domain.CommunityType; +import at.mueller.eeg.backend.community.domain.EnergyCommunity; +import at.mueller.eeg.backend.community.mapper.EnergyCommunityMapper; +import at.mueller.eeg.backend.community.repository.EnergyCommunityRepository; +import at.mueller.eeg.backend.community.repository.MembershipRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.web.server.ResponseStatusException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class EnergyCommunityServiceTest { + + @Mock + private EnergyCommunityRepository energyCommunityRepository; + + @Mock + private MembershipRepository membershipRepository; + + @Mock + private EnergyCommunityMapper energyCommunityMapper; + + @InjectMocks + private EnergyCommunityService energyCommunityService; + + private EnergyCommunity testCommunity; + private UUID testCommunityId; + + @BeforeEach + void setUp() { + testCommunityId = UUID.randomUUID(); + + testCommunity = new EnergyCommunity(); + testCommunity.setId(testCommunityId); + testCommunity.setEdaEcId("EEG-001"); + testCommunity.setType(CommunityType.EEG_LOKAL); + testCommunity.setName("Test-Energiegemeinschaft"); + testCommunity.setGridOperatorId("GridOp-01"); + testCommunity.setSubstationId("UW-01"); + testCommunity.setTransformerId("Trafo-01"); + } + + private List memberCountRow(UUID communityId, long count) { + List rows = new ArrayList<>(); + rows.add(new Object[]{communityId, count}); + return rows; + } + + @Test + void getAllCommunitiesForAdmin() { + when(energyCommunityRepository.findAll()).thenReturn(List.of(testCommunity)); + doReturn(memberCountRow(testCommunityId, 5L)) + .when(membershipRepository).countActiveMembersForCommunities(List.of(testCommunityId)); + + List result = energyCommunityService.getAllCommunitiesForAdmin(); + + assertEquals(1, result.size()); + assertEquals("Test-Energiegemeinschaft", result.get(0).name()); + } + + @Test + void getCommunityById_success() { + when(energyCommunityRepository.findById(testCommunityId)).thenReturn(Optional.of(testCommunity)); + doReturn(memberCountRow(testCommunityId, 3L)) + .when(membershipRepository).countActiveMembersForCommunities(List.of(testCommunityId)); + + EnergyCommunityDto result = energyCommunityService.getCommunityById(testCommunityId); + + assertNotNull(result); + assertEquals("Test-Energiegemeinschaft", result.name()); + } + + @Test + void getCommunityById_notFound_throws() { + UUID unknownId = UUID.randomUUID(); + when(energyCommunityRepository.findById(unknownId)).thenReturn(Optional.empty()); + + assertThrows(IllegalArgumentException.class, () -> energyCommunityService.getCommunityById(unknownId)); + } + + @Test + void create_success() { + EnergyCommunityDto dto = new EnergyCommunityDto(null, "EEG-002", CommunityType.EEG_REGIONAL, + "Neue EG", "GridOp-02", "UW-02", "Trafo-02", 0); + + when(energyCommunityMapper.toEntity(any(), any())).thenReturn(testCommunity); + when(energyCommunityRepository.save(any())).thenReturn(testCommunity); + when(energyCommunityMapper.toDto(any(), eq(0))) + .thenReturn(new EnergyCommunityDto(testCommunityId, "EEG-001", CommunityType.EEG_LOKAL, + "Test-Energiegemeinschaft", "GridOp-01", "UW-01", "Trafo-01", 0)); + + EnergyCommunityDto result = energyCommunityService.create(dto); + + assertNotNull(result); + verify(energyCommunityRepository).save(any()); + } + + @Test + void update_success() { + EnergyCommunityDto dto = new EnergyCommunityDto(null, "EEG-001-UPDATED", CommunityType.EEG_LOKAL, + "Update EG", "GridOp-01", "UW-01", "Trafo-01", 0); + + when(energyCommunityRepository.findById(testCommunityId)).thenReturn(Optional.of(testCommunity)); + when(energyCommunityRepository.save(any())).thenReturn(testCommunity); + doReturn(memberCountRow(testCommunityId, 2L)) + .when(membershipRepository).countActiveMembersForCommunities(List.of(testCommunityId)); + when(energyCommunityMapper.toDto(any(), anyInt())) + .thenReturn(new EnergyCommunityDto(testCommunityId, "EEG-001-UPDATED", CommunityType.EEG_LOKAL, + "Update EG", "GridOp-01", "UW-01", "Trafo-01", 2)); + + EnergyCommunityDto result = energyCommunityService.update(testCommunityId, dto); + + assertNotNull(result); + verify(energyCommunityRepository).save(any()); + } + + @Test + void update_notFound_throws() { + UUID unknownId = UUID.randomUUID(); + EnergyCommunityDto dto = new EnergyCommunityDto(null, "EEG-002", CommunityType.EEG_REGIONAL, + "Neue EG", "GridOp-02", "UW-02", "Trafo-02", 0); + + when(energyCommunityRepository.findById(unknownId)).thenReturn(Optional.empty()); + + assertThrows(ResponseStatusException.class, () -> energyCommunityService.update(unknownId, dto)); + } + + @Test + void delete_success() { + when(energyCommunityRepository.existsById(testCommunityId)).thenReturn(true); + when(membershipRepository.existsByEnergyCommunityId(testCommunityId)).thenReturn(false); + + energyCommunityService.delete(testCommunityId); + + verify(energyCommunityRepository).deleteById(testCommunityId); + } + + @Test + void delete_withMemberships_throws() { + when(energyCommunityRepository.existsById(testCommunityId)).thenReturn(true); + when(membershipRepository.existsByEnergyCommunityId(testCommunityId)).thenReturn(true); + + assertThrows(ResponseStatusException.class, () -> energyCommunityService.delete(testCommunityId)); + verify(energyCommunityRepository, never()).deleteById(any()); + } + + @Test + void delete_notFound_throws() { + UUID unknownId = UUID.randomUUID(); + when(energyCommunityRepository.existsById(unknownId)).thenReturn(false); + + assertThrows(IllegalArgumentException.class, () -> energyCommunityService.delete(unknownId)); + } +} diff --git a/eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AdminIamServiceTest.java b/eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AdminIamServiceTest.java new file mode 100644 index 0000000..4e1c9d4 --- /dev/null +++ b/eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AdminIamServiceTest.java @@ -0,0 +1,127 @@ +package at.mueller.eeg.backend.iam.service; + +import at.mueller.eeg.backend.common.event.UserApprovedEvent; +import at.mueller.eeg.backend.common.event.UserRejectedEvent; +import at.mueller.eeg.backend.iam.domain.RegistrationStatus; +import at.mueller.eeg.backend.iam.domain.User; +import at.mueller.eeg.backend.iam.repository.UserRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.web.server.ResponseStatusException; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AdminIamServiceTest { + + @Mock + private UserRepository userRepository; + + @Mock + private ApplicationEventPublisher eventPublisher; + + @InjectMocks + private AdminIamService adminIamService; + + private User testUser; + + @BeforeEach + void setUp() { + testUser = new User(); + testUser.setId(UUID.randomUUID()); + testUser.setEmail("test@example.com"); + testUser.setFirstName("Test"); + testUser.setLastName("Benutzer"); + testUser.setStatus(RegistrationStatus.PENDING); + testUser.setEnabled(false); + testUser.setEmailVerified(true); + } + + @Test + void getPendingUsers() { + when(userRepository.findAllByStatusAndEmailVerified(RegistrationStatus.PENDING, true)) + .thenReturn(List.of(testUser)); + + List result = adminIamService.getPendingUsers(); + + assertEquals(1, result.size()); + assertEquals("test@example.com", result.get(0).getEmail()); + } + + @Test + void approveUser_success() { + when(userRepository.findById(testUser.getId())).thenReturn(Optional.of(testUser)); + when(userRepository.save(any())).thenReturn(testUser); + + adminIamService.approveUser(testUser.getId()); + + assertEquals(RegistrationStatus.APPROVED, testUser.getStatus()); + assertTrue(testUser.isEnabled()); + verify(eventPublisher).publishEvent(any(UserApprovedEvent.class)); + } + + @Test + void approveUser_notPending_throws() { + testUser.setStatus(RegistrationStatus.APPROVED); + when(userRepository.findById(testUser.getId())).thenReturn(Optional.of(testUser)); + + assertThrows(IllegalStateException.class, () -> adminIamService.approveUser(testUser.getId())); + verify(userRepository, never()).save(any()); + } + + @Test + void approveUser_alreadyEnabled_throws() { + testUser.setEnabled(true); + when(userRepository.findById(testUser.getId())).thenReturn(Optional.of(testUser)); + + assertThrows(IllegalStateException.class, () -> adminIamService.approveUser(testUser.getId())); + verify(userRepository, never()).save(any()); + } + + @Test + void approveUser_notFound_throws() { + UUID unknownId = UUID.randomUUID(); + when(userRepository.findById(unknownId)).thenReturn(Optional.empty()); + + assertThrows(IllegalArgumentException.class, () -> adminIamService.approveUser(unknownId)); + } + + @Test + void rejectUser_success() { + when(userRepository.findById(testUser.getId())).thenReturn(Optional.of(testUser)); + when(userRepository.save(any())).thenReturn(testUser); + + adminIamService.rejectUser(testUser.getId()); + + assertEquals(RegistrationStatus.REJECTED, testUser.getStatus()); + verify(eventPublisher).publishEvent(any(UserRejectedEvent.class)); + } + + @Test + void rejectUser_notPending_throws() { + testUser.setStatus(RegistrationStatus.APPROVED); + when(userRepository.findById(testUser.getId())).thenReturn(Optional.of(testUser)); + + assertThrows(ResponseStatusException.class, () -> adminIamService.rejectUser(testUser.getId())); + verify(userRepository, never()).save(any()); + } + + @Test + void rejectUser_notFound_throws() { + UUID unknownId = UUID.randomUUID(); + when(userRepository.findById(unknownId)).thenReturn(Optional.empty()); + + assertThrows(ResponseStatusException.class, () -> adminIamService.rejectUser(unknownId)); + } +} diff --git a/eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AuthServiceTest.java b/eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AuthServiceTest.java new file mode 100644 index 0000000..e3563f5 --- /dev/null +++ b/eeg_backend/src/test/java/at/mueller/eeg/backend/iam/service/AuthServiceTest.java @@ -0,0 +1,160 @@ +package at.mueller.eeg.backend.iam.service; + +import at.mueller.eeg.backend.iam.api.dto.IamDtos; +import at.mueller.eeg.backend.iam.domain.ParticipantType; +import at.mueller.eeg.backend.iam.domain.User; +import at.mueller.eeg.backend.iam.mapper.UserMapper; +import at.mueller.eeg.backend.iam.repository.UserRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AuthServiceTest { + + @Mock + private AuthenticationManager authenticationManager; + + @Mock + private JwtEncoder jwtEncoder; + + @Mock + private UserRepository userRepository; + + @Mock + private UserMapper userMapper; + + @Mock + private ApplicationEventPublisher eventPublisher; + + @Mock + private MailService mailService; + + @InjectMocks + private AuthService authService; + + private User testUser; + + @BeforeEach + void setUp() { + testUser = new User(); + testUser.setId(UUID.randomUUID()); + testUser.setEmail("test@example.com"); + testUser.setPasswordHash("$2a$10$encodedPassword"); + testUser.setFirstName("Test"); + testUser.setLastName("Benutzer"); + } + + @Test + void register_success() { + IamDtos.RegistrationRequest request = new IamDtos.RegistrationRequest( + ParticipantType.PRIVATE, "Test", "Benutzer", null, "test@example.com", "password123" + ); + + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.empty()); + when(userMapper.mapToEntity(any(), any())).thenReturn(testUser); + when(userRepository.save(any())).thenReturn(testUser); + + authService.register(request); + + verify(userRepository).save(any()); + verify(mailService).sendVerificationEmail(eq("test@example.com"), anyString()); + } + + @Test + void register_duplicateEmail_throws() { + IamDtos.RegistrationRequest request = new IamDtos.RegistrationRequest( + ParticipantType.PRIVATE, "Test", "Benutzer", null, "test@example.com", "password123" + ); + + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + + assertThrows(RuntimeException.class, () -> authService.register(request)); + verify(userRepository, never()).save(any()); + } + + @Test + void register_companyWithoutName_throws() { + IamDtos.RegistrationRequest request = new IamDtos.RegistrationRequest( + ParticipantType.COMPANY, "Test", "Benutzer", null, "test@example.com", "password123" + ); + + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.empty()); + + assertThrows(IllegalArgumentException.class, () -> authService.register(request)); + verify(userRepository, never()).save(any()); + } + + @Test + void login_success() { + IamDtos.LoginRequest request = new IamDtos.LoginRequest("test@example.com", "password123"); + + Authentication auth = mock(Authentication.class); + when(auth.getName()).thenReturn("test@example.com"); + doReturn(List.of(new SimpleGrantedAuthority("ROLE_MEMBER"))).when(auth).getAuthorities(); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))).thenReturn(auth); + when(userRepository.findByEmail("test@example.com")).thenReturn(Optional.of(testUser)); + when(jwtEncoder.encode(any(JwtEncoderParameters.class))).thenReturn( + org.springframework.security.oauth2.jwt.Jwt.withTokenValue("fake-token") + .header("alg", "HS256") + .claim("sub", "test@example.com") + .claim("role", "MEMBER") + .build() + ); + + IamDtos.AuthResponse response = authService.login(request); + + assertNotNull(response); + assertEquals("fake-token", response.token()); + } + + @Test + void login_userNotFound_throws() { + IamDtos.LoginRequest request = new IamDtos.LoginRequest("unknown@example.com", "password123"); + + Authentication auth = mock(Authentication.class); + when(authenticationManager.authenticate(any(UsernamePasswordAuthenticationToken.class))).thenReturn(auth); + when(userRepository.findByEmail("unknown@example.com")).thenReturn(Optional.empty()); + + assertThrows(IllegalStateException.class, () -> authService.login(request)); + } + + @Test + void verifyEmail_success() { + String token = "valid-token"; + testUser.setVerificationToken(token); + when(userRepository.findByVerificationToken(token)).thenReturn(Optional.of(testUser)); + + authService.verifyEmail(token); + + assertTrue(testUser.isEmailVerified()); + assertNull(testUser.getVerificationToken()); + verify(userRepository).save(testUser); + } + + @Test + void verifyEmail_invalidToken_throws() { + when(userRepository.findByVerificationToken("invalid-token")).thenReturn(Optional.empty()); + + assertThrows(IllegalArgumentException.class, () -> authService.verifyEmail("invalid-token")); + } +}