//go:build testing package alerts_test import ( "bytes" "encoding/json" "io" "net/http" "strings" "testing" "github.com/henrygd/beszel/internal/alerts" beszelTests "github.com/henrygd/beszel/internal/tests" pbTests "github.com/pocketbase/pocketbase/tests" "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/core" "github.com/stretchr/testify/assert" ) // marshal to json and return an io.Reader (for use in ApiScenario.Body) func jsonReader(v any) io.Reader { data, err := json.Marshal(v) if err != nil { panic(err) } return bytes.NewReader(data) } func TestIsInternalURL(t *testing.T) { testCases := []struct { name string url string internal bool }{ {name: "loopback ipv4", url: "generic://127.0.0.1", internal: true}, {name: "private ipv4", url: "generic://10.0.0.1", internal: true}, {name: "localhost hostname", url: "generic://localhost", internal: true}, {name: "localhost with path", url: "generic+http://localhost/api/v1/postStuff", internal: true}, {name: "loopback with port and path", url: "generic+http://127.0.0.1:8080/api/v1/postStuff", internal: true}, {name: "public hostname", url: "generic+https://beszel.dev/api/v1/postStuff", internal: false}, {name: "cloud metadata ipv4", url: "generic://169.254.169.254", internal: true}, {name: "link-local ipv4", url: "generic://169.254.1.1", internal: true}, {name: "link-local ipv6", url: "generic://[fe80::1]", internal: true}, {name: "mapped link-local ipv4", url: "generic://[::ffff:169.254.169.254]", internal: true}, {name: "cgnat lower boundary", url: "generic://100.64.0.0", internal: true}, {name: "cgnat upper boundary", url: "generic://100.127.255.255", internal: true}, {name: "below cgnat", url: "generic://100.63.255.255", internal: false}, {name: "above cgnat", url: "generic://100.128.0.0", internal: false}, {name: "multicast ipv4", url: "generic://224.0.0.1", internal: true}, {name: "multicast ipv6", url: "generic://[ff02::1]", internal: true}, {name: "public ipv4", url: "generic://8.8.8.8", internal: false}, {name: "public ipv6", url: "generic://[2001:4860:4860::8888]", internal: false}, {name: "token style service url", url: "discord://abc123@123456789", internal: false}, {name: "single label service url", url: "slack://token@team/channel", internal: false}, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { internal, err := alerts.IsInternalURL(testCase.url) assert.NoError(t, err) assert.Equal(t, testCase.internal, internal) }) } } func TestUserAlertsApi(t *testing.T) { hub, _ := beszelTests.NewTestHub(t.TempDir()) defer hub.Cleanup() hub.StartHub() user1, _ := beszelTests.CreateUser(hub, "alertstest@example.com", "password") user1Token, _ := user1.NewAuthToken() user2, _ := beszelTests.CreateUser(hub, "alertstest2@example.com", "password") user2Token, _ := user2.NewAuthToken() system1, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{ "name": "system1", "users": []string{user1.Id}, "host": "127.0.0.1", }) system2, _ := beszelTests.CreateRecord(hub, "systems", map[string]any{ "name": "system2", "users": []string{user1.Id, user2.Id}, "host": "127.0.0.2", }) userRecords, _ := hub.CountRecords("users") assert.EqualValues(t, 2, userRecords, "all users should be created") systemRecords, _ := hub.CountRecords("systems") assert.EqualValues(t, 2, systemRecords, "all systems should be created") testAppFactory := func(t testing.TB) *pbTests.TestApp { return hub.TestApp } scenarios := []beszelTests.ApiScenario{ // { // Name: "GET not implemented - returns index", // Method: http.MethodGet, // URL: "/api/beszel/user-alerts", // ExpectedStatus: 200, // ExpectedContent: []string{"