package com.common.service; import org.junit.jupiter.api.Test; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.transaction.annotation.Transactional; import java.lang.reflect.Method; import java.time.LocalDateTime; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockingDetails; import static org.mockito.Mockito.when; class AnalysisCheckpointServiceTest { @Test void ruleLeaseUsesFractionalDayInsteadOfIntegerDivision() { JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class); when(jdbcTemplate.update(anyString(), any(Object[].class))).thenReturn(1); AnalysisCheckpointService service = new AnalysisCheckpointService(jdbcTemplate); ReflectionTestUtils.setField(service, "leaseSeconds", 600); service.claimRuleWindow("rule-1", "1:window-v2", LocalDateTime.of(2026, 8, 10, 17, 35), LocalDateTime.of(2026, 8, 10, 17, 42)); assertTrue(mockingDetails(jdbcTemplate).getInvocations().stream() .map(invocation -> String.valueOf(invocation.getRawArguments()[0])) .anyMatch(sql -> sql.contains("lease_until=SYSDATE+(?/86400.0)"))); } @Test void terminalCheckpointUpdatesAreTransactional() throws Exception { assertTransactional("completeRuleWindow", String.class, String.class, LocalDateTime.class, LocalDateTime.class, long.class, long.class); assertTransactional("failRuleWindow", String.class, String.class, LocalDateTime.class, LocalDateTime.class, String.class, String.class); assertTransactional("completeAlgorithmWindow", String.class, String.class, LocalDateTime.class, LocalDateTime.class, long.class, long.class); assertTransactional("failAlgorithmWindow", String.class, String.class, LocalDateTime.class, LocalDateTime.class, String.class, String.class); } private void assertTransactional(String methodName, Class... parameterTypes) throws Exception { Method method = AnalysisCheckpointService.class.getMethod(methodName, parameterTypes); Transactional annotation = method.getAnnotation(Transactional.class); assertNotNull(annotation, methodName + " must commit when Hikari auto-commit is disabled"); assertTrue(annotation.rollbackFor().length == 0); } }