mirror of
https://github.com/henrygd/beszel.git
synced 2026-04-08 14:01:49 +02:00
188 lines
6.7 KiB
Go
188 lines
6.7 KiB
Go
//go:build testing
|
|
|
|
package alerts_test
|
|
|
|
import (
|
|
"testing"
|
|
"testing/synctest"
|
|
"time"
|
|
|
|
beszelTests "github.com/henrygd/beszel/internal/tests"
|
|
|
|
"github.com/henrygd/beszel/internal/alerts"
|
|
"github.com/pocketbase/dbx"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestAlertsHistory(t *testing.T) {
|
|
synctest.Test(t, func(t *testing.T) {
|
|
hub, user := beszelTests.GetHubWithUser(t)
|
|
defer hub.Cleanup()
|
|
|
|
// Create systems and alerts
|
|
systems, err := beszelTests.CreateSystems(hub, 1, user.Id, "up")
|
|
assert.NoError(t, err)
|
|
system := systems[0]
|
|
|
|
alert, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
|
|
"name": "Status",
|
|
"system": system.Id,
|
|
"user": user.Id,
|
|
"min": 1,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
// Initially, no alert history records should exist
|
|
initialHistoryCount, err := hub.CountRecords("alerts_history", nil)
|
|
assert.NoError(t, err)
|
|
assert.Zero(t, initialHistoryCount, "Should have 0 alert history records initially")
|
|
|
|
// Set system to up initially
|
|
system.Set("status", "up")
|
|
err = hub.SaveNoValidate(system)
|
|
assert.NoError(t, err)
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
// Set system to down to trigger alert
|
|
system.Set("status", "down")
|
|
err = hub.SaveNoValidate(system)
|
|
assert.NoError(t, err)
|
|
|
|
// Wait for alert to trigger (after the downtime delay)
|
|
// With 1 minute delay, we need to wait at least 1 minute + some buffer
|
|
time.Sleep(time.Second * 75)
|
|
|
|
// Check that alert is triggered
|
|
triggeredCount, err := hub.CountRecords("alerts", dbx.HashExp{"triggered": true, "id": alert.Id})
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 1, triggeredCount, "Alert should be triggered")
|
|
|
|
// Check that alert history record was created
|
|
historyCount, err := hub.CountRecords("alerts_history", dbx.HashExp{"alert_id": alert.Id})
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 1, historyCount, "Should have 1 alert history record for triggered alert")
|
|
|
|
// Get the alert history record and verify it's not resolved immediately
|
|
historyRecord, err := hub.FindFirstRecordByFilter("alerts_history", "alert_id={:alert_id}", dbx.Params{"alert_id": alert.Id})
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, historyRecord, "Alert history record should exist")
|
|
assert.Equal(t, alert.Id, historyRecord.GetString("alert_id"), "Alert history should reference correct alert")
|
|
assert.Equal(t, system.Id, historyRecord.GetString("system"), "Alert history should reference correct system")
|
|
assert.Equal(t, "Status", historyRecord.GetString("name"), "Alert history should have correct name")
|
|
|
|
// The alert history might be resolved immediately in some cases, so let's check the alert's triggered status
|
|
alertRecord, err := hub.FindFirstRecordByFilter("alerts", "id={:id}", dbx.Params{"id": alert.Id})
|
|
assert.NoError(t, err)
|
|
assert.True(t, alertRecord.GetBool("triggered"), "Alert should still be triggered when checking history")
|
|
|
|
// Now resolve the alert by setting system back to up
|
|
system.Set("status", "up")
|
|
err = hub.SaveNoValidate(system)
|
|
assert.NoError(t, err)
|
|
time.Sleep(200 * time.Millisecond)
|
|
|
|
// Check that alert is no longer triggered
|
|
triggeredCount, err = hub.CountRecords("alerts", dbx.HashExp{"triggered": true, "id": alert.Id})
|
|
assert.NoError(t, err)
|
|
assert.Zero(t, triggeredCount, "Alert should not be triggered after system is back up")
|
|
|
|
// Check that alert history record is now resolved
|
|
historyRecord, err = hub.FindFirstRecordByFilter("alerts_history", "alert_id={:alert_id}", dbx.Params{"alert_id": alert.Id})
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, historyRecord, "Alert history record should still exist")
|
|
assert.NotNil(t, historyRecord.Get("resolved"), "Alert history should be resolved")
|
|
|
|
// Test deleting a triggered alert resolves its history
|
|
// Create another system and alert
|
|
systems2, err := beszelTests.CreateSystems(hub, 1, user.Id, "up")
|
|
assert.NoError(t, err)
|
|
system2 := systems2[0]
|
|
system2.Set("name", "test-system-2") // Rename for clarity
|
|
err = hub.SaveNoValidate(system2)
|
|
assert.NoError(t, err)
|
|
|
|
alert2, err := beszelTests.CreateRecord(hub, "alerts", map[string]any{
|
|
"name": "Status",
|
|
"system": system2.Id,
|
|
"user": user.Id,
|
|
"min": 1,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
// Set system2 to down to trigger alert
|
|
system2.Set("status", "down")
|
|
err = hub.SaveNoValidate(system2)
|
|
assert.NoError(t, err)
|
|
|
|
// Wait for alert to trigger
|
|
time.Sleep(time.Second * 75)
|
|
|
|
// Verify alert is triggered and history record exists
|
|
triggeredCount, err = hub.CountRecords("alerts", dbx.HashExp{"triggered": true, "id": alert2.Id})
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 1, triggeredCount, "Second alert should be triggered")
|
|
|
|
historyCount, err = hub.CountRecords("alerts_history", dbx.HashExp{"alert_id": alert2.Id})
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 1, historyCount, "Should have 1 alert history record for second alert")
|
|
|
|
// Delete the triggered alert
|
|
err = hub.Delete(alert2)
|
|
assert.NoError(t, err)
|
|
|
|
// Check that alert history record is resolved after deletion
|
|
historyRecord2, err := hub.FindFirstRecordByFilter("alerts_history", "alert_id={:alert_id}", dbx.Params{"alert_id": alert2.Id})
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, historyRecord2, "Alert history record should still exist after alert deletion")
|
|
assert.NotNil(t, historyRecord2.Get("resolved"), "Alert history should be resolved after alert deletion")
|
|
|
|
// Verify total history count is correct (2 records total)
|
|
totalHistoryCount, err := hub.CountRecords("alerts_history", nil)
|
|
assert.NoError(t, err)
|
|
assert.EqualValues(t, 2, totalHistoryCount, "Should have 2 total alert history records")
|
|
})
|
|
}
|
|
|
|
func TestSetAlertTriggered(t *testing.T) {
|
|
hub, _ := beszelTests.NewTestHub(t.TempDir())
|
|
defer hub.Cleanup()
|
|
|
|
hub.StartHub()
|
|
|
|
user, _ := beszelTests.CreateUser(hub, "test@example.com", "password")
|
|
system, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{
|
|
"name": "test-system",
|
|
"users": []string{user.Id},
|
|
"host": "127.0.0.1",
|
|
})
|
|
|
|
alertRecord, _ := beszelTests.CreateRecord(hub, "alerts", map[string]any{
|
|
"name": "CPU",
|
|
"system": system.Id,
|
|
"user": user.Id,
|
|
"value": 80,
|
|
"triggered": false,
|
|
})
|
|
|
|
am := alerts.NewAlertManager(hub)
|
|
|
|
var alert alerts.CachedAlertData
|
|
alert.PopulateFromRecord(alertRecord)
|
|
|
|
// Test triggering the alert
|
|
err := am.SetAlertTriggered(alert, true)
|
|
assert.NoError(t, err)
|
|
|
|
updatedRecord, err := hub.FindRecordById("alerts", alert.Id)
|
|
assert.NoError(t, err)
|
|
assert.True(t, updatedRecord.GetBool("triggered"))
|
|
|
|
// Test un-triggering the alert
|
|
err = am.SetAlertTriggered(alert, false)
|
|
assert.NoError(t, err)
|
|
|
|
updatedRecord, err = hub.FindRecordById("alerts", alert.Id)
|
|
assert.NoError(t, err)
|
|
assert.False(t, updatedRecord.GetBool("triggered"))
|
|
}
|