Tests for agents, alerts, integrations, organization, members, and invitations controllers. Refactor alert filters to reduce complexity. 75 new tests, all passing.
254 lines
8.1 KiB
Elixir
254 lines
8.1 KiB
Elixir
defmodule ToweropsWeb.Api.V1.AlertsControllerTest do
|
|
use ToweropsWeb.ConnCase, async: true
|
|
|
|
import Towerops.AccountsFixtures
|
|
import Towerops.DevicesFixtures
|
|
import Towerops.OrganizationsFixtures
|
|
|
|
alias Towerops.Alerts
|
|
alias Towerops.ApiTokens
|
|
|
|
setup do
|
|
user = user_fixture()
|
|
organization = organization_fixture(user.id)
|
|
|
|
{:ok, {_token, raw_token}} =
|
|
ApiTokens.create_api_token(%{
|
|
organization_id: organization.id,
|
|
user_id: user.id,
|
|
name: "Test Token"
|
|
})
|
|
|
|
conn =
|
|
build_conn()
|
|
|> put_req_header("authorization", "Bearer #{raw_token}")
|
|
|> put_req_header("accept", "application/json")
|
|
|
|
%{
|
|
conn: conn,
|
|
user: user,
|
|
organization: organization
|
|
}
|
|
end
|
|
|
|
defp create_alert(device, attrs \\ %{}) do
|
|
default_attrs = %{
|
|
device_id: device.id,
|
|
alert_type: "ping_down",
|
|
message: "Device unreachable",
|
|
triggered_at: DateTime.truncate(DateTime.utc_now(), :second)
|
|
}
|
|
|
|
{:ok, alert} = Alerts.create_alert(Map.merge(default_attrs, attrs))
|
|
alert
|
|
end
|
|
|
|
describe "index/2" do
|
|
test "lists alerts for the authenticated organization", %{
|
|
conn: conn,
|
|
organization: organization
|
|
} do
|
|
device = device_fixture(%{organization_id: organization.id})
|
|
alert1 = create_alert(device)
|
|
alert2 = create_alert(device, %{alert_type: "device_down", message: "SNMP timeout"})
|
|
|
|
conn = get(conn, ~p"/api/v1/alerts")
|
|
|
|
assert %{"data" => alerts} = json_response(conn, 200)
|
|
assert length(alerts) == 2
|
|
|
|
alert_ids = Enum.map(alerts, & &1["id"])
|
|
assert alert1.id in alert_ids
|
|
assert alert2.id in alert_ids
|
|
|
|
alert_json = List.first(alerts)
|
|
assert Map.has_key?(alert_json, "id")
|
|
assert Map.has_key?(alert_json, "alert_type")
|
|
assert Map.has_key?(alert_json, "message")
|
|
assert Map.has_key?(alert_json, "triggered_at")
|
|
assert Map.has_key?(alert_json, "acknowledged_at")
|
|
assert Map.has_key?(alert_json, "resolved_at")
|
|
assert Map.has_key?(alert_json, "device_id")
|
|
assert Map.has_key?(alert_json, "device_name")
|
|
assert Map.has_key?(alert_json, "acknowledged_by_email")
|
|
assert Map.has_key?(alert_json, "gaiia_impact")
|
|
assert Map.has_key?(alert_json, "inserted_at")
|
|
end
|
|
|
|
test "returns empty list when organization has no alerts", %{conn: conn} do
|
|
conn = get(conn, ~p"/api/v1/alerts")
|
|
|
|
assert %{"data" => []} = json_response(conn, 200)
|
|
end
|
|
|
|
test "filters by status param for open alerts", %{
|
|
conn: conn,
|
|
organization: organization
|
|
} do
|
|
device = device_fixture(%{organization_id: organization.id})
|
|
_open_alert = create_alert(device)
|
|
|
|
resolved_alert = create_alert(device, %{alert_type: "device_down", message: "Resolved one"})
|
|
Alerts.resolve_alert(resolved_alert)
|
|
|
|
conn = get(conn, ~p"/api/v1/alerts?status=active")
|
|
|
|
assert %{"data" => alerts} = json_response(conn, 200)
|
|
assert length(alerts) == 1
|
|
|
|
[returned] = alerts
|
|
assert is_nil(returned["resolved_at"])
|
|
end
|
|
|
|
test "filters by device_id param", %{
|
|
conn: conn,
|
|
organization: organization
|
|
} do
|
|
device1 = device_fixture(%{organization_id: organization.id})
|
|
device2 = device_fixture(%{organization_id: organization.id})
|
|
|
|
_alert1 = create_alert(device1)
|
|
_alert2 = create_alert(device2)
|
|
|
|
conn = get(conn, ~p"/api/v1/alerts?device_id=#{device1.id}")
|
|
|
|
assert %{"data" => alerts} = json_response(conn, 200)
|
|
assert length(alerts) == 1
|
|
assert List.first(alerts)["device_id"] == device1.id
|
|
end
|
|
|
|
test "does not return alerts from other organizations", %{conn: conn} do
|
|
other_user = user_fixture()
|
|
other_org = organization_fixture(other_user.id)
|
|
other_device = device_fixture(%{organization_id: other_org.id})
|
|
_other_alert = create_alert(other_device)
|
|
|
|
conn = get(conn, ~p"/api/v1/alerts")
|
|
|
|
assert %{"data" => []} = json_response(conn, 200)
|
|
end
|
|
end
|
|
|
|
describe "show/2" do
|
|
test "returns alert details when it belongs to the organization", %{
|
|
conn: conn,
|
|
organization: organization
|
|
} do
|
|
device = device_fixture(%{organization_id: organization.id})
|
|
alert = create_alert(device)
|
|
|
|
conn = get(conn, ~p"/api/v1/alerts/#{alert.id}")
|
|
|
|
assert %{"data" => alert_json} = json_response(conn, 200)
|
|
assert alert_json["id"] == alert.id
|
|
assert alert_json["alert_type"] == "ping_down"
|
|
assert alert_json["message"] == "Device unreachable"
|
|
assert alert_json["device_id"] == device.id
|
|
assert alert_json["device_name"] == device.name
|
|
end
|
|
|
|
test "returns 404 when alert does not exist", %{conn: conn} do
|
|
conn = get(conn, ~p"/api/v1/alerts/#{Ecto.UUID.generate()}")
|
|
|
|
assert %{"error" => "Alert not found"} = json_response(conn, 404)
|
|
end
|
|
|
|
test "returns 404 when alert belongs to a different organization", %{conn: conn} do
|
|
other_user = user_fixture()
|
|
other_org = organization_fixture(other_user.id)
|
|
other_device = device_fixture(%{organization_id: other_org.id})
|
|
other_alert = create_alert(other_device)
|
|
|
|
conn = get(conn, ~p"/api/v1/alerts/#{other_alert.id}")
|
|
|
|
assert %{"error" => "Alert not found"} = json_response(conn, 404)
|
|
end
|
|
end
|
|
|
|
describe "acknowledge/2" do
|
|
test "sets acknowledged_at on the alert", %{
|
|
conn: conn,
|
|
organization: organization
|
|
} do
|
|
device = device_fixture(%{organization_id: organization.id})
|
|
alert = create_alert(device)
|
|
|
|
conn = post(conn, ~p"/api/v1/alerts/#{alert.id}/acknowledge")
|
|
|
|
assert %{"data" => alert_json} = json_response(conn, 200)
|
|
assert alert_json["id"] == alert.id
|
|
assert alert_json["acknowledged_at"]
|
|
end
|
|
|
|
test "returns 404 when alert belongs to a different organization", %{conn: conn} do
|
|
other_user = user_fixture()
|
|
other_org = organization_fixture(other_user.id)
|
|
other_device = device_fixture(%{organization_id: other_org.id})
|
|
other_alert = create_alert(other_device)
|
|
|
|
conn = post(conn, ~p"/api/v1/alerts/#{other_alert.id}/acknowledge")
|
|
|
|
assert %{"error" => "Alert not found"} = json_response(conn, 404)
|
|
end
|
|
|
|
test "returns 404 when alert does not exist", %{conn: conn} do
|
|
conn = post(conn, ~p"/api/v1/alerts/#{Ecto.UUID.generate()}/acknowledge")
|
|
|
|
assert %{"error" => "Alert not found"} = json_response(conn, 404)
|
|
end
|
|
end
|
|
|
|
describe "resolve/2" do
|
|
test "sets resolved_at on the alert", %{
|
|
conn: conn,
|
|
organization: organization
|
|
} do
|
|
device = device_fixture(%{organization_id: organization.id})
|
|
alert = create_alert(device)
|
|
|
|
conn = post(conn, ~p"/api/v1/alerts/#{alert.id}/resolve")
|
|
|
|
assert %{"data" => alert_json} = json_response(conn, 200)
|
|
assert alert_json["id"] == alert.id
|
|
assert alert_json["resolved_at"]
|
|
end
|
|
|
|
test "returns 404 when alert belongs to a different organization", %{conn: conn} do
|
|
other_user = user_fixture()
|
|
other_org = organization_fixture(other_user.id)
|
|
other_device = device_fixture(%{organization_id: other_org.id})
|
|
other_alert = create_alert(other_device)
|
|
|
|
conn = post(conn, ~p"/api/v1/alerts/#{other_alert.id}/resolve")
|
|
|
|
assert %{"error" => "Alert not found"} = json_response(conn, 404)
|
|
end
|
|
|
|
test "returns 404 when alert does not exist", %{conn: conn} do
|
|
conn = post(conn, ~p"/api/v1/alerts/#{Ecto.UUID.generate()}/resolve")
|
|
|
|
assert %{"error" => "Alert not found"} = json_response(conn, 404)
|
|
end
|
|
end
|
|
|
|
describe "authentication" do
|
|
test "returns 401 without authorization header" do
|
|
conn =
|
|
build_conn()
|
|
|> put_req_header("accept", "application/json")
|
|
|> get(~p"/api/v1/alerts")
|
|
|
|
assert %{"error" => _message} = json_response(conn, 401)
|
|
end
|
|
|
|
test "returns 401 with invalid token" do
|
|
conn =
|
|
build_conn()
|
|
|> put_req_header("authorization", "Bearer towerops_invalid_token")
|
|
|> put_req_header("accept", "application/json")
|
|
|> get(~p"/api/v1/alerts")
|
|
|
|
assert %{"error" => _message} = json_response(conn, 401)
|
|
end
|
|
end
|
|
end
|