Skip to content

Commit

Permalink
Merge pull request #47 from amanjpro/upkeep/add-oldest-missing-period…
Browse files Browse the repository at this point in the history
…-age-to-api

Upkeep/add oldest missing period age to api
  • Loading branch information
amanjpro authored Jul 26, 2020
2 parents c78c6ea + 0461f94 commit 4c8e562
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 107 deletions.
4 changes: 4 additions & 0 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ $ curl --silent -G http://0.0.0.0:8080/summary | jq .
"job_id": 0,
"name": "Job1",
"missing": 4,
"oldest_mising_period": 10,
"alert_level": "warn"
},
{
"job_id": 1,
"name": "Job2",
"missing": 2,
"oldest_mising_period": 3,
"alert_level": "normal"
}
]
Expand All @@ -49,12 +51,14 @@ $ curl --silent -G http://0.0.0.0:8080/summary | jq .
"job_id": 0,
"name": "Job3",
"missing": 6,
"oldest_mising_period": 6,
"alert_level": "critical"
},
{
"job_id": 1,
"name": "Job4",
"missing": 0,
"oldest_mising_period": 0,
"alert_level": "great"
}
]
Expand Down
7 changes: 1 addition & 6 deletions src/main/scala/checker/CommandRunner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,14 @@ class CommandRunner(statsActor: ActorRef) extends Actor with ActorLogging {
period => PeriodHealth(period, mapped(period)) }
context.sender ! RunResult(periodHealths, group, job, clockCounter)
statsActor ! MissingPeriods(prometheusId, periodHealths.count(!_.ok))
val oldestMissingPeriod = CommandRunner.computeOldest(periodHealths)
val oldestMissingPeriod = computeOldest(periodHealths)
statsActor ! OldestMissingPeriod(prometheusId, oldestMissingPeriod)
}
}
}

object CommandRunner {
private[this] val Matcher = "^greenish-period\t(.*)\t(1|0)$".r
protected[checker] def computeOldest(periodHealths: Seq[PeriodHealth]): Int = {
val missingIndex = periodHealths.indexWhere(!_.ok)
if(missingIndex == -1) 0
else periodHealths.length - missingIndex
}

protected[checker] def parseOutput(lines: LazyList[String],
periods: Set[String]): Seq[(String, Boolean)] =
Expand Down
4 changes: 3 additions & 1 deletion src/main/scala/checker/StatusChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ trait StatusCheckerApi {
else if(missing <= status.job.alertLevels.normal) Normal
else if(missing <= status.job.alertLevels.warn) Warn
else Critical
JobStatusSummary(status.job.jobId, status.job.name, missing, alertLevel)

val oldestMissingPeriod = computeOldest(status.periodHealth)
JobStatusSummary(status.job.jobId, status.job.name, missing, oldestMissingPeriod, alertLevel)
}.toSeq
GroupStatusSummary(group.group.groupId, group.group.name, status)
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/scala/checker/checker.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package me.amanj.greenish

import me.amanj.greenish.models.PeriodHealth

package object checker {
protected[checker] def computeOldest(periodHealths: Seq[PeriodHealth]): Int = {
val missingIndex = periodHealths.indexWhere(!_.ok)
if(missingIndex == -1) 0
else periodHealths.length - missingIndex
}
}
1 change: 1 addition & 0 deletions src/main/scala/models/JobStatusSummary.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ case class JobStatusSummary(
jobId: Int,
name: String,
missing: Int,
oldestMissingPeriod: Int,
alertLevel: AlertLevel,
)
object JobStatusSummary {
Expand Down
80 changes: 80 additions & 0 deletions src/test/scala/checker/CheckerSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package me.amanj.greenish.checker

import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach}
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import me.amanj.greenish.models.PeriodHealth

class CheckerSpec() extends AnyWordSpecLike with Matchers {

"computeOldest" must {
"work for empty period health lists" in {
val periods = Seq.empty[PeriodHealth]
val actual = computeOldest(periods)
val expected = 0
actual shouldBe expected
}

"work when the first period is missing" in {
val periods = Seq(
PeriodHealth("kaka", false),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
)
val actual = computeOldest(periods)
val expected = 4
actual shouldBe expected
}

"work when a middle period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
)
val actual = computeOldest(periods)
val expected = 3
actual shouldBe expected
}

"work when the last period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
)
val actual = computeOldest(periods)
val expected = 1
actual shouldBe expected
}

"work when more than a period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
)
val actual = computeOldest(periods)
val expected = 3
actual shouldBe expected
}

"work when no period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
)
val actual = computeOldest(periods)
val expected = 0
actual shouldBe expected
}
}
}


70 changes: 0 additions & 70 deletions src/test/scala/checker/CommandRunnerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,76 +52,6 @@ class CommandRunnerSpec()
Props(new StatsCollector(Set("p1", "p2", "p3"))))
}

"computeOldest" must {
import CommandRunner.computeOldest
"work for empty period health lists" in {
val periods = Seq.empty[PeriodHealth]
val actual = computeOldest(periods)
val expected = 0
actual shouldBe expected
}

"work when the first period is missing" in {
val periods = Seq(
PeriodHealth("kaka", false),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
)
val actual = computeOldest(periods)
val expected = 4
actual shouldBe expected
}

"work when a middle period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
)
val actual = computeOldest(periods)
val expected = 3
actual shouldBe expected
}

"work when the last period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
)
val actual = computeOldest(periods)
val expected = 1
actual shouldBe expected
}

"work when more than a period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
PeriodHealth("kaka", true),
PeriodHealth("kaka", false),
)
val actual = computeOldest(periods)
val expected = 3
actual shouldBe expected
}

"work when no period is missing" in {
val periods = Seq(
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
PeriodHealth("kaka", true),
)
val actual = computeOldest(periods)
val expected = 0
actual shouldBe expected
}
}

"parseOutput" must {
"parse output lines correctly" in {
val lines = LazyList(
Expand Down
54 changes: 29 additions & 25 deletions src/test/scala/checker/StatusCheckerSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -83,28 +83,32 @@ class StatusCheckerSpec()
override protected[this] var state = IndexedSeq.empty[GroupStatus]
}

val singletonState = IndexedSeq(GroupStatus(
group1, Array(JobStatus(job1, tstamp, Seq(PeriodHealth("1", false))))
))

val singletonChecker = new StatusCheckerApi {
override protected[this] var state = IndexedSeq(GroupStatus(
group1, Array(JobStatus(job1, tstamp, Seq(PeriodHealth("1", false))))
))
override protected[this] var state = singletonState
}

val nestedChecker = new StatusCheckerApi {
override protected[this] var state = IndexedSeq(
GroupStatus(
group1, Array(
JobStatus(job1, tstamp, Seq(PeriodHealth("1", true), PeriodHealth("1", true))),
JobStatus(job1, tstamp, Seq(PeriodHealth("2", false), PeriodHealth("3", false))),
)
),
GroupStatus(
group1, Array(
JobStatus(job1, tstamp, Seq(PeriodHealth("1", false), PeriodHealth("1", true))),
JobStatus(job1, tstamp, Seq(PeriodHealth("2", false),
PeriodHealth("3", false), PeriodHealth("4", false))),
)
val deeplyNestedState = IndexedSeq(
GroupStatus(
group1, Array(
JobStatus(job1, tstamp, Seq(PeriodHealth("1", true), PeriodHealth("1", true))),
JobStatus(job1, tstamp, Seq(PeriodHealth("2", false), PeriodHealth("3", false))),
)
),
GroupStatus(
group1, Array(
JobStatus(job1, tstamp, Seq(PeriodHealth("1", false), PeriodHealth("1", true))),
JobStatus(job1, tstamp, Seq(PeriodHealth("2", false),
PeriodHealth("3", false), PeriodHealth("4", false))),
)
)
)

val nestedChecker = new StatusCheckerApi {
override protected[this] var state = deeplyNestedState
}

"maxLag" must {
Expand All @@ -129,11 +133,11 @@ class StatusCheckerSpec()
}

"work when state is not empty" in {
singletonChecker.allEntries.length shouldBe 1
singletonChecker.allEntries shouldBe singletonState
}

"work when state is deeply nested" in {
nestedChecker.allEntries.length shouldBe 2
nestedChecker.allEntries shouldBe deeplyNestedState
}
}

Expand Down Expand Up @@ -179,7 +183,7 @@ class StatusCheckerSpec()

"work when state is not empty" in {
val expected = Seq(
GroupStatusSummary(0, "group1", Seq(JobStatusSummary(0, "job1", 1, Normal)))
GroupStatusSummary(0, "group1", Seq(JobStatusSummary(0, "job1", 1, 1, Normal)))
)
singletonChecker.summary shouldBe expected
}
Expand All @@ -188,14 +192,14 @@ class StatusCheckerSpec()
val expected = Seq(
GroupStatusSummary(
0, "group1", Seq(
JobStatusSummary(0, "job1", 0, Great),
JobStatusSummary(0, "job1", 2, Warn),
JobStatusSummary(0, "job1", 0, 0, Great),
JobStatusSummary(0, "job1", 2, 2, Warn),
)
),
GroupStatusSummary(
0, "group1", Seq(
JobStatusSummary(0, "job1", 1, Normal),
JobStatusSummary(0, "job1", 3, Critical),
JobStatusSummary(0, "job1", 1, 2, Normal),
JobStatusSummary(0, "job1", 3, 3, Critical),
)
)
)
Expand Down Expand Up @@ -298,7 +302,7 @@ class StatusCheckerSpec()
actual shouldBe expected
}

"various cron styles" in {
"work various cron styles" in {
val job = cron => Job(1, null, null, null,
"yyyy-MM-dd-HH-mm", cron, 1, ZoneId.of("UTC"),
2, null, Seq.empty
Expand Down
6 changes: 3 additions & 3 deletions src/test/scala/endpoints/RoutesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,11 @@ class RoutesSpec()
.flatMap(_.as[Seq[GroupStatusSummary]]).getOrElse(null)
val expected = Seq(
GroupStatusSummary(0, group1.name, Seq(
JobStatusSummary(0, job1.name, 1, Normal),
JobStatusSummary(1, job2.name, 1, Normal),
JobStatusSummary(0, job1.name, 1, 2, Normal),
JobStatusSummary(1, job2.name, 1, 2, Normal),
)),
GroupStatusSummary(1, group2.name, Seq(
JobStatusSummary(0, job3.name, 1, Normal),
JobStatusSummary(0, job3.name, 1, 2, Normal),
)),
)
actual shouldBe expected
Expand Down
5 changes: 3 additions & 2 deletions src/test/scala/models/JsonSerdeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class JsonSerdeSpec() extends Matchers
}

"GroupStatusSummary" must {
val jobStatus = Seq(JobStatusSummary(0, "j", 1, Critical))
val jobStatus = Seq(JobStatusSummary(0, "j", 1, 1, Critical))
val groupStatusSummary = GroupStatusSummary(2, "g", jobStatus)
"produce correct JSON" in {

Expand Down Expand Up @@ -248,12 +248,13 @@ class JsonSerdeSpec() extends Matchers
}

"JobStatusSummary" must {
val jobStatusSummary = JobStatusSummary(0, "j", 1, Critical)
val jobStatusSummary = JobStatusSummary(0, "j", 1, 2, Critical)
"produce correct JSON" in {
val expected = Json.obj(
"job_id" -> 0.asJson,
"name" -> "j".asJson,
"missing" -> 1.asJson,
"oldest_missing_period" -> 2.asJson,
"alert_level" -> "critical".asJson,
)

Expand Down

0 comments on commit 4c8e562

Please sign in to comment.