Adds tests across previously-uncovered or under-covered modules: - Mix tasks: backfill_checks, copy_mibs, import_mibs (new test files) - Status pages: StatusIncident changeset (new file) - Webhook signature verification on AgentReleaseWebhookController - CloudflareBanWorker: HTTP-stubbed success / 5xx / transport-error paths - FirmwareVersionFetcherWorker: stubbed perform/0 success + non-200 + tx error - Geoip.Import: production --production code path (HTTP-stubbed) - AgentLive.Show: superuser restart_agent + update_agent + non-superuser paths - NetworkMapLive: node_clicked, deep-link node, topology_updated PubSub - PreseemInsightsLive: toggle_select, deselect_all, filter, dismiss-twice - AlertQuery: 1-arity defaults variants - ProfileWatcher: yaml + reload-trigger event passthrough - MobileAuthController: verify_qr_token success + get/revoke session - HealthController: redis-configured branch - RedisHealthCheck: un-tag :integration tests now that Redis is local - FourOhFourTracker: un-skip module (Redis available) - PingExecutor: un-tag local-only tests + KeyError surface + clamp branch - CheckExecutorWorker: dispatch tcp/dns/ssl/ping branches - UserResetPasswordController: drop dead edit/update + their template Also removes dead code: edit/update actions on UserResetPasswordController and the unused edit.html.heex template — both routed via LiveView.
182 lines
6.4 KiB
Elixir
182 lines
6.4 KiB
Elixir
defmodule Towerops.Alerts.AlertQueryTest do
|
|
use Towerops.DataCase, async: true
|
|
use ExUnitProperties
|
|
|
|
import Towerops.DevicesFixtures
|
|
|
|
alias Towerops.Alerts.Alert
|
|
alias Towerops.Alerts.AlertQuery
|
|
alias Towerops.Repo
|
|
|
|
setup do
|
|
device = device_fixture()
|
|
%{device: device, organization_id: device.organization_id}
|
|
end
|
|
|
|
describe "base/0" do
|
|
test "returns the Alert schema as a queryable" do
|
|
assert AlertQuery.base() == Alert
|
|
end
|
|
end
|
|
|
|
describe "for_organization/2" do
|
|
test "filters to a single organization", %{device: device, organization_id: org_id} do
|
|
keep = insert_alert!(device.id, org_id, "device_down")
|
|
other_device = device_fixture()
|
|
_other_org = insert_alert!(other_device.id, other_device.organization_id, "device_down")
|
|
|
|
[result] = AlertQuery.base() |> AlertQuery.for_organization(org_id) |> Repo.all()
|
|
assert result.id == keep.id
|
|
end
|
|
|
|
test "is composable with other filters", %{device: device, organization_id: org_id} do
|
|
a = insert_alert!(device.id, org_id, "device_down")
|
|
_b = insert_alert!(device.id, org_id, "device_up")
|
|
|
|
[result] =
|
|
AlertQuery.base()
|
|
|> AlertQuery.for_organization(org_id)
|
|
|> AlertQuery.of_type("device_down")
|
|
|> Repo.all()
|
|
|
|
assert result.id == a.id
|
|
end
|
|
end
|
|
|
|
describe "for_device/2" do
|
|
test "filters to a single device", %{device: device, organization_id: org_id} do
|
|
other_device = device_fixture()
|
|
keep = insert_alert!(device.id, org_id, "device_down")
|
|
_drop = insert_alert!(other_device.id, other_device.organization_id, "device_down")
|
|
|
|
[result] = AlertQuery.base() |> AlertQuery.for_device(device.id) |> Repo.all()
|
|
assert result.id == keep.id
|
|
end
|
|
end
|
|
|
|
describe "of_type/2" do
|
|
test "filters by alert_type", %{device: device, organization_id: org_id} do
|
|
down = insert_alert!(device.id, org_id, "device_down")
|
|
_up = insert_alert!(device.id, org_id, "device_up")
|
|
|
|
[result] = AlertQuery.base() |> AlertQuery.of_type("device_down") |> Repo.all()
|
|
assert result.id == down.id
|
|
end
|
|
end
|
|
|
|
describe "unresolved/1 and resolved/1" do
|
|
test "partition alerts by resolved_at presence", %{device: device, organization_id: org_id} do
|
|
open = insert_alert!(device.id, org_id, "device_down")
|
|
|
|
closed =
|
|
insert_alert!(device.id, org_id, "device_down", resolved_at: DateTime.truncate(DateTime.utc_now(), :second))
|
|
|
|
assert [%{id: id1}] = AlertQuery.base() |> AlertQuery.unresolved() |> Repo.all()
|
|
assert id1 == open.id
|
|
|
|
assert [%{id: id2}] = AlertQuery.base() |> AlertQuery.resolved() |> Repo.all()
|
|
assert id2 == closed.id
|
|
end
|
|
end
|
|
|
|
describe "with_severity/2" do
|
|
test "filters by severity", %{device: device, organization_id: org_id} do
|
|
crit = insert_alert!(device.id, org_id, "device_down", severity: 1)
|
|
_warn = insert_alert!(device.id, org_id, "device_down", severity: 2)
|
|
|
|
[result] = AlertQuery.base() |> AlertQuery.with_severity(1) |> Repo.all()
|
|
assert result.id == crit.id
|
|
end
|
|
end
|
|
|
|
describe "default-arg one-arity helpers" do
|
|
test "for_organization/1 starts from base()", %{device: device, organization_id: org_id} do
|
|
keep = insert_alert!(device.id, org_id, "device_down")
|
|
[result] = org_id |> AlertQuery.for_organization() |> Repo.all()
|
|
assert result.id == keep.id
|
|
end
|
|
|
|
test "for_device/1 starts from base()", %{device: device, organization_id: org_id} do
|
|
keep = insert_alert!(device.id, org_id, "device_down")
|
|
[result] = device.id |> AlertQuery.for_device() |> Repo.all()
|
|
assert result.id == keep.id
|
|
end
|
|
|
|
test "of_type/1 starts from base()", %{device: device, organization_id: org_id} do
|
|
down = insert_alert!(device.id, org_id, "device_down")
|
|
_up = insert_alert!(device.id, org_id, "device_up")
|
|
[result] = "device_down" |> AlertQuery.of_type() |> Repo.all()
|
|
assert result.id == down.id
|
|
end
|
|
|
|
test "unresolved/0 starts from base()", %{device: device, organization_id: org_id} do
|
|
open = insert_alert!(device.id, org_id, "device_down")
|
|
|
|
_closed =
|
|
insert_alert!(device.id, org_id, "device_down", resolved_at: DateTime.truncate(DateTime.utc_now(), :second))
|
|
|
|
[result] = Repo.all(AlertQuery.unresolved())
|
|
assert result.id == open.id
|
|
end
|
|
|
|
test "resolved/0 starts from base()", %{device: device, organization_id: org_id} do
|
|
_open = insert_alert!(device.id, org_id, "device_down")
|
|
|
|
closed =
|
|
insert_alert!(device.id, org_id, "device_down", resolved_at: DateTime.truncate(DateTime.utc_now(), :second))
|
|
|
|
[result] = Repo.all(AlertQuery.resolved())
|
|
assert result.id == closed.id
|
|
end
|
|
|
|
test "with_severity/1 starts from base()", %{device: device, organization_id: org_id} do
|
|
crit = insert_alert!(device.id, org_id, "device_down", severity: 1)
|
|
_warn = insert_alert!(device.id, org_id, "device_down", severity: 2)
|
|
[result] = 1 |> AlertQuery.with_severity() |> Repo.all()
|
|
assert result.id == crit.id
|
|
end
|
|
end
|
|
|
|
describe "property: composed filters always return a subset" do
|
|
property "organization + type + unresolved is always a subset of for_organization", %{
|
|
device: device,
|
|
organization_id: org_id
|
|
} do
|
|
_ = insert_alert!(device.id, org_id, "device_down")
|
|
_ = insert_alert!(device.id, org_id, "device_up")
|
|
_ = insert_alert!(device.id, org_id, "device_down", resolved_at: DateTime.truncate(DateTime.utc_now(), :second))
|
|
|
|
check all(alert_type <- StreamData.member_of(["device_down", "device_up", "check_ping"]), max_runs: 25) do
|
|
all_for_org_ids =
|
|
AlertQuery.base()
|
|
|> AlertQuery.for_organization(org_id)
|
|
|> Repo.all()
|
|
|> MapSet.new(& &1.id)
|
|
|
|
narrowed_ids =
|
|
AlertQuery.base()
|
|
|> AlertQuery.for_organization(org_id)
|
|
|> AlertQuery.of_type(alert_type)
|
|
|> AlertQuery.unresolved()
|
|
|> Repo.all()
|
|
|> MapSet.new(& &1.id)
|
|
|
|
assert MapSet.subset?(narrowed_ids, all_for_org_ids)
|
|
end
|
|
end
|
|
end
|
|
|
|
defp insert_alert!(device_id, organization_id, alert_type, extra \\ []) do
|
|
attrs =
|
|
Enum.into(extra, %{
|
|
device_id: device_id,
|
|
organization_id: organization_id,
|
|
alert_type: alert_type,
|
|
triggered_at: DateTime.truncate(DateTime.utc_now(), :second)
|
|
})
|
|
|
|
%Alert{}
|
|
|> Alert.changeset(attrs)
|
|
|> Repo.insert!()
|
|
end
|
|
end
|