Backend stamps last_fire_error ({at, detail}) on a job when a scheduled fire
can't reach the gateway loopback (gateway down / api_server not bound) —
the "job runs manually but never auto-fires" case. Previously invisible in
mobile.
- CronJob.kt: model as CronJobFireError(at, detail) — the backend sends a
nested object, NOT a flat string (issue's String? proposal would fail to
deserialize), plus the last_fire_error field.
- CronJobsScreen: "Fire failed" ERROR badge in the list + "Dispatch Error"
row (detail + timestamp) in the Run Details dialog.
- Strings en/zh/ko. Test: job with last_fire_error loads + parses.
Backward-compatible: field has a default, existing jobs without it parse fine.
Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
1 parent
1039d7db1d
commit
79c2ea1341
6 files changed
+69
No files matched your search
@@ -5,6 +5,7 @@ import com.m57.hermescontrol.data.model.CronBlueprint
|
||||
import com.m57.hermescontrol.data.model.CronBlueprintField
|
||||
import com.m57.hermescontrol.data.model.CronBlueprintListResponse
|
||||
import com.m57.hermescontrol.data.model.CronJob
|
||||
import com.m57.hermescontrol.data.model.CronJobFireError
|
||||
import com.m57.hermescontrol.data.model.DeliveryTarget
|
||||
import com.m57.hermescontrol.data.model.DeliveryTargetsResponse
|
||||
import com.m57.hermescontrol.data.model.InstantiateBlueprintRequest
|
||||
@@ -30,6 +31,7 @@ import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
@@ -528,4 +530,28 @@ class CronJobsViewModelTest {
|
||||
)
|
||||
assertFalse(vm.uiState.value.editorState.isOpen)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loadCronJobs surfaces last_fire_error on a job`() {
|
||||
val vm = createViewModel()
|
||||
coEvery { mockApi.getCronJobs() } returns
|
||||
Response.success(
|
||||
listOf(
|
||||
CronJob(
|
||||
id = "j11",
|
||||
name = "Flaky job",
|
||||
schedule = JsonPrimitive("every 1h"),
|
||||
last_fire_error = CronJobFireError(at = "2026-08-18T09:00:00", detail = "gateway unreachable"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
vm.loadCronJobs()
|
||||
settle()
|
||||
|
||||
val job = vm.uiState.value.jobs.first()
|
||||
assertNotNull(job.last_fire_error)
|
||||
assertEquals("gateway unreachable", job.last_fire_error?.detail)
|
||||
assertEquals("2026-08-18T09:00:00", job.last_fire_error?.at)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user