fix(config): fail fast on invalid operation-day zone

运营日时区只认 PARAM:msgx.operation-day.zone:JobRunner、HistorySweepJob、JdbcSnapshotLogRepository.purgeBefore 改走注入的 OperationDayProps;ScheduleProcessor/AdftProcessor 删除「非法值回退字面量」;新增 @Context 启动自检 OperationDayZoneCheck,配置错位在启动时暴露。

验证:./gradlew test 126 tests / 0 fail(新增 OperationDayPropsTest 覆盖合法解析与非法即失败)。
This commit is contained in:
windyboy
2026-09-12 20:34:56 +08:00
parent 3f2a1be75b
commit 9554b1aae8
8 changed files with 68 additions and 10 deletions
@@ -0,0 +1,31 @@
package com.gzzn.omms.msgexchange.config
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import java.time.ZoneId
/**
* 运营日时区只有一个出处(`PARAM:msgx.operation-day.zone`):能解析就解析,
* 解析不了必须让启动失败,**不允许回退到代码字面量**——回退会把配置错位藏起来,
* 让运营日按错误的时区计算。
*/
class OperationDayPropsTest {
@Test
fun `configured zone resolves to the IANA zone`() {
val props = OperationDayProps().apply { zone = "Asia/Shanghai" }
assertEquals(ZoneId.of("Asia/Shanghai"), props.zoneId())
}
@Test
fun `invalid zone fails fast instead of falling back to a literal`() {
val props = OperationDayProps().apply { zone = "Not/AZone" }
val failure = assertThrows(IllegalStateException::class.java) { props.zoneId() }
assertTrue(failure.message!!.contains("msgx.operation-day.zone"))
}
}
@@ -1,6 +1,7 @@
package com.gzzn.omms.msgexchange.jobs
import com.gzzn.omms.msgexchange.config.HistoryProps
import com.gzzn.omms.msgexchange.config.OperationDayProps
import com.gzzn.omms.msgexchange.domain.EventType
import com.gzzn.omms.msgexchange.domain.flight.FlightState
import com.gzzn.omms.msgexchange.domain.flight.HistoryCandidate
@@ -50,7 +51,7 @@ class HistorySweepJobTest {
fun `history store not connected must delete zero rows`() {
val f = seededFlight("F1", deleted = true, idleDays = 30)
val events = StubMsgEvents()
val job = HistorySweepJob(f, events, HistoryProps().apply { historyStoreEnabled = false })
val job = HistorySweepJob(f, events, HistoryProps().apply { historyStoreEnabled = false }, OperationDayProps())
val outcome = job.run(now)
@@ -71,7 +72,7 @@ class HistorySweepJobTest {
val events = StubMsgEvents()
val store = RecordingHistoryStore().apply { confirmed.add("F1") } // 只有 F1 归档确认成功
val job = HistorySweepJob(
f, events, HistoryProps().apply { historyStoreEnabled = true }, historyStore = store,
f, events, HistoryProps().apply { historyStoreEnabled = true }, OperationDayProps(), historyStore = store,
)
val outcome = job.run(now)
@@ -90,7 +91,7 @@ class HistorySweepJobTest {
val events = StubMsgEvents()
val store = RecordingHistoryStore()
val job = HistorySweepJob(
f, events, HistoryProps().apply { historyStoreEnabled = true }, historyStore = store,
f, events, HistoryProps().apply { historyStoreEnabled = true }, OperationDayProps(), historyStore = store,
)
job.run(now)
@@ -108,7 +109,7 @@ class HistorySweepJobTest {
var cutoff: Instant? = null
val purge = com.gzzn.omms.msgexchange.infra.persistence.SnapshotLogPurge { instant -> cutoff = instant; 7 }
val job = HistorySweepJob(
f, StubMsgEvents(), HistoryProps().apply { historyStoreEnabled = false }, snapLogPurge = purge,
f, StubMsgEvents(), HistoryProps().apply { historyStoreEnabled = false }, OperationDayProps(), snapLogPurge = purge,
)
val outcome = job.run(now)