From f9a4611105cbbb5d0be9972a242b943ac15c25a8 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 8 May 2026 11:28:25 -0500 Subject: [PATCH] test: add query module tests for SiteQuery, AgentTokenQuery, ScheduleQuery, EscalationPolicyQuery --- test/towerops/query_modules_test.exs | 137 +++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 test/towerops/query_modules_test.exs diff --git a/test/towerops/query_modules_test.exs b/test/towerops/query_modules_test.exs new file mode 100644 index 00000000..5afb8132 --- /dev/null +++ b/test/towerops/query_modules_test.exs @@ -0,0 +1,137 @@ +defmodule Towerops.QueryModulesTest do + @moduledoc """ + Coverage for the small composable query modules. Each function is a thin + Ecto.Query.where/order wrapper — exercising the default-argument arity + variants is what's missing from coverage. + """ + use Towerops.DataCase, async: true + + import Towerops.AccountsFixtures + + alias Towerops.Agents.AgentTokenQuery + alias Towerops.OnCall.EscalationPolicyQuery + alias Towerops.OnCall.ScheduleQuery + alias Towerops.Repo + alias Towerops.Sites.SiteQuery + + setup do + user = user_fixture() + {:ok, org} = Towerops.Organizations.create_organization(%{name: "Q Org"}, user.id) + %{user: user, organization: org} + end + + describe "Sites.SiteQuery" do + test "roots/0 returns Site query without parent filter applied", %{organization: org} do + {:ok, parent} = Towerops.Sites.create_site(%{name: "Parent", organization_id: org.id}) + + {:ok, _child} = + Towerops.Sites.create_site(%{ + name: "Child", + organization_id: org.id, + parent_site_id: parent.id + }) + + ids = + SiteQuery.base() + |> SiteQuery.for_organization(org.id) + |> SiteQuery.roots() + |> Repo.all() + |> Enum.map(& &1.id) + + assert parent.id in ids + end + + test "order_by_display/0 sorts the implicit Site source", %{organization: org} do + {:ok, b} = Towerops.Sites.create_site(%{name: "B Site", organization_id: org.id}) + {:ok, a} = Towerops.Sites.create_site(%{name: "A Site", organization_id: org.id}) + + result = + SiteQuery.order_by_display() + |> SiteQuery.for_organization(org.id) + |> Repo.all() + + ids = Enum.map(result, & &1.id) + assert Enum.find_index(ids, &(&1 == a.id)) < Enum.find_index(ids, &(&1 == b.id)) + end + end + + describe "Agents.AgentTokenQuery" do + test "excluding_cloud_pollers/0 returns the implicit AgentToken source", %{organization: org} do + {:ok, normal, _raw} = Towerops.Agents.create_agent_token(org.id, "Normal Agent") + {:ok, cloud, _raw} = Towerops.Agents.create_cloud_poller("Cloud Poller") + + ids = + AgentTokenQuery.excluding_cloud_pollers() + |> Repo.all() + |> Enum.map(& &1.id) + + assert normal.id in ids + refute cloud.id in ids + end + + test "enabled/0 filters disabled tokens out", %{organization: org} do + {:ok, _enabled_tok, _raw} = Towerops.Agents.create_agent_token(org.id, "Enabled") + {:ok, disabled_tok, _raw} = Towerops.Agents.create_agent_token(org.id, "Disabled") + + Repo.update_all( + Ecto.Query.from(t in Towerops.Agents.AgentToken, where: t.id == ^disabled_tok.id), + set: [enabled: false] + ) + + ids = + AgentTokenQuery.enabled() + |> AgentTokenQuery.for_organization(org.id) + |> Repo.all() + |> Enum.map(& &1.id) + + refute disabled_tok.id in ids + end + end + + describe "OnCall.ScheduleQuery" do + test "with_id/1 and order_by_name/0 use base() default", %{organization: org} do + {:ok, b} = + Towerops.OnCall.create_schedule(%{name: "B Schedule", organization_id: org.id, timezone: "UTC"}) + + {:ok, a} = + Towerops.OnCall.create_schedule(%{name: "A Schedule", organization_id: org.id, timezone: "UTC"}) + + assert [%{id: id}] = + a.id + |> ScheduleQuery.with_id() + |> ScheduleQuery.for_organization(org.id) + |> Repo.all() + + assert id == a.id + + ordered = + ScheduleQuery.order_by_name() + |> ScheduleQuery.for_organization(org.id) + |> Repo.all() + |> Enum.map(& &1.id) + + assert Enum.find_index(ordered, &(&1 == a.id)) < + Enum.find_index(ordered, &(&1 == b.id)) + end + end + + describe "OnCall.EscalationPolicyQuery" do + test "with_id/1 and order_by_name/0 use base() default", %{organization: org} do + {:ok, p} = + Towerops.OnCall.create_escalation_policy(%{name: "Pri", organization_id: org.id}) + + assert [%{id: id}] = + p.id + |> EscalationPolicyQuery.with_id() + |> EscalationPolicyQuery.for_organization(org.id) + |> Repo.all() + + assert id == p.id + + assert [%{id: ^id}] = + EscalationPolicyQuery.order_by_name() + |> EscalationPolicyQuery.for_organization(org.id) + |> Repo.all() + end + end +end