pcp: единообразие времени (UTC) по группе сервисов
Фронт (pcp-tgu-ops-ui): - тест-страж utcTime.guard.test.ts: запрещает Date.parse / new Date(string) / toLocale* без timeZone вне utils/utcTime; тестовые фикстуры переведены на parseUtc. Бэкенд: - UTC-now: LocalDateTime.now() -> LocalDateTime.now(ZoneOffset.UTC) по всем сервисам (entity-дефолты, воркеры, use case'ы) и в тестовых фикстурах. - Конвертации к UTC (баги на не-UTC JVM, каждая с регресс-тестом в не-UTC поясе): - tgu: VisibilityPayloadParser, SyncSpacecraftFromNsiUseCase (Instant -> UTC LocalDateTime); - mission-planing: MissionPlaningService (OffsetDateTime -> UTC через toUtcLocalDateTime); - dynamic-plan: RequestServiceClient (OffsetDateTime -> UTC); - slots: SlotRepositoryImpl (getObject(LocalDateTime) вместо getTimestamp().toLocalDateTime()). - Контрактные сериализационные тесты формата на проводе (naive без зоны / Z): PlanResponse (tgu), RequestResponseDto (request, эталон), TguPlanning DTO (ui). - KDoc-инвариант «=UTC» на UI-facing DTO (tgu PlanResponse, ui-service DTO вкладки ТГУ). Документация: docs/standards/DATETIME_UTC.md (соглашение, таблица сервисов, под-задачи на миграцию к Z), docs/standards/CHECKLIST.md (пункт про UTC на API).
This commit is contained in:
+62
@@ -0,0 +1,62 @@
|
||||
package space.nstart.pcp.slots_service.dto.tgu
|
||||
|
||||
import com.fasterxml.jackson.databind.SerializationFeature
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* Контракт формата времени на проводе для DTO вкладки ТГУ в pcp-ui-service:
|
||||
* naive `LocalDateTime` → ISO без зоны (= UTC), `Instant` → ISO с `Z`
|
||||
* (см. docs/standards/DATETIME_UTC.md). Тест ловит молчаливый дрейф контракта.
|
||||
*
|
||||
* Mapper зеркалит конфиг Spring Boot: JavaTimeModule + disable(WRITE_DATES_AS_TIMESTAMPS).
|
||||
*/
|
||||
class TguPlanningDtoContractTest {
|
||||
|
||||
private val mapper = jacksonObjectMapper().findAndRegisterModules()
|
||||
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
|
||||
@Test
|
||||
fun `serializes plan times as naive ISO without zone`() {
|
||||
val plan = TguPlanResponse(
|
||||
planId = UUID.fromString("00000000-0000-0000-0000-000000000001"),
|
||||
spacecraftId = "25544",
|
||||
startTime = LocalDateTime.of(2026, 5, 29, 1, 0, 0),
|
||||
endTime = LocalDateTime.of(2026, 5, 29, 2, 0, 0),
|
||||
kppId = "KPP-1",
|
||||
status = "PLANNED"
|
||||
)
|
||||
|
||||
val node = mapper.readTree(mapper.writeValueAsString(plan))
|
||||
|
||||
assertEquals("2026-05-29T01:00:00", node.get("startTime").asText())
|
||||
assertTrue(
|
||||
node.get("startTime").asText().matches(Regex("""\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}""")),
|
||||
"ожидался naive ISO без зоны"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `serializes platform validity instants with explicit Z zone`() {
|
||||
val platform = TguPlatformResponse(
|
||||
id = "25544",
|
||||
businessKey = "bk-1",
|
||||
name = "SAT",
|
||||
status = "OPERATIONAL",
|
||||
noradId = 25544L,
|
||||
mission = "obs",
|
||||
validFrom = Instant.parse("2026-05-29T01:00:00Z"),
|
||||
validTo = Instant.parse("2026-12-31T23:00:00Z")
|
||||
)
|
||||
|
||||
val node = mapper.readTree(mapper.writeValueAsString(platform))
|
||||
|
||||
assertEquals("2026-05-29T01:00:00Z", node.get("validFrom").asText())
|
||||
assertTrue(node.get("validTo").asText().endsWith("Z"), "ожидалась явная зона Z")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user