defmodule Towerops.DashboardTest do use Towerops.DataCase, async: true import Towerops.AccountsFixtures import Towerops.DevicesFixtures import Towerops.OrganizationsFixtures alias Towerops.Dashboard alias Towerops.Integrations setup do user = user_fixture() org = organization_fixture(user.id) %{org: org, user: user} end describe "get_dashboard_summary/1" do test "returns correct structure with empty org", %{org: org} do summary = Dashboard.get_dashboard_summary(org.id) assert is_map(summary) assert Map.has_key?(summary, :health_score) assert Map.has_key?(summary, :devices) assert Map.has_key?(summary, :alerts) assert Map.has_key?(summary, :subscribers) assert Map.has_key?(summary, :insights) end test "returns device counts", %{org: org} do device = device_fixture(%{organization_id: org.id}) Towerops.Devices.update_device_status(device, :up) summary = Dashboard.get_dashboard_summary(org.id) assert summary.devices.total == 1 assert summary.devices.up == 1 assert summary.devices.down == 0 end test "returns alert count", %{org: org} do device = device_fixture(%{organization_id: org.id}) {:ok, _alert} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device is down" }) summary = Dashboard.get_dashboard_summary(org.id) assert summary.alerts.active_count == 1 end test "returns subscriber totals from billing integrations", %{org: org} do {:ok, integration} = Integrations.create_integration(org.id, %{provider: "gaiia", enabled: true}) {:ok, _} = Integrations.update_billing_totals(integration, 100, Decimal.new("5000.00")) summary = Dashboard.get_dashboard_summary(org.id) assert summary.subscribers.total == 100 assert Decimal.equal?(summary.subscribers.total_mrr, Decimal.new("5000.00")) end test "returns zero subscribers when no billing integrations", %{org: org} do summary = Dashboard.get_dashboard_summary(org.id) assert summary.subscribers.total == 0 end test "returns insight counts by urgency", %{org: org} do summary = Dashboard.get_dashboard_summary(org.id) assert summary.insights.critical == 0 assert summary.insights.warning == 0 assert summary.insights.info == 0 end end describe "compute_health_score/1" do test "returns 100 when all devices up, no alerts", %{org: org} do device = device_fixture(%{organization_id: org.id}) Towerops.Devices.update_device_status(device, :up) score = Dashboard.compute_health_score(org.id) assert score == 100 end test "returns lower score when devices down", %{org: org} do d1 = device_fixture(%{organization_id: org.id}) d2 = device_fixture(%{organization_id: org.id}) Towerops.Devices.update_device_status(d1, :up) Towerops.Devices.update_device_status(d2, :down) score = Dashboard.compute_health_score(org.id) assert score < 100 assert score > 0 end test "returns 100 when no devices exist", %{org: org} do score = Dashboard.compute_health_score(org.id) assert score == 100 end test "penalizes for critical alerts", %{org: org} do device = device_fixture(%{organization_id: org.id}) Towerops.Devices.update_device_status(device, :up) {:ok, _} = Towerops.Alerts.create_alert(%{ device_id: device.id, alert_type: "device_down", triggered_at: DateTime.utc_now(), message: "Device down" }) score = Dashboard.compute_health_score(org.id) assert score < 100 end end describe "get_org_subscriber_summary/1" do test "returns totals from billing integrations", %{org: org} do {:ok, i1} = Integrations.create_integration(org.id, %{provider: "gaiia", enabled: true}) {:ok, _} = Integrations.update_billing_totals(i1, 50, Decimal.new("2500.00")) {:ok, i2} = Integrations.create_integration(org.id, %{provider: "splynx", enabled: true}) {:ok, _} = Integrations.update_billing_totals(i2, 30, Decimal.new("1500.00")) result = Dashboard.get_org_subscriber_summary(org.id) assert result.total == 80 assert Decimal.equal?(result.total_mrr, Decimal.new("4000.00")) end test "returns zeros when no billing integrations", %{org: org} do result = Dashboard.get_org_subscriber_summary(org.id) assert result.total == 0 assert Decimal.equal?(result.total_mrr, Decimal.new(0)) end end describe "list_site_summaries/1" do test "returns enriched site data", %{org: org} do {:ok, site} = Towerops.Sites.create_site(%{ name: "Test Tower", organization_id: org.id }) device = device_fixture(%{organization_id: org.id, site_id: site.id}) Towerops.Devices.update_device_status(device, :up) summaries = Dashboard.list_site_summaries(org.id) assert summaries != [] summary = Enum.find(summaries, &(&1.site_id == site.id)) assert summary.name == "Test Tower" assert summary.device_count >= 1 end end end