Files
werkator/src/test/kotlin/de/hoennig/gittally/server/UiViewsTest.kt
T
mhoennigandClaude Fable 5 f2d4dbfda0 Highlight critical utilization on the system page (v0.9.6)
The Current cell of CPU/RAM/disk used turns orange from 80% of the
total and red from 90%. UiFormats.utilizationClass and the mirrored
utilizationClass in gittally.js apply the same thresholds; unavailable
metrics (n/a) are never highlighted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 19:08:23 +02:00

115 lines
4.9 KiB
Kotlin

package de.hoennig.gittally.server
import de.hoennig.gittally.config.GiteaConfig
import de.hoennig.gittally.metrics.MetricAggregate
import de.hoennig.gittally.metrics.SystemMetrics
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import java.time.Duration
import java.time.Instant
class UiViewsTest : FunSpec() {
init {
test("durations format as m:ss and h:mm:ss like the legacy duration column") {
UiFormats.duration(null) shouldBe ""
UiFormats.duration(Duration.ofSeconds(0)) shouldBe "0:00"
UiFormats.duration(Duration.ofSeconds(83)) shouldBe "1:23"
UiFormats.duration(Duration.ofSeconds(3600 + 62)) shouldBe "1:01:02"
}
test("metric values format with two decimals and a dot, n/a when unavailable") {
UiFormats.metric(null) shouldBe "n/a"
UiFormats.metric(Double.NaN) shouldBe "n/a"
UiFormats.metric(0.0) shouldBe "0.00"
UiFormats.metric(1.234) shouldBe "1.23"
UiFormats.metric(31.288) shouldBe "31.29"
}
test("utilization highlights warn from 80% and crit from 90% of the total") {
UiFormats.utilizationClass(7.9, 10.0) shouldBe ""
UiFormats.utilizationClass(8.0, 10.0) shouldBe "metric-warn"
UiFormats.utilizationClass(8.9, 10.0) shouldBe "metric-warn"
UiFormats.utilizationClass(9.0, 10.0) shouldBe "metric-crit"
UiFormats.utilizationClass(11.0, 10.0) shouldBe "metric-crit"
}
test("utilization highlighting is off when a value or the total is unavailable") {
UiFormats.utilizationClass(null, 10.0) shouldBe ""
UiFormats.utilizationClass(9.5, null) shouldBe ""
UiFormats.utilizationClass(Double.NaN, 10.0) shouldBe ""
UiFormats.utilizationClass(9.5, 0.0) shouldBe ""
}
test("only the used rows with a total get the critical highlighting") {
val aggregate = { value: Double -> MetricAggregate(current = value, min = 0.0, max = value, avg = value) }
val view =
SystemMetricsView.from(
SystemMetrics(
timestamp = Instant.parse("2026-08-10T12:00:00Z"),
sampleCount = 1,
cpuCount = 4,
ramTotalGib = 8.0,
diskTotalGib = 100.0,
cpuUsed = aggregate(3.7),
cpuIdle = aggregate(0.3),
ramUsedGib = aggregate(6.5),
ramFreeGib = aggregate(1.5),
diskUsedGib = aggregate(70.0),
diskFreeGib = aggregate(30.0),
repoSizeGib = aggregate(95.0),
),
)
val classesByKey = view.rows.associate { it.key to it.currentClass }
classesByKey["cpuUsed"] shouldBe "metric-crit"
classesByKey["ramUsedGib"] shouldBe "metric-warn"
classesByKey["diskUsedGib"] shouldBe ""
// free/idle and the repo size have no meaningful utilization ratio
classesByKey["cpuIdle"] shouldBe ""
classesByKey["ramFreeGib"] shouldBe ""
classesByKey["diskFreeGib"] shouldBe ""
classesByKey["repoSizeGib"] shouldBe ""
}
test("Gitea web links escape branch segments but keep slashes") {
val links =
GiteaWebLinks(GiteaConfig(baseUrl = "https://git.example.org/", owner = "acme", repo = "widget"))
links.repoUrl shouldBe "https://git.example.org/acme/widget"
links.branchUrl("feature/some topic") shouldBe
"https://git.example.org/acme/widget/src/branch/feature/some%20topic"
links.commitUrl("0123abc") shouldBe "https://git.example.org/acme/widget/commit/0123abc"
}
test("Gitea web links are null when Gitea is not configured") {
val links = GiteaWebLinks(GiteaConfig())
links.repoUrl shouldBe null
links.branchUrl("main") shouldBe null
links.commitUrl("0123abc") shouldBe null
}
test("rows are in progress while running or pending, so the artifact link shows the log-only icon") {
val links = GiteaWebLinks(GiteaConfig())
fun row(status: String) =
BuildRowView.from(
BranchDto(
branch = "main",
commit = "0123abc",
status = status,
startedAt = null,
durationSeconds = null,
artifactKey = "some-key",
),
links,
)
row("running").inProgress shouldBe true
row("pending").inProgress shouldBe true
row("success").inProgress shouldBe false
row("failed").inProgress shouldBe false
}
}
}