test: add AiConfigServiceTest unit test
This commit is contained in:
parent
2c5626c0f9
commit
688a3aac7c
@ -0,0 +1,212 @@
|
|||||||
|
package com.walkguide.service;
|
||||||
|
|
||||||
|
import com.walkguide.dto.request.AiConfigUpdateRequest;
|
||||||
|
import com.walkguide.dto.response.AiConfigResponse;
|
||||||
|
import com.walkguide.entity.AiConfig;
|
||||||
|
import com.walkguide.entity.PairingRelation;
|
||||||
|
import com.walkguide.entity.User;
|
||||||
|
import com.walkguide.enums.PairingStatus;
|
||||||
|
import com.walkguide.exception.PairingException;
|
||||||
|
import com.walkguide.repository.AiConfigRepository;
|
||||||
|
import com.walkguide.repository.PairingRelationRepository;
|
||||||
|
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.ArgumentCaptor;
|
||||||
|
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("AiConfigService Unit Tests")
|
||||||
|
class AiConfigServiceTest {
|
||||||
|
|
||||||
|
@Mock AiConfigRepository aiConfigRepository;
|
||||||
|
@Mock PairingRelationRepository pairingRelationRepository;
|
||||||
|
@Mock FcmService fcmService;
|
||||||
|
|
||||||
|
@InjectMocks AiConfigService aiConfigService;
|
||||||
|
|
||||||
|
private User guardian;
|
||||||
|
private User user;
|
||||||
|
private PairingRelation activePairing;
|
||||||
|
private AiConfig existingConfig;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
guardian = User.builder()
|
||||||
|
.id(1L).email("guardian@test.com").role("ROLE_GUARDIAN")
|
||||||
|
.displayName("Guardian").fcmToken("guardian-fcm").build();
|
||||||
|
|
||||||
|
user = User.builder()
|
||||||
|
.id(2L).email("user@test.com").role("ROLE_USER")
|
||||||
|
.displayName("User").fcmToken("user-fcm").build();
|
||||||
|
|
||||||
|
activePairing = PairingRelation.builder()
|
||||||
|
.id(5L).guardian(guardian).user(user).status(PairingStatus.ACTIVE).build();
|
||||||
|
|
||||||
|
existingConfig = AiConfig.builder()
|
||||||
|
.id(10L).userId(2L).guardianId(1L)
|
||||||
|
.confidenceThreshold(0.5)
|
||||||
|
.alertDistanceClose(1.5)
|
||||||
|
.alertDistanceMedium(3.0)
|
||||||
|
.maxInferenceFps(5)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== GET CONFIG TESTS =====
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getConfig - konfigurasi ada harus return data dari DB")
|
||||||
|
void getConfig_configExists_shouldReturnExistingConfig() {
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.of(existingConfig));
|
||||||
|
|
||||||
|
AiConfigResponse result = aiConfigService.getConfig(2L);
|
||||||
|
|
||||||
|
assertThat(result.getId()).isEqualTo(10L);
|
||||||
|
assertThat(result.getConfidenceThreshold()).isEqualTo(0.5);
|
||||||
|
assertThat(result.getAlertDistanceClose()).isEqualTo(1.5);
|
||||||
|
verify(aiConfigRepository, never()).save(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getConfig - konfigurasi belum ada harus buat default dan simpan")
|
||||||
|
void getConfig_configNotExists_shouldCreateDefaultAndSave() {
|
||||||
|
AiConfig newConfig = AiConfig.builder().id(99L).userId(2L).build();
|
||||||
|
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.empty());
|
||||||
|
when(aiConfigRepository.save(any(AiConfig.class))).thenReturn(newConfig);
|
||||||
|
|
||||||
|
AiConfigResponse result = aiConfigService.getConfig(2L);
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
verify(aiConfigRepository).save(any(AiConfig.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== UPDATE CONFIG BY GUARDIAN TESTS =====
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("updateConfigByGuardian - update confidenceThreshold berhasil")
|
||||||
|
void updateConfigByGuardian_updateThreshold_shouldSaveAndNotify() {
|
||||||
|
AiConfigUpdateRequest req = new AiConfigUpdateRequest();
|
||||||
|
req.setConfidenceThreshold(0.75);
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
|
||||||
|
.thenReturn(Optional.of(activePairing));
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.of(existingConfig));
|
||||||
|
when(aiConfigRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
|
||||||
|
AiConfigResponse result = aiConfigService.updateConfigByGuardian(1L, req);
|
||||||
|
|
||||||
|
assertThat(result.getConfidenceThreshold()).isEqualTo(0.75);
|
||||||
|
verify(aiConfigRepository).save(any(AiConfig.class));
|
||||||
|
verify(fcmService).sendToToken(eq("user-fcm"), anyString(), anyString(), anyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("updateConfigByGuardian - update semua field sekaligus")
|
||||||
|
void updateConfigByGuardian_updateAllFields_shouldUpdateAll() {
|
||||||
|
AiConfigUpdateRequest req = new AiConfigUpdateRequest();
|
||||||
|
req.setConfidenceThreshold(0.8);
|
||||||
|
req.setAlertDistanceClose(1.0);
|
||||||
|
req.setAlertDistanceMedium(2.5);
|
||||||
|
req.setMaxInferenceFps(10);
|
||||||
|
req.setEnabledLabels("person,car,motorcycle");
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
|
||||||
|
.thenReturn(Optional.of(activePairing));
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.of(existingConfig));
|
||||||
|
when(aiConfigRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
|
||||||
|
AiConfigResponse result = aiConfigService.updateConfigByGuardian(1L, req);
|
||||||
|
|
||||||
|
assertThat(result.getConfidenceThreshold()).isEqualTo(0.8);
|
||||||
|
assertThat(result.getAlertDistanceClose()).isEqualTo(1.0);
|
||||||
|
assertThat(result.getAlertDistanceMedium()).isEqualTo(2.5);
|
||||||
|
assertThat(result.getMaxInferenceFps()).isEqualTo(10);
|
||||||
|
assertThat(result.getEnabledLabels()).isEqualTo("person,car,motorcycle");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("updateConfigByGuardian - field null tidak boleh mengubah nilai existing")
|
||||||
|
void updateConfigByGuardian_nullFields_shouldNotOverrideExisting() {
|
||||||
|
// Request dengan semua field null — tidak ada yang berubah
|
||||||
|
AiConfigUpdateRequest req = new AiConfigUpdateRequest();
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
|
||||||
|
.thenReturn(Optional.of(activePairing));
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.of(existingConfig));
|
||||||
|
when(aiConfigRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
|
||||||
|
AiConfigResponse result = aiConfigService.updateConfigByGuardian(1L, req);
|
||||||
|
|
||||||
|
// Nilai lama tetap
|
||||||
|
assertThat(result.getConfidenceThreshold()).isEqualTo(0.5);
|
||||||
|
assertThat(result.getAlertDistanceClose()).isEqualTo(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("updateConfigByGuardian - Guardian tanpa pairing aktif harus throw PairingException")
|
||||||
|
void updateConfigByGuardian_noPairing_shouldThrow() {
|
||||||
|
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
|
||||||
|
.thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> aiConfigService.updateConfigByGuardian(1L, new AiConfigUpdateRequest()))
|
||||||
|
.isInstanceOf(PairingException.class)
|
||||||
|
.hasMessageContaining("Tidak ada user yang dipair");
|
||||||
|
|
||||||
|
verify(aiConfigRepository, never()).save(any());
|
||||||
|
verify(fcmService, never()).sendToToken(any(), any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("updateConfigByGuardian - konfigurasi belum ada harus buat baru lalu update")
|
||||||
|
void updateConfigByGuardian_configNotExists_shouldCreateAndUpdate() {
|
||||||
|
AiConfigUpdateRequest req = new AiConfigUpdateRequest();
|
||||||
|
req.setConfidenceThreshold(0.6);
|
||||||
|
|
||||||
|
AiConfig freshConfig = AiConfig.builder().userId(2L).guardianId(1L)
|
||||||
|
.confidenceThreshold(0.5).build();
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
|
||||||
|
.thenReturn(Optional.of(activePairing));
|
||||||
|
// Pertama kali findByUserId kosong → save default → kembalikan freshConfig
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.empty());
|
||||||
|
when(aiConfigRepository.save(any())).thenAnswer(inv -> {
|
||||||
|
AiConfig c = inv.getArgument(0);
|
||||||
|
c.setId(50L);
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
|
||||||
|
AiConfigResponse result = aiConfigService.updateConfigByGuardian(1L, req);
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
// save dipanggil 2x: sekali buat default, sekali update
|
||||||
|
verify(aiConfigRepository, times(2)).save(any(AiConfig.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("updateConfigByGuardian - harus kirim FCM ke user setelah update")
|
||||||
|
void updateConfigByGuardian_shouldSendFcmToUser() {
|
||||||
|
AiConfigUpdateRequest req = new AiConfigUpdateRequest();
|
||||||
|
req.setMaxInferenceFps(8);
|
||||||
|
|
||||||
|
when(pairingRelationRepository.findByGuardian_IdAndStatus(1L, PairingStatus.ACTIVE))
|
||||||
|
.thenReturn(Optional.of(activePairing));
|
||||||
|
when(aiConfigRepository.findByUserId(2L)).thenReturn(Optional.of(existingConfig));
|
||||||
|
when(aiConfigRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||||
|
|
||||||
|
aiConfigService.updateConfigByGuardian(1L, req);
|
||||||
|
|
||||||
|
ArgumentCaptor<String> tokenCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(fcmService).sendToToken(tokenCaptor.capture(), anyString(), anyString(), anyMap());
|
||||||
|
assertThat(tokenCaptor.getValue()).isEqualTo("user-fcm");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user