This commit is contained in:
Graham McIntire 2026-05-07 13:14:02 -05:00
parent 03ec909e3a
commit f36315acf9
4 changed files with 26595 additions and 81 deletions

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,161 @@
defmodule Towerops.Reports.ReportTest do
use Towerops.DataCase, async: true
alias Towerops.Reports.Report
describe "valid_report_types/0" do
test "returns list of valid report types" do
assert Report.valid_report_types() == ~w(uptime_summary alert_history capacity_trends rf_link_health)
end
end
describe "valid_formats/0" do
test "returns list of valid formats" do
assert Report.valid_formats() == ~w(csv)
end
end
describe "valid_schedule_types/0" do
test "returns list of valid schedule types" do
assert Report.valid_schedule_types() == ~w(one_time daily weekly monthly)
end
end
describe "changeset/2" do
test "valid changeset with valid attrs" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
schedule: %{"type" => "daily"},
recipients: ["admin@example.com"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
assert changeset.valid?
end
test "invalid without name" do
attrs = %{
report_type: "uptime_summary",
schedule: %{"type" => "daily"},
recipients: ["admin@example.com"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
refute changeset.valid?
assert changeset.errors[:name]
end
test "invalid without organization_id" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
schedule: %{"type" => "daily"},
recipients: ["admin@example.com"]
}
changeset = Report.changeset(%Report{}, attrs)
refute changeset.valid?
assert changeset.errors[:organization_id]
end
test "invalid report_type" do
attrs = %{
name: "Uptime Report",
report_type: "invalid_type",
schedule: %{"type" => "daily"},
recipients: ["admin@example.com"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
refute changeset.valid?
assert changeset.errors[:report_type]
end
test "invalid format" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
format: "pdf",
schedule: %{"type" => "daily"},
recipients: ["admin@example.com"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
refute changeset.valid?
assert changeset.errors[:format]
end
test "invalid schedule without type key" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
schedule: %{},
recipients: ["admin@example.com"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
refute changeset.valid?
assert changeset.errors[:schedule]
end
test "invalid recipients when empty" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
schedule: %{"type" => "daily"},
recipients: [],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
refute changeset.valid?
assert changeset.errors[:recipients]
end
test "invalid recipients with invalid email" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
schedule: %{"type" => "daily"},
recipients: ["not-an-email"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
refute changeset.valid?
assert changeset.errors[:recipients]
end
test "uses default format csv" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
schedule: %{"type" => "daily"},
recipients: ["admin@example.com"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
assert get_field(changeset, :format) == "csv"
end
test "uses default enabled true" do
attrs = %{
name: "Uptime Report",
report_type: "uptime_summary",
schedule: %{"type" => "daily"},
recipients: ["admin@example.com"],
organization_id: Ecto.UUID.generate()
}
changeset = Report.changeset(%Report{}, attrs)
assert get_field(changeset, :enabled) == true
end
end
end

View file

@ -0,0 +1,97 @@
defmodule Towerops.Settings.ApplicationSettingTest do
use Towerops.DataCase, async: true
alias Towerops.Settings.ApplicationSetting
describe "parse_value/1" do
test "returns nil for nil value" do
setting = %ApplicationSetting{value: nil, value_type: "string"}
assert ApplicationSetting.parse_value(setting) == nil
end
test "returns string value as-is" do
setting = %ApplicationSetting{value: "hello", value_type: "string"}
assert ApplicationSetting.parse_value(setting) == "hello"
end
test "returns uuid value as-is" do
setting = %ApplicationSetting{value: "abc-123-def", value_type: "uuid"}
assert ApplicationSetting.parse_value(setting) == "abc-123-def"
end
test "parses integer value" do
setting = %ApplicationSetting{value: "42", value_type: "integer"}
assert ApplicationSetting.parse_value(setting) == 42
end
test "returns nil for unparseable integer" do
setting = %ApplicationSetting{value: "not-a-number", value_type: "integer"}
assert ApplicationSetting.parse_value(setting) == nil
end
test "parses boolean true" do
setting = %ApplicationSetting{value: "true", value_type: "boolean"}
assert ApplicationSetting.parse_value(setting) == true
end
test "parses boolean true from 1" do
setting = %ApplicationSetting{value: "1", value_type: "boolean"}
assert ApplicationSetting.parse_value(setting) == true
end
test "parses boolean false" do
setting = %ApplicationSetting{value: "false", value_type: "boolean"}
assert ApplicationSetting.parse_value(setting) == false
end
test "parses JSON value" do
setting = %ApplicationSetting{value: ~s({"key":"value"}), value_type: "json", key: "test"}
assert ApplicationSetting.parse_value(setting) == %{"key" => "value"}
end
test "returns nil for invalid JSON" do
setting = %ApplicationSetting{value: "{invalid", value_type: "json", key: "test"}
assert ApplicationSetting.parse_value(setting) == nil
end
test "parses decimal value" do
setting = %ApplicationSetting{value: "3.14", value_type: "decimal"}
result = ApplicationSetting.parse_value(setting)
assert Decimal.equal?(result, Decimal.new("3.14"))
end
test "returns nil for unparseable decimal" do
setting = %ApplicationSetting{value: "not-a-decimal", value_type: "decimal"}
assert ApplicationSetting.parse_value(setting) == nil
end
end
describe "changeset/2" do
test "valid changeset with valid attrs" do
attrs = %{key: "site_title", value: "TowerOps", value_type: "string"}
changeset = ApplicationSetting.changeset(%ApplicationSetting{}, attrs)
assert changeset.valid?
end
test "invalid without key" do
attrs = %{value_type: "string"}
changeset = ApplicationSetting.changeset(%ApplicationSetting{}, attrs)
refute changeset.valid?
assert changeset.errors[:key]
end
test "invalid without value_type" do
attrs = %{key: "site_title", value_type: ""}
changeset = ApplicationSetting.changeset(%ApplicationSetting{}, attrs)
refute changeset.valid?
assert changeset.errors[:value_type]
end
test "invalid value_type" do
attrs = %{key: "site_title", value: "hello", value_type: "unsupported"}
changeset = ApplicationSetting.changeset(%ApplicationSetting{}, attrs)
refute changeset.valid?
assert changeset.errors[:value_type]
end
end
end

View file

@ -1,81 +0,0 @@
defmodule Towerops.StatusPages.StatusIncidentTest do
use ExUnit.Case, async: true
alias Towerops.StatusPages.StatusIncident
describe "changeset/2" do
test "valid with required fields" do
attrs = %{
title: "Outage in core",
status: "investigating",
started_at: DateTime.truncate(DateTime.utc_now(), :second),
status_page_config_id: Ecto.UUID.generate()
}
assert StatusIncident.changeset(%StatusIncident{}, attrs).valid?
end
test "rejects missing required fields" do
attrs = %{}
changeset = StatusIncident.changeset(%StatusIncident{}, attrs)
refute changeset.valid?
keys = Keyword.keys(changeset.errors)
assert :title in keys
assert :started_at in keys
assert :status_page_config_id in keys
end
test "rejects invalid severity" do
attrs = %{
title: "x",
status: "investigating",
severity: "catastrophic",
started_at: DateTime.truncate(DateTime.utc_now(), :second),
status_page_config_id: Ecto.UUID.generate()
}
changeset = StatusIncident.changeset(%StatusIncident{}, attrs)
refute changeset.valid?
assert {:severity, _} = List.keyfind(changeset.errors, :severity, 0)
end
test "rejects invalid status" do
attrs = %{
title: "x",
status: "nuked",
started_at: DateTime.truncate(DateTime.utc_now(), :second),
status_page_config_id: Ecto.UUID.generate()
}
changeset = StatusIncident.changeset(%StatusIncident{}, attrs)
refute changeset.valid?
assert {:status, _} = List.keyfind(changeset.errors, :status, 0)
end
test "accepts each valid severity and status" do
base_attrs = %{
title: "x",
started_at: DateTime.truncate(DateTime.utc_now(), :second),
status_page_config_id: Ecto.UUID.generate()
}
for severity <- StatusIncident.valid_severities() do
attrs = base_attrs |> Map.put(:severity, severity) |> Map.put(:status, "investigating")
assert StatusIncident.changeset(%StatusIncident{}, attrs).valid?, "expected severity #{severity} to be valid"
end
for status <- StatusIncident.valid_statuses() do
attrs = Map.put(base_attrs, :status, status)
assert StatusIncident.changeset(%StatusIncident{}, attrs).valid?, "expected status #{status} to be valid"
end
end
end
describe "valid_severities/0 and valid_statuses/0" do
test "return canonical lists" do
assert StatusIncident.valid_severities() == ~w(minor major critical)
assert StatusIncident.valid_statuses() == ~w(investigating identified monitoring resolved)
end
end
end