towerops/test/towerops_web/live/integrations_smoke_test.exs
Graham McIntire fde6158251 ci: enable PostGIS in test workflows + add tests covering ~3pp more
CI: switch postgres service image to timescale/timescaledb-ha:pg17-all
which bundles PostGIS, fixing the lidar migration failure in PR and
production workflows.

Tests: ~30 new test files / extensions, ~600+ new tests, taking total
coverage from 70.42% to 73.4%. Targets included GraphQL resolver
unauthenticated paths, SNMP context queries (mempools, processors,
ip_addresses, neighbors, wireless_clients, arp_entries), worker
routing/lifecycle (alert notification, alert digest, weather sync,
job cleanup, cn_maestro, uisp, mikrotik backup, report worker),
SNMP monitoring executors (storage, interface, processor) end-to-end
via stub adapter, NetBox + Sonar sync integration paths, ConfigChanges
listing and correlator, organizations membership query, and live-view
smoke tests for org-scoped settings, integrations, maintenance, agent,
device deep paths, schedules. Property tests used for query
composition and pure helpers where natural.
2026-05-05 10:35:22 -05:00

230 lines
7.8 KiB
Elixir

defmodule ToweropsWeb.IntegrationsSmokeTest do
@moduledoc """
Smoke tests for low-coverage org-scoped integration LiveViews and device-scoped
LiveViews. These tests exercise the mount/render/handle_params paths without
asserting deep behavior, which is sufficient for coverage of happy-path code.
"""
use ToweropsWeb.ConnCase, async: true
import Phoenix.LiveViewTest
alias Towerops.Devices.MikrotikBackups
alias Towerops.MaintenanceFixtures
setup :register_and_log_in_user
setup %{user: user} do
{:ok, organization} = Towerops.Organizations.create_organization(%{name: "Smoke Org"}, user.id)
%{organization: organization}
end
defp assert_mount_or_redirect(result) do
assert match?({:ok, _, _}, result) or
match?({:error, {:redirect, _}}, result) or
match?({:error, {:live_redirect, _}}, result)
end
describe "smoke: gaiia integration LiveViews" do
test "GET /orgs/:slug/settings/integrations/gaiia/mapping", %{conn: conn, organization: org} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/gaiia/mapping"))
end
test "GET /orgs/:slug/settings/integrations/gaiia/mapping?tab=sites", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/gaiia/mapping?tab=sites"))
end
test "GET /orgs/:slug/settings/integrations/gaiia/mapping?filter=linked", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/gaiia/mapping?filter=linked"))
end
test "GET /orgs/:slug/settings/integrations/gaiia/mapping?filter=unlinked", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/gaiia/mapping?filter=unlinked"))
end
test "GET /orgs/:slug/settings/integrations/gaiia/reconciliation", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/gaiia/reconciliation"))
end
test "GET /orgs/:slug/settings/integrations/gaiia/reconciliation?tab=devices", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/gaiia/reconciliation?tab=devices"))
end
test "GET /orgs/:slug/settings/integrations/gaiia/reconciliation?tab=sites", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/gaiia/reconciliation?tab=sites"))
end
end
describe "smoke: preseem integration LiveViews" do
test "GET /orgs/:slug/settings/integrations/preseem/devices", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/preseem/devices"))
end
test "GET /orgs/:slug/settings/integrations/preseem/devices?filter=matched", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/preseem/devices?filter=matched"))
end
test "GET /orgs/:slug/settings/integrations/preseem/devices?filter=unmatched", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/preseem/devices?filter=unmatched"))
end
test "GET /orgs/:slug/settings/integrations/preseem/insights", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/preseem/insights"))
end
test "GET /orgs/:slug/settings/integrations/preseem/insights?status=resolved", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(live(conn, ~p"/orgs/#{org.slug}/settings/integrations/preseem/insights?status=resolved"))
end
test "GET /orgs/:slug/settings/integrations/preseem/insights?type=qoe&urgency=high", %{
conn: conn,
organization: org
} do
assert_mount_or_redirect(
live(
conn,
~p"/orgs/#{org.slug}/settings/integrations/preseem/insights?type=qoe&urgency=high"
)
)
end
end
describe "smoke: user settings sub-tabs (SessionManager / TotpManager)" do
test "GET /users/settings (default index)", %{conn: conn} do
assert_mount_or_redirect(live(conn, ~p"/users/settings"))
end
test "GET /users/settings?tab=sessions", %{conn: conn} do
assert_mount_or_redirect(live(conn, ~p"/users/settings?tab=sessions"))
end
test "GET /users/settings?tab=security", %{conn: conn} do
assert_mount_or_redirect(live(conn, ~p"/users/settings?tab=security"))
end
test "GET /users/settings?tab=personal", %{conn: conn} do
assert_mount_or_redirect(live(conn, ~p"/users/settings?tab=personal"))
end
test "GET /users/settings?tab=account", %{conn: conn} do
assert_mount_or_redirect(live(conn, ~p"/users/settings?tab=account"))
end
test "GET /users/settings?tab=notifications", %{conn: conn} do
assert_mount_or_redirect(live(conn, ~p"/users/settings?tab=notifications"))
end
test "GET /users/settings?tab=api", %{conn: conn} do
assert_mount_or_redirect(live(conn, ~p"/users/settings?tab=api"))
end
end
describe "smoke: device-scoped LiveViews (ConfigTimeline / Compare)" do
setup %{organization: org} do
{:ok, site} =
Towerops.Sites.create_site(%{
name: "Site-#{System.unique_integer([:positive])}",
organization_id: org.id
})
device =
Towerops.DevicesFixtures.device_fixture(%{
organization_id: org.id,
site_id: site.id
})
%{site: site, device: device}
end
test "GET /devices/:device_id/config-timeline", %{conn: conn, device: device} do
assert_mount_or_redirect(live(conn, ~p"/devices/#{device.id}/config-timeline"))
end
test "GET /devices/:device_id/config-timeline?range=24h", %{conn: conn, device: device} do
assert_mount_or_redirect(live(conn, ~p"/devices/#{device.id}/config-timeline?range=24h"))
end
test "GET /devices/:device_id/config-timeline?range=30d", %{conn: conn, device: device} do
assert_mount_or_redirect(live(conn, ~p"/devices/#{device.id}/config-timeline?range=30d"))
end
test "GET /devices/:device_id/backups/compare without backup params redirects", %{
conn: conn,
device: device
} do
# Compare requires backup_a + backup_b query params; without them it redirects.
assert_mount_or_redirect(live(conn, ~p"/devices/#{device.id}/backups/compare"))
end
test "GET /devices/:device_id/backups/compare with two backups", %{
conn: conn,
device: device
} do
{:ok, backup_a} =
MikrotikBackups.create_backup(device.id, "/system identity\nset name=router-a", "manual")
{:ok, backup_b} =
MikrotikBackups.create_backup(device.id, "/system identity\nset name=router-b", "manual")
assert_mount_or_redirect(
live(
conn,
~p"/devices/#{device.id}/backups/compare?backup_a=#{backup_a.id}&backup_b=#{backup_b.id}"
)
)
end
end
describe "smoke: maintenance show extra params" do
setup %{organization: org, user: user} do
window =
MaintenanceFixtures.maintenance_window_fixture(%{
name: "Smoke Window 2",
organization_id: org.id,
created_by_id: user.id
})
%{window: window}
end
test "GET /maintenance/:id with tab param", %{conn: conn, window: window} do
assert_mount_or_redirect(live(conn, ~p"/maintenance/#{window.id}?tab=devices"))
end
test "GET /maintenance/:id/edit with section", %{conn: conn, window: window} do
assert_mount_or_redirect(live(conn, ~p"/maintenance/#{window.id}/edit"))
end
end
end