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>
115 lines
4.9 KiB
Kotlin
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
|
|
}
|
|
}
|
|
}
|