package com.battery.business.runtime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.time.Instant; import java.time.LocalDateTime; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; import tools.jackson.databind.json.JsonMapper; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.BaseEntity; import com.battery.business.domain.TTest; import com.battery.business.domain.TTestDataRevisionAction; import com.battery.business.service.ITestLiveService.LiveState; import com.battery.business.mapper.TTestMapper; import com.battery.business.service.impl.TTestServiceImpl; import com.battery.business.service.impl.TestDataQueryServiceImpl; import com.battery.business.web.TTestController; import org.springframework.test.util.ReflectionTestUtils; /** 控制台 REST/SSE 的业务时间统一为毫秒,平台响应保持原有格式。 */ class ConsoleTimeContractTest { private final JsonMapper json = JsonMapper.builder().findAndAddModules().build(); private final long time = 1788588000123L; @Test void testDetailAndRevisionExposeEpochMillis() { TTest test = new TTest(); test.setCreateTime(new Date(time)); test.setUpdateTime(new Date(time)); test.setStartedAtUtc(new Date(time)); test.setEndedAtUtc(new Date(time)); var detail = json.readTree(json.writeValueAsString(AjaxResult.success(test))).get("data"); for (String field : List.of("createTime", "updateTime", "startedAtUtc", "endedAtUtc")) { assertTrue(detail.get(field).isIntegralNumber(), field); assertEquals(time, detail.get(field).longValue()); } TTestDataRevisionAction action = new TTestDataRevisionAction(); action.setCreatedAtUtc(new Date(time)); assertEquals(time, json.readTree(json.writeValueAsString(action)).get("createdAtUtc").longValue()); BaseEntity platform = new BaseEntity(); platform.setCreateTime(new Date(time)); assertTrue(json.readTree(json.writeValueAsString(platform)).get("createTime").isString()); } @Test void snapshotAndHeartbeatExposeTheSameMillis() { LiveState state = new LiveState(42L, "RUNNING", "RECEIVING", time, List.of(), List.of(), null); assertEquals(time, json.readTree(json.writeValueAsString(state)).get("updatedAt").longValue()); assertEquals(time, json.readTree(json.writeValueAsString(Map.of("at", state.updatedAt()))).get("at").longValue()); } @Test void persistedDataEndpointsInterpretDatabaseLocalDateTimeAsUtcMillis() { var mapper = mock(TTestMapper.class); var storedTest = new TTest(); storedTest.setTestId(42L); when(mapper.selectTestById(42L)).thenReturn(storedTest); var tests = new TTestServiceImpl(); ReflectionTestUtils.setField(tests, "testMapper", mapper); var controller = new TTestController(); ReflectionTestUtils.setField(controller, "testDataQueryService", new TestDataQueryServiceImpl(mapper, tests)); // JDBC 可将 UTC DATETIME(3) 返回为 LocalDateTime;它不是用户所在时区的本地时间。 for (Object databaseTime : List.of(LocalDateTime.parse("2023-05-08T03:42:11.123"), Instant.parse("2023-05-08T03:42:11.123Z"), new Date(1683517331123L))) { Map row = new LinkedHashMap<>(); for (String field : List.of("deviceTime", "collectorDeviceTime", "captureSlot", "serverReceivedAt", "recordedAt", "absoluteTime")) row.put(field, databaseTime); row.put("deviceTimeRaw", "2023-05-08 11:42:11.123"); row.put("temperature", null); when(mapper.selectPersistedFinalRealtimeRecords(42L)).thenReturn(List.of(new LinkedHashMap<>(row))); when(mapper.selectPersistedFinalStepRecords(42L)).thenReturn(List.of(new LinkedHashMap<>(row))); when(mapper.selectPersistedFinalCycleRecords(42L)).thenReturn(List.of(new LinkedHashMap<>(row))); for (AjaxResult result : List.of(controller.persistedRecords(42L), controller.persistedSteps(42L), controller.persistedCycles(42L))) { var item = json.readTree(json.writeValueAsString(result)).get("data").get(0); for (String field : List.of("deviceTime", "collectorDeviceTime", "captureSlot", "serverReceivedAt", "recordedAt", "absoluteTime")) { assertTrue(item.get(field).isIntegralNumber(), field + ": " + item.get(field)); assertEquals(1683517331123L, item.get(field).longValue()); } assertEquals("2023-05-08 11:42:11.123", item.get("deviceTimeRaw").asString()); assertTrue(item.get("temperature").isNull()); } } } }