test: add PairingServiceTest unit test
This commit is contained in:
parent
bfcfd4e0f5
commit
70487e6d0d
@ -0,0 +1,217 @@
|
|||||||
|
package com.walkguide.service;
|
||||||
|
|
||||||
|
import com.walkguide.dto.response.PairingStatusResponse;
|
||||||
|
import com.walkguide.entity.PairingRelation;
|
||||||
|
import com.walkguide.entity.User;
|
||||||
|
import com.walkguide.enums.PairingStatus;
|
||||||
|
import com.walkguide.exception.PairingException;
|
||||||
|
import com.walkguide.exception.ResourceNotFoundException;
|
||||||
|
import com.walkguide.repository.*;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
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 java.util.Optional;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@DisplayName("PairingService Unit Tests")
|
||||||
|
class PairingServiceTest {
|
||||||
|
|
||||||
|
@Mock PairingRelationRepository pairingRelationRepository;
|
||||||
|
@Mock UserRepository userRepository;
|
||||||
|
@Mock VoiceCommandConfigRepository voiceCommandConfigRepository;
|
||||||
|
@Mock HardwareShortcutRepository hardwareShortcutRepository;
|
||||||
|
@Mock AiConfigRepository aiConfigRepository;
|
||||||
|
@Mock ActivityLogService activityLogService;
|
||||||
|
@Mock FcmService fcmService;
|
||||||
|
|
||||||
|
@InjectMocks PairingService pairingService;
|
||||||
|
|
||||||
|
private User guardian;
|
||||||
|
private User user;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
guardian = User.builder()
|
||||||
|
.id(1L)
|
||||||
|
.email("guardian@test.com")
|
||||||
|
.role("ROLE_GUARDIAN")
|
||||||
|
.displayName("Guardian Test")
|
||||||
|
.fcmToken("guardian-fcm-token")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
user = User.builder()
|
||||||
|
.id(2L)
|
||||||
|
.email("user@test.com")
|
||||||
|
.role("ROLE_USER")
|
||||||
|
.displayName("User Test")
|
||||||
|
.uniqueUserId("ABC123DEF456")
|
||||||
|
.fcmToken("user-fcm-token")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== INVITE USER TESTS =====
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("inviteUser - berhasil mengirim invite ke user yang valid")
|
||||||
|
void inviteUser_success_shouldSavePairingAndSendFcm() {
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE)).thenReturn(false);
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.PENDING)).thenReturn(false);
|
||||||
|
when(userRepository.findById(1L)).thenReturn(Optional.of(guardian));
|
||||||
|
when(userRepository.findByUniqueUserId("ABC123DEF456")).thenReturn(Optional.of(user));
|
||||||
|
when(pairingRelationRepository.existsByUser_IdAndStatus(2L, PairingStatus.ACTIVE)).thenReturn(false);
|
||||||
|
when(pairingRelationRepository.save(any(PairingRelation.class))).thenAnswer(inv -> {
|
||||||
|
PairingRelation p = inv.getArgument(0);
|
||||||
|
p.setId(10L);
|
||||||
|
return p;
|
||||||
|
});
|
||||||
|
|
||||||
|
PairingStatusResponse result = pairingService.inviteUser(1L, "ABC123DEF456");
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
verify(pairingRelationRepository).save(any(PairingRelation.class));
|
||||||
|
verify(fcmService).sendToToken(eq("user-fcm-token"), anyString(), anyString(), anyMap());
|
||||||
|
verify(activityLogService).createLog(eq(guardian), any(), anyString(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("inviteUser - Guardian sudah ACTIVE pairing harus throw PairingException")
|
||||||
|
void inviteUser_alreadyActivePairing_shouldThrow() {
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE)).thenReturn(true);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> pairingService.inviteUser(1L, "ABC123DEF456"))
|
||||||
|
.isInstanceOf(PairingException.class)
|
||||||
|
.hasMessageContaining("sudah memiliki user yang dipair");
|
||||||
|
|
||||||
|
verify(pairingRelationRepository, never()).save(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("inviteUser - Guardian sudah PENDING invite harus throw PairingException")
|
||||||
|
void inviteUser_alreadyPendingInvite_shouldThrow() {
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE)).thenReturn(false);
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.PENDING)).thenReturn(true);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> pairingService.inviteUser(1L, "ABC123DEF456"))
|
||||||
|
.isInstanceOf(PairingException.class)
|
||||||
|
.hasMessageContaining("sudah punya invite yang menunggu");
|
||||||
|
|
||||||
|
verify(pairingRelationRepository, never()).save(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("inviteUser - uniqueUserId tidak ditemukan harus throw ResourceNotFoundException")
|
||||||
|
void inviteUser_userNotFound_shouldThrow() {
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE)).thenReturn(false);
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.PENDING)).thenReturn(false);
|
||||||
|
when(userRepository.findById(1L)).thenReturn(Optional.of(guardian));
|
||||||
|
when(userRepository.findByUniqueUserId("INVALID")).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> pairingService.inviteUser(1L, "INVALID"))
|
||||||
|
.isInstanceOf(ResourceNotFoundException.class)
|
||||||
|
.hasMessageContaining("tidak ditemukan");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("inviteUser - target bukan ROLE_USER harus throw PairingException")
|
||||||
|
void inviteUser_targetNotUser_shouldThrow() {
|
||||||
|
User anotherGuardian = User.builder()
|
||||||
|
.id(3L).role("ROLE_GUARDIAN").uniqueUserId("GRD000000001").build();
|
||||||
|
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE)).thenReturn(false);
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.PENDING)).thenReturn(false);
|
||||||
|
when(userRepository.findById(1L)).thenReturn(Optional.of(guardian));
|
||||||
|
when(userRepository.findByUniqueUserId("GRD000000001")).thenReturn(Optional.of(anotherGuardian));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> pairingService.inviteUser(1L, "GRD000000001"))
|
||||||
|
.isInstanceOf(PairingException.class)
|
||||||
|
.hasMessageContaining("bukan milik User");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("inviteUser - User sudah ACTIVE dengan Guardian lain harus throw PairingException")
|
||||||
|
void inviteUser_userAlreadyPaired_shouldThrow() {
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE)).thenReturn(false);
|
||||||
|
when(pairingRelationRepository.existsByGuardian_IdAndStatus(1L, PairingStatus.PENDING)).thenReturn(false);
|
||||||
|
when(userRepository.findById(1L)).thenReturn(Optional.of(guardian));
|
||||||
|
when(userRepository.findByUniqueUserId("ABC123DEF456")).thenReturn(Optional.of(user));
|
||||||
|
when(pairingRelationRepository.existsByUser_IdAndStatus(2L, PairingStatus.ACTIVE)).thenReturn(true);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> pairingService.inviteUser(1L, "ABC123DEF456"))
|
||||||
|
.isInstanceOf(PairingException.class)
|
||||||
|
.hasMessageContaining("sudah dipair dengan Guardian lain");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== RESPOND TO PAIRING TESTS =====
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("respondToPairing - accept: status harus jadi ACTIVE")
|
||||||
|
void respondToPairing_accept_shouldSetStatusActive() {
|
||||||
|
PairingRelation pairing = PairingRelation.builder()
|
||||||
|
.id(10L).guardian(guardian).user(user).status(PairingStatus.PENDING).build();
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findById(10L)).thenReturn(Optional.of(pairing));
|
||||||
|
when(pairingRelationRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
// Stub untuk pembuatan config saat accept
|
||||||
|
when(voiceCommandConfigRepository.existsByUserId(2L)).thenReturn(false);
|
||||||
|
when(hardwareShortcutRepository.existsByUserId(2L)).thenReturn(false);
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.empty());
|
||||||
|
when(aiConfigRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
|
||||||
|
PairingStatusResponse result = pairingService.respondToPairing(2L, 10L, true);
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(pairing.getStatus()).isEqualTo(PairingStatus.ACTIVE);
|
||||||
|
verify(pairingRelationRepository).save(pairing);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("respondToPairing - reject: status harus jadi REJECTED")
|
||||||
|
void respondToPairing_reject_shouldSetStatusRejected() {
|
||||||
|
PairingRelation pairing = PairingRelation.builder()
|
||||||
|
.id(10L).guardian(guardian).user(user).status(PairingStatus.PENDING).build();
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findById(10L)).thenReturn(Optional.of(pairing));
|
||||||
|
when(pairingRelationRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
|
||||||
|
PairingStatusResponse result = pairingService.respondToPairing(2L, 10L, false);
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(pairing.getStatus()).isEqualTo(PairingStatus.REJECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("respondToPairing - user yang salah harus throw PairingException")
|
||||||
|
void respondToPairing_wrongUser_shouldThrow() {
|
||||||
|
PairingRelation pairing = PairingRelation.builder()
|
||||||
|
.id(10L).guardian(guardian).user(user).status(PairingStatus.PENDING).build();
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findById(10L)).thenReturn(Optional.of(pairing));
|
||||||
|
|
||||||
|
// userId=99 bukan pemilik pairing ini (user.id=2)
|
||||||
|
assertThatThrownBy(() -> pairingService.respondToPairing(99L, 10L, true))
|
||||||
|
.isInstanceOf(PairingException.class)
|
||||||
|
.hasMessageContaining("tidak berhak");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("respondToPairing - pairing yang sudah direspons harus throw PairingException")
|
||||||
|
void respondToPairing_alreadyResponded_shouldThrow() {
|
||||||
|
PairingRelation pairing = PairingRelation.builder()
|
||||||
|
.id(10L).guardian(guardian).user(user).status(PairingStatus.ACTIVE).build();
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findById(10L)).thenReturn(Optional.of(pairing));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> pairingService.respondToPairing(2L, 10L, true))
|
||||||
|
.isInstanceOf(PairingException.class)
|
||||||
|
.hasMessageContaining("sudah direspons");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user