Skip to content

Commit fb6970a

Browse files
Add StatusAt method for Alert struct
This commit adds the StatusAt method for the Alert struct. It calls the ResolvedAt method while Status calls the Resolved method. This method will be used in Alertmanager to fix issue prometheus/alertmanager#3351. Signed-off-by: George Robinson <[email protected]>
1 parent 0234594 commit fb6970a

File tree

2 files changed

+115
-7
lines changed

2 files changed

+115
-7
lines changed

model/alert.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,12 @@ func (a *Alert) ResolvedAt(ts time.Time) bool {
7575

7676
// Status returns the status of the alert.
7777
func (a *Alert) Status() AlertStatus {
78-
if a.Resolved() {
78+
return a.StatusAt(time.Now())
79+
}
80+
81+
// StatusAt returns the status of the alert before the given timestamp.
82+
func (a *Alert) StatusAt(ts time.Time) AlertStatus {
83+
if a.ResolvedAt(ts) {
7984
return AlertResolved
8085
}
8186
return AlertFiring
@@ -127,10 +132,30 @@ func (as Alerts) HasFiring() bool {
127132
return false
128133
}
129134

135+
// HasFiringAt returns true iff one of the alerts is not resolved
136+
// at the time ts.
137+
func (as Alerts) HasFiringAt(ts time.Time) bool {
138+
for _, a := range as {
139+
if !a.ResolvedAt(ts) {
140+
return true
141+
}
142+
}
143+
return false
144+
}
145+
130146
// Status returns StatusFiring iff at least one of the alerts is firing.
131147
func (as Alerts) Status() AlertStatus {
132148
if as.HasFiring() {
133149
return AlertFiring
134150
}
135151
return AlertResolved
136152
}
153+
154+
// StatusAt returns StatusFiring iff at least one of the alerts is firing
155+
// at the time ts.
156+
func (as Alerts) StatusAt(ts time.Time) AlertStatus {
157+
if as.HasFiringAt(ts) {
158+
return AlertFiring
159+
}
160+
return AlertResolved
161+
}

model/alert_test.go

+89-6
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ func TestAlert(t *testing.T) {
133133
t.Errorf("expected %s, but got %s", expected, actual)
134134
}
135135

136-
actualStatus := string(alert.Status())
137-
expectedStatus := "firing"
136+
actualStatus := alert.Status()
137+
expectedStatus := AlertStatus("firing")
138138

139139
if actualStatus != expectedStatus {
140140
t.Errorf("expected alertStatus %s, but got %s", expectedStatus, actualStatus)
@@ -150,19 +150,55 @@ func TestAlert(t *testing.T) {
150150
EndsAt: ts2,
151151
}
152152

153+
if !alert.Resolved() {
154+
t.Error("expected alert to be resolved, but it was not")
155+
}
156+
153157
actual = fmt.Sprint(alert)
154158
expected = "[d181d0f][resolved]"
155159

156160
if actual != expected {
157161
t.Errorf("expected %s, but got %s", expected, actual)
158162
}
159163

160-
actualStatus = string(alert.Status())
164+
actualStatus = alert.Status()
161165
expectedStatus = "resolved"
162166

163167
if actualStatus != expectedStatus {
164168
t.Errorf("expected alertStatus %s, but got %s", expectedStatus, actualStatus)
165169
}
170+
171+
// Verifying that ResolvedAt works for different times
172+
if alert.ResolvedAt(ts1) {
173+
t.Error("unexpected alert was resolved at start time")
174+
}
175+
if alert.ResolvedAt(ts2.Add(-time.Millisecond)) {
176+
t.Error("unexpected alert was resolved before it ended")
177+
}
178+
if !alert.ResolvedAt(ts2) {
179+
t.Error("expected alert to be resolved at end time")
180+
}
181+
if !alert.ResolvedAt(ts2.Add(time.Millisecond)) {
182+
t.Error("expected alert to be resolved after it ended")
183+
}
184+
185+
// Verifying that StatusAt works for different times
186+
actualStatus = alert.StatusAt(ts1)
187+
if actualStatus != "firing" {
188+
t.Errorf("expected alert to be firing at start time, but got %s", actualStatus)
189+
}
190+
actualStatus = alert.StatusAt(ts1.Add(-time.Millisecond))
191+
if actualStatus != "firing" {
192+
t.Errorf("expected alert to be firing before it ended, but got %s", actualStatus)
193+
}
194+
actualStatus = alert.StatusAt(ts2)
195+
if actualStatus != "resolved" {
196+
t.Errorf("expected alert to be resolved at end time, but got %s", actualStatus)
197+
}
198+
actualStatus = alert.StatusAt(ts2.Add(time.Millisecond))
199+
if actualStatus != "resolved" {
200+
t.Errorf("expected alert to be resolved after it ended, but got %s", actualStatus)
201+
}
166202
}
167203

168204
func TestSortAlerts(t *testing.T) {
@@ -228,18 +264,19 @@ func TestSortAlerts(t *testing.T) {
228264
}
229265

230266
func TestAlertsStatus(t *testing.T) {
267+
ts := time.Now()
231268
firingAlerts := Alerts{
232269
{
233270
Labels: LabelSet{
234271
"foo": "bar",
235272
},
236-
StartsAt: time.Now(),
273+
StartsAt: ts,
237274
},
238275
{
239276
Labels: LabelSet{
240277
"bar": "baz",
241278
},
242-
StartsAt: time.Now(),
279+
StartsAt: ts,
243280
},
244281
}
245282

@@ -250,7 +287,12 @@ func TestAlertsStatus(t *testing.T) {
250287
t.Errorf("expected status %s, but got %s", expectedStatus, actualStatus)
251288
}
252289

253-
ts := time.Now()
290+
actualStatus = firingAlerts.StatusAt(ts)
291+
if actualStatus != expectedStatus {
292+
t.Errorf("expected status %s, but got %s", expectedStatus, actualStatus)
293+
}
294+
295+
ts = time.Now()
254296
resolvedAlerts := Alerts{
255297
{
256298
Labels: LabelSet{
@@ -270,7 +312,48 @@ func TestAlertsStatus(t *testing.T) {
270312

271313
actualStatus = resolvedAlerts.Status()
272314
expectedStatus = AlertResolved
315+
if actualStatus != expectedStatus {
316+
t.Errorf("expected status %s, but got %s", expectedStatus, actualStatus)
317+
}
318+
319+
actualStatus = resolvedAlerts.StatusAt(ts)
320+
expectedStatus = AlertResolved
321+
if actualStatus != expectedStatus {
322+
t.Errorf("expected status %s, but got %s", expectedStatus, actualStatus)
323+
}
273324

325+
ts = time.Now()
326+
mixedAlerts := Alerts{
327+
{
328+
Labels: LabelSet{
329+
"foo": "bar",
330+
},
331+
StartsAt: ts.Add(-1 * time.Minute),
332+
EndsAt: ts.Add(5 * time.Minute),
333+
},
334+
{
335+
Labels: LabelSet{
336+
"bar": "baz",
337+
},
338+
StartsAt: ts.Add(-1 * time.Minute),
339+
EndsAt: ts,
340+
},
341+
}
342+
343+
actualStatus = mixedAlerts.Status()
344+
expectedStatus = AlertFiring
345+
if actualStatus != expectedStatus {
346+
t.Errorf("expected status %s, but got %s", expectedStatus, actualStatus)
347+
}
348+
349+
actualStatus = mixedAlerts.StatusAt(ts)
350+
expectedStatus = AlertFiring
351+
if actualStatus != expectedStatus {
352+
t.Errorf("expected status %s, but got %s", expectedStatus, actualStatus)
353+
}
354+
355+
actualStatus = mixedAlerts.StatusAt(ts.Add(5 * time.Minute))
356+
expectedStatus = AlertResolved
274357
if actualStatus != expectedStatus {
275358
t.Errorf("expected status %s, but got %s", expectedStatus, actualStatus)
276359
}

0 commit comments

Comments
 (0)