- Remove all 25ms and 50ms sleeps from agent_channel_test - Add poll_until helper for async DB operations (early exit on success) - Reduce timeout test sleeps from 100ms to 60ms - Reduce polling delays from 10ms to 5ms in multiple tests - Remove unnecessary timestamp and background task sleeps - Reduce circuit breaker recovery sleep from 150ms to 110ms Performance: 30.3s → 28.3s (6.6% faster) Total improvement from baseline: 52s → 28.3s (45.6% faster)
629 lines
20 KiB
Elixir
629 lines
20 KiB
Elixir
defmodule Towerops.AlertsTest do
|
|
use Towerops.DataCase
|
|
|
|
alias Towerops.Alerts
|
|
|
|
describe "alerts" do
|
|
import Towerops.AccountsFixtures
|
|
|
|
alias Towerops.Alerts.Alert
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
{:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
|
|
|
|
{:ok, site} =
|
|
Towerops.Sites.create_site(%{
|
|
name: "Test Site",
|
|
organization_id: organization.id
|
|
})
|
|
|
|
{:ok, device} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Router 1",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site.id,
|
|
organization_id: organization.id
|
|
})
|
|
|
|
%{device: device, organization: organization, user: user}
|
|
end
|
|
|
|
@valid_attrs %{
|
|
alert_type: "device_down",
|
|
triggered_at: ~U[2025-12-21 12:00:00Z],
|
|
message: "Equipment is not responding"
|
|
}
|
|
|
|
test "create_alert/1 with valid data creates an alert", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
assert {:ok, %Alert{} = alert} = Alerts.create_alert(attrs)
|
|
assert alert.alert_type == "device_down"
|
|
assert alert.message == "Equipment is not responding"
|
|
end
|
|
|
|
test "create_alert/1 with invalid data returns error changeset" do
|
|
assert {:error, %Ecto.Changeset{}} = Alerts.create_alert(%{})
|
|
end
|
|
|
|
test "list_devices_alerts/2 returns alerts for device", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
[result] = Alerts.list_devices_alerts(device.id)
|
|
assert result.id == alert.id
|
|
end
|
|
|
|
test "list_organization_active_alerts/1 returns unresolved alerts", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
|
|
# Create resolved alert
|
|
{:ok, resolved_alert} =
|
|
Alerts.create_alert(Map.put(attrs, :resolved_at, ~U[2025-12-21 13:00:00Z]))
|
|
|
|
active = Alerts.list_organization_active_alerts(organization.id)
|
|
assert length(active) == 1
|
|
assert hd(active).id == alert.id
|
|
refute Enum.any?(active, fn a -> a.id == resolved_alert.id end)
|
|
end
|
|
|
|
test "list_organization_alerts/2 returns all alerts", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, _alert1} = Alerts.create_alert(attrs)
|
|
{:ok, _alert2} = Alerts.create_alert(Map.put(attrs, :alert_type, :device_up))
|
|
|
|
alerts = Alerts.list_organization_alerts(organization.id, 100)
|
|
assert length(alerts) == 2
|
|
end
|
|
|
|
test "get_alert!/1 returns the alert with given id", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
assert Alerts.get_alert!(alert.id).id == alert.id
|
|
end
|
|
|
|
test "acknowledge_alert/2 marks alert as acknowledged", %{device: device, user: user} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
|
|
assert {:ok, acknowledged} = Alerts.acknowledge_alert(alert, user.id)
|
|
assert acknowledged.acknowledged_at
|
|
assert acknowledged.acknowledged_by_id == user.id
|
|
end
|
|
|
|
test "resolve_alert/1 marks alert as resolved", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
|
|
assert {:ok, resolved} = Alerts.resolve_alert(alert)
|
|
assert resolved.resolved_at
|
|
end
|
|
|
|
test "has_active_alert?/2 returns true when active alert exists", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, _alert} = Alerts.create_alert(attrs)
|
|
|
|
assert Alerts.has_active_alert?(device.id, :device_down) == true
|
|
assert Alerts.has_active_alert?(device.id, :device_up) == false
|
|
end
|
|
|
|
test "has_active_alert?/2 returns false for resolved alerts", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
{:ok, _resolved} = Alerts.resolve_alert(alert)
|
|
|
|
assert Alerts.has_active_alert?(device.id, :device_down) == false
|
|
end
|
|
|
|
test "get_active_alert/2 returns active alert of specific type", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
|
|
found = Alerts.get_active_alert(device.id, :device_down)
|
|
assert found.id == alert.id
|
|
end
|
|
|
|
test "get_active_alert/2 returns nil when no active alert exists", %{device: device} do
|
|
assert Alerts.get_active_alert(device.id, :device_down) == nil
|
|
end
|
|
|
|
test "get_active_alert/2 returns nil for resolved alerts", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
{:ok, _resolved} = Alerts.resolve_alert(alert)
|
|
|
|
assert Alerts.get_active_alert(device.id, :device_down) == nil
|
|
end
|
|
|
|
test "count_active_alerts/1 returns count of unresolved alerts", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, _alert1} = Alerts.create_alert(attrs)
|
|
{:ok, _alert2} = Alerts.create_alert(attrs)
|
|
|
|
# Create resolved alert
|
|
{:ok, resolved} = Alerts.create_alert(attrs)
|
|
{:ok, _} = Alerts.resolve_alert(resolved)
|
|
|
|
assert Alerts.count_active_alerts(organization.id) == 2
|
|
end
|
|
|
|
test "count_active_alerts/1 returns 0 when no active alerts", %{organization: organization} do
|
|
assert Alerts.count_active_alerts(organization.id) == 0
|
|
end
|
|
|
|
test "list_devices_alerts/2 respects limit parameter", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
# Create 5 alerts
|
|
for _i <- 1..5 do
|
|
{:ok, _} = Alerts.create_alert(attrs)
|
|
end
|
|
|
|
# Request only 3
|
|
alerts = Alerts.list_devices_alerts(device.id, 3)
|
|
assert length(alerts) == 3
|
|
end
|
|
|
|
test "list_devices_alerts/2 orders by triggered_at descending", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
{:ok, old_alert} =
|
|
Alerts.create_alert(Map.put(attrs, :triggered_at, ~U[2025-12-21 10:00:00Z]))
|
|
|
|
{:ok, new_alert} =
|
|
Alerts.create_alert(Map.put(attrs, :triggered_at, ~U[2025-12-21 12:00:00Z]))
|
|
|
|
[first, second] = Alerts.list_devices_alerts(device.id)
|
|
assert first.id == new_alert.id
|
|
assert second.id == old_alert.id
|
|
end
|
|
|
|
test "list_organization_alerts/2 with status filter active", %{
|
|
device: device,
|
|
organization: organization,
|
|
user: user
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
# Create unacknowledged alert
|
|
{:ok, active_alert} = Alerts.create_alert(attrs)
|
|
|
|
# Create acknowledged alert
|
|
{:ok, acked_alert} = Alerts.create_alert(attrs)
|
|
{:ok, _} = Alerts.acknowledge_alert(acked_alert, user.id)
|
|
|
|
# Create resolved alert
|
|
{:ok, resolved_alert} = Alerts.create_alert(attrs)
|
|
{:ok, _} = Alerts.resolve_alert(resolved_alert)
|
|
|
|
active = Alerts.list_organization_alerts(organization.id, %{"status" => "active"})
|
|
assert length(active) == 1
|
|
assert hd(active).id == active_alert.id
|
|
end
|
|
|
|
test "list_organization_alerts/2 with status filter acknowledged", %{
|
|
device: device,
|
|
organization: organization,
|
|
user: user
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
# Create acknowledged alert
|
|
{:ok, acked_alert} = Alerts.create_alert(attrs)
|
|
{:ok, _} = Alerts.acknowledge_alert(acked_alert, user.id)
|
|
|
|
# Create unacknowledged alert
|
|
{:ok, _active} = Alerts.create_alert(attrs)
|
|
|
|
acknowledged =
|
|
Alerts.list_organization_alerts(organization.id, %{"status" => "acknowledged"})
|
|
|
|
assert length(acknowledged) == 1
|
|
assert hd(acknowledged).id == acked_alert.id
|
|
end
|
|
|
|
test "list_organization_alerts/2 with status filter resolved", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
# Create resolved alert
|
|
{:ok, resolved_alert} = Alerts.create_alert(attrs)
|
|
{:ok, _} = Alerts.resolve_alert(resolved_alert)
|
|
|
|
# Create active alert
|
|
{:ok, _active} = Alerts.create_alert(attrs)
|
|
|
|
resolved = Alerts.list_organization_alerts(organization.id, %{"status" => "resolved"})
|
|
assert length(resolved) == 1
|
|
assert hd(resolved).id == resolved_alert.id
|
|
end
|
|
|
|
test "list_organization_alerts/2 with limit in filters map", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
for _i <- 1..5 do
|
|
{:ok, _} = Alerts.create_alert(attrs)
|
|
end
|
|
|
|
alerts = Alerts.list_organization_alerts(organization.id, %{"limit" => 2})
|
|
assert length(alerts) == 2
|
|
end
|
|
|
|
test "list_organization_alerts/2 defaults to limit 100", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
# Just verify it doesn't error with no limit specified
|
|
{:ok, _} = Alerts.create_alert(attrs)
|
|
|
|
alerts = Alerts.list_organization_alerts(organization.id, %{})
|
|
assert length(alerts) == 1
|
|
end
|
|
|
|
test "list_organization_active_alerts/1 only returns device_down alerts", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
# Create device_down alert
|
|
{:ok, down_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
# Create device_up alert
|
|
{:ok, _up_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device.id,
|
|
alert_type: "device_up",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
active = Alerts.list_organization_active_alerts(organization.id)
|
|
assert length(active) == 1
|
|
assert hd(active).id == down_alert.id
|
|
assert hd(active).alert_type == "device_down"
|
|
end
|
|
|
|
test "list_organization_active_alerts/1 preloads associations", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, _alert} = Alerts.create_alert(attrs)
|
|
|
|
[alert] = Alerts.list_organization_active_alerts(organization.id)
|
|
assert Ecto.assoc_loaded?(alert.device)
|
|
assert Ecto.assoc_loaded?(alert.device.site)
|
|
end
|
|
|
|
test "get_alert!/1 preloads associations", %{device: device} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
{:ok, alert} = Alerts.create_alert(attrs)
|
|
|
|
fetched = Alerts.get_alert!(alert.id)
|
|
assert Ecto.assoc_loaded?(fetched.device)
|
|
assert Ecto.assoc_loaded?(fetched.acknowledged_by)
|
|
end
|
|
|
|
test "get_alert!/1 raises when alert doesn't exist" do
|
|
assert_raise Ecto.NoResultsError, fn ->
|
|
Alerts.get_alert!(Ecto.UUID.generate())
|
|
end
|
|
end
|
|
|
|
test "get_active_alert/2 returns most recent when multiple active alerts", %{
|
|
device: device
|
|
} do
|
|
attrs = Map.put(@valid_attrs, :device_id, device.id)
|
|
|
|
{:ok, old_alert} =
|
|
Alerts.create_alert(Map.put(attrs, :triggered_at, ~U[2025-12-21 10:00:00Z]))
|
|
|
|
{:ok, new_alert} =
|
|
Alerts.create_alert(Map.put(attrs, :triggered_at, ~U[2025-12-21 12:00:00Z]))
|
|
|
|
found = Alerts.get_active_alert(device.id, :device_down)
|
|
assert found.id == new_alert.id
|
|
refute found.id == old_alert.id
|
|
end
|
|
|
|
test "count_active_alerts/1 only counts device_down alerts", %{
|
|
device: device,
|
|
organization: organization
|
|
} do
|
|
# Create device_down alert
|
|
{:ok, _} =
|
|
Alerts.create_alert(%{
|
|
device_id: device.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
# Create device_up alert (should not be counted)
|
|
{:ok, _} =
|
|
Alerts.create_alert(%{
|
|
device_id: device.id,
|
|
alert_type: "device_up",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
assert Alerts.count_active_alerts(organization.id) == 1
|
|
end
|
|
end
|
|
|
|
describe "GDPR data access - list_alerts_for_organizations/2" do
|
|
import Towerops.AccountsFixtures
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
{:ok, org1} = Towerops.Organizations.create_organization(%{name: "Org 1"}, user.id)
|
|
|
|
# Create org2 with a different owner to avoid subscription limits
|
|
other_user = user_fixture()
|
|
{:ok, org2} = Towerops.Organizations.create_organization(%{name: "Org 2"}, other_user.id)
|
|
|
|
{:ok, site1} =
|
|
Towerops.Sites.create_site(%{
|
|
name: "Org1 Site",
|
|
organization_id: org1.id
|
|
})
|
|
|
|
{:ok, site2} =
|
|
Towerops.Sites.create_site(%{
|
|
name: "Org2 Site",
|
|
organization_id: org2.id
|
|
})
|
|
|
|
{:ok, device1} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Device 1",
|
|
ip_address: "192.168.1.1",
|
|
site_id: site1.id,
|
|
organization_id: org1.id
|
|
})
|
|
|
|
{:ok, device2} =
|
|
Towerops.Devices.create_device(%{
|
|
name: "Device 2",
|
|
ip_address: "192.168.1.2",
|
|
site_id: site2.id,
|
|
organization_id: org2.id
|
|
})
|
|
|
|
%{org1: org1, org2: org2, device1: device1, device2: device2}
|
|
end
|
|
|
|
test "returns all alerts for given organizations", %{
|
|
org1: org1,
|
|
org2: org2,
|
|
device1: device1,
|
|
device2: device2
|
|
} do
|
|
{:ok, alert1} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now(),
|
|
message: "Device 1 down"
|
|
})
|
|
|
|
{:ok, alert2} =
|
|
Alerts.create_alert(%{
|
|
device_id: device2.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now(),
|
|
message: "Device 2 down"
|
|
})
|
|
|
|
# Default limit is 90 days
|
|
result = Alerts.list_alerts_for_organizations([org1.id, org2.id])
|
|
assert length(result) == 2
|
|
|
|
alert_ids = Enum.map(result, & &1.id)
|
|
assert alert1.id in alert_ids
|
|
assert alert2.id in alert_ids
|
|
end
|
|
|
|
test "returns only alerts from specified organizations", %{
|
|
org1: org1,
|
|
device1: device1,
|
|
device2: device2
|
|
} do
|
|
{:ok, alert1} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
{:ok, _alert2} =
|
|
Alerts.create_alert(%{
|
|
device_id: device2.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
# Only request alerts from org1
|
|
result = Alerts.list_alerts_for_organizations([org1.id])
|
|
assert length(result) == 1
|
|
assert hd(result).id == alert1.id
|
|
end
|
|
|
|
test "respects since parameter to filter old alerts", %{org1: org1, device1: device1} do
|
|
# Create recent alert (within 30 days)
|
|
{:ok, recent_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
# Sleep briefly to ensure different inserted_at times
|
|
Process.sleep(5)
|
|
|
|
# Create old alert (older than 30 days based on inserted_at)
|
|
{:ok, old_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
# Manually set old alert's inserted_at to 60 days ago
|
|
sixty_days_ago = DateTime.utc_now() |> DateTime.add(-60, :day) |> DateTime.truncate(:second)
|
|
|
|
old_alert
|
|
|> Ecto.Changeset.change(inserted_at: sixty_days_ago)
|
|
|> Towerops.Repo.update!()
|
|
|
|
# Request only alerts from last 30 days
|
|
thirty_days_ago = DateTime.add(DateTime.utc_now(), -30, :day)
|
|
result = Alerts.list_alerts_for_organizations([org1.id], since: thirty_days_ago)
|
|
assert length(result) == 1
|
|
assert hd(result).id == recent_alert.id
|
|
end
|
|
|
|
test "returns all alerts when no since parameter provided", %{org1: org1, device1: device1} do
|
|
# Create two alerts with different ages
|
|
{:ok, recent_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
{:ok, old_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.add(DateTime.utc_now(), -120, :day)
|
|
})
|
|
|
|
# Without since parameter, should return all alerts
|
|
result = Alerts.list_alerts_for_organizations([org1.id])
|
|
assert length(result) == 2
|
|
|
|
alert_ids = Enum.map(result, & &1.id)
|
|
assert recent_alert.id in alert_ids
|
|
assert old_alert.id in alert_ids
|
|
end
|
|
|
|
test "returns empty list when organizations have no alerts", %{org1: org1} do
|
|
result = Alerts.list_alerts_for_organizations([org1.id])
|
|
assert result == []
|
|
end
|
|
|
|
test "returns empty list for empty organization list" do
|
|
result = Alerts.list_alerts_for_organizations([])
|
|
assert result == []
|
|
end
|
|
|
|
test "preloads device and site associations", %{org1: org1, device1: device1} do
|
|
{:ok, _alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
result = Alerts.list_alerts_for_organizations([org1.id])
|
|
assert length(result) == 1
|
|
loaded_alert = hd(result)
|
|
assert Ecto.assoc_loaded?(loaded_alert.device)
|
|
assert Ecto.assoc_loaded?(loaded_alert.device.site)
|
|
end
|
|
|
|
test "orders alerts by triggered_at descending", %{org1: org1, device1: device1} do
|
|
{:ok, old_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.add(DateTime.utc_now(), -10, :day)
|
|
})
|
|
|
|
{:ok, new_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.add(DateTime.utc_now(), -5, :day)
|
|
})
|
|
|
|
result = Alerts.list_alerts_for_organizations([org1.id])
|
|
assert length(result) == 2
|
|
|
|
# Most recent should be first
|
|
[first, second] = result
|
|
assert first.id == new_alert.id
|
|
assert second.id == old_alert.id
|
|
end
|
|
|
|
test "includes both active and resolved alerts", %{org1: org1, device1: device1} do
|
|
# Create active alert
|
|
{:ok, active_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
# Create resolved alert
|
|
{:ok, resolved_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
{:ok, _} = Alerts.resolve_alert(resolved_alert)
|
|
|
|
# Should include both
|
|
result = Alerts.list_alerts_for_organizations([org1.id])
|
|
assert length(result) == 2
|
|
|
|
alert_ids = Enum.map(result, & &1.id)
|
|
assert active_alert.id in alert_ids
|
|
assert resolved_alert.id in alert_ids
|
|
end
|
|
|
|
test "includes all alert types", %{org1: org1, device1: device1} do
|
|
{:ok, _down_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_down",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
{:ok, _up_alert} =
|
|
Alerts.create_alert(%{
|
|
device_id: device1.id,
|
|
alert_type: "device_up",
|
|
triggered_at: DateTime.utc_now()
|
|
})
|
|
|
|
result = Alerts.list_alerts_for_organizations([org1.id])
|
|
assert length(result) == 2
|
|
|
|
alert_types = Enum.map(result, & &1.alert_type)
|
|
assert "device_down" in alert_types
|
|
assert "device_up" in alert_types
|
|
end
|
|
end
|
|
end
|