more tests
This commit is contained in:
parent
b78a40555c
commit
88d549cd92
5 changed files with 546 additions and 6 deletions
|
|
@ -48,9 +48,6 @@ defmodule Towerops.Accounts.UserConsent do
|
|||
|> validate_required([:user_id, :consent_type, :version, :granted_at])
|
||||
|> validate_inclusion(:consent_type, @consent_types)
|
||||
|> foreign_key_constraint(:user_id)
|
||||
|> unique_constraint([:user_id, :consent_type, :version],
|
||||
name: :user_consents_user_id_consent_type_version_index
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
@ -64,7 +61,8 @@ defmodule Towerops.Accounts.UserConsent do
|
|||
end
|
||||
|
||||
defp validate_not_already_revoked(changeset) do
|
||||
if get_field(changeset, :revoked_at) do
|
||||
# Check the original struct's revoked_at, not the changeset's pending changes
|
||||
if changeset.data.revoked_at do
|
||||
add_error(changeset, :revoked_at, "consent already revoked")
|
||||
else
|
||||
changeset
|
||||
|
|
|
|||
|
|
@ -243,12 +243,16 @@ defmodule ToweropsWeb.UserRegistrationLive do
|
|||
/>
|
||||
</div>
|
||||
<div class="ml-3 text-sm">
|
||||
<label for="privacy_policy_consent" class="text-zinc-700 dark:text-zinc-300">
|
||||
<label
|
||||
for="privacy_policy_consent"
|
||||
class="text-zinc-700 dark:text-zinc-300 cursor-pointer"
|
||||
>
|
||||
I agree to the
|
||||
<.link
|
||||
href={~p"/privacy"}
|
||||
target="_blank"
|
||||
class="font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
onclick="event.stopPropagation()"
|
||||
>
|
||||
Privacy Policy
|
||||
</.link>
|
||||
|
|
@ -268,12 +272,16 @@ defmodule ToweropsWeb.UserRegistrationLive do
|
|||
/>
|
||||
</div>
|
||||
<div class="ml-3 text-sm">
|
||||
<label for="terms_of_service_consent" class="text-zinc-700 dark:text-zinc-300">
|
||||
<label
|
||||
for="terms_of_service_consent"
|
||||
class="text-zinc-700 dark:text-zinc-300 cursor-pointer"
|
||||
>
|
||||
I agree to the
|
||||
<.link
|
||||
href={~p"/terms"}
|
||||
target="_blank"
|
||||
class="font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
onclick="event.stopPropagation()"
|
||||
>
|
||||
Terms of Service
|
||||
</.link>
|
||||
|
|
|
|||
236
test/towerops/accounts/user_consent_test.exs
Normal file
236
test/towerops/accounts/user_consent_test.exs
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
defmodule Towerops.Accounts.UserConsentTest do
|
||||
use Towerops.DataCase, async: true
|
||||
|
||||
import Towerops.AccountsFixtures
|
||||
|
||||
alias Towerops.Accounts.UserConsent
|
||||
|
||||
describe "consent_types/0" do
|
||||
test "returns list of valid consent types" do
|
||||
types = UserConsent.consent_types()
|
||||
assert "privacy_policy" in types
|
||||
assert "terms_of_service" in types
|
||||
assert length(types) == 2
|
||||
end
|
||||
end
|
||||
|
||||
describe "current_version/1" do
|
||||
test "returns current version for privacy_policy" do
|
||||
assert UserConsent.current_version("privacy_policy") == "1.0"
|
||||
end
|
||||
|
||||
test "returns current version for terms_of_service" do
|
||||
assert UserConsent.current_version("terms_of_service") == "1.0"
|
||||
end
|
||||
end
|
||||
|
||||
describe "grant_changeset/2" do
|
||||
setup do
|
||||
user = user_fixture()
|
||||
{:ok, user: user}
|
||||
end
|
||||
|
||||
test "valid attributes create valid changeset", %{user: user} do
|
||||
attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
assert changeset.valid?
|
||||
end
|
||||
|
||||
test "requires user_id" do
|
||||
attrs = %{
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
refute changeset.valid?
|
||||
assert "can't be blank" in errors_on(changeset).user_id
|
||||
end
|
||||
|
||||
test "requires consent_type", %{user: user} do
|
||||
attrs = %{
|
||||
user_id: user.id,
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
refute changeset.valid?
|
||||
assert "can't be blank" in errors_on(changeset).consent_type
|
||||
end
|
||||
|
||||
test "requires version", %{user: user} do
|
||||
attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
refute changeset.valid?
|
||||
assert "can't be blank" in errors_on(changeset).version
|
||||
end
|
||||
|
||||
test "requires granted_at", %{user: user} do
|
||||
attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0"
|
||||
}
|
||||
|
||||
changeset = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
refute changeset.valid?
|
||||
assert "can't be blank" in errors_on(changeset).granted_at
|
||||
end
|
||||
|
||||
test "validates consent_type is in valid list", %{user: user} do
|
||||
attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "invalid_type",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
refute changeset.valid?
|
||||
assert "is invalid" in errors_on(changeset).consent_type
|
||||
end
|
||||
|
||||
test "validates foreign key constraint on user_id" do
|
||||
attrs = %{
|
||||
user_id: Ecto.UUID.generate(),
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
assert changeset.valid?
|
||||
|
||||
{:error, changeset} = Repo.insert(changeset)
|
||||
assert "does not exist" in errors_on(changeset).user_id
|
||||
end
|
||||
|
||||
test "allows multiple consents for same user_id + consent_type + version", %{user: user} do
|
||||
attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
# Insert first consent
|
||||
changeset1 = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
assert {:ok, _consent1} = Repo.insert(changeset1)
|
||||
|
||||
# Insert another consent (allowed - e.g., user re-consents after revoking)
|
||||
changeset2 = UserConsent.grant_changeset(%UserConsent{}, attrs)
|
||||
assert {:ok, _consent2} = Repo.insert(changeset2)
|
||||
end
|
||||
|
||||
test "allows same user to consent to different types", %{user: user} do
|
||||
privacy_attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
terms_attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "terms_of_service",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset1 = UserConsent.grant_changeset(%UserConsent{}, privacy_attrs)
|
||||
assert {:ok, _consent1} = Repo.insert(changeset1)
|
||||
|
||||
changeset2 = UserConsent.grant_changeset(%UserConsent{}, terms_attrs)
|
||||
assert {:ok, _consent2} = Repo.insert(changeset2)
|
||||
end
|
||||
|
||||
test "allows same user to consent to different versions", %{user: user} do
|
||||
v1_attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
v2_attrs = %{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
version: "2.0",
|
||||
granted_at: DateTime.utc_now()
|
||||
}
|
||||
|
||||
changeset1 = UserConsent.grant_changeset(%UserConsent{}, v1_attrs)
|
||||
assert {:ok, _consent1} = Repo.insert(changeset1)
|
||||
|
||||
changeset2 = UserConsent.grant_changeset(%UserConsent{}, v2_attrs)
|
||||
assert {:ok, _consent2} = Repo.insert(changeset2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "revoke_changeset/2" do
|
||||
setup do
|
||||
user = user_fixture()
|
||||
granted_at = DateTime.utc_now()
|
||||
|
||||
consent =
|
||||
%UserConsent{}
|
||||
|> UserConsent.grant_changeset(%{
|
||||
user_id: user.id,
|
||||
consent_type: "privacy_policy",
|
||||
version: "1.0",
|
||||
granted_at: granted_at
|
||||
})
|
||||
|> Repo.insert!()
|
||||
|
||||
{:ok, user: user, consent: consent}
|
||||
end
|
||||
|
||||
test "valid attributes create valid changeset", %{consent: consent} do
|
||||
attrs = %{revoked_at: DateTime.utc_now()}
|
||||
changeset = UserConsent.revoke_changeset(consent, attrs)
|
||||
assert changeset.valid?
|
||||
end
|
||||
|
||||
test "requires revoked_at", %{consent: consent} do
|
||||
changeset = UserConsent.revoke_changeset(consent, %{})
|
||||
refute changeset.valid?
|
||||
assert "can't be blank" in errors_on(changeset).revoked_at
|
||||
end
|
||||
|
||||
test "prevents revoking already revoked consent", %{consent: consent} do
|
||||
# Revoke once
|
||||
revoked_at = DateTime.utc_now()
|
||||
|
||||
{:ok, revoked_consent} =
|
||||
consent
|
||||
|> UserConsent.revoke_changeset(%{revoked_at: revoked_at})
|
||||
|> Repo.update()
|
||||
|
||||
# Try to revoke again
|
||||
changeset = UserConsent.revoke_changeset(revoked_consent, %{revoked_at: DateTime.utc_now()})
|
||||
refute changeset.valid?
|
||||
assert "consent already revoked" in errors_on(changeset).revoked_at
|
||||
end
|
||||
|
||||
test "successfully revokes consent", %{consent: consent} do
|
||||
revoked_at = DateTime.truncate(DateTime.utc_now(), :second)
|
||||
|
||||
changeset = UserConsent.revoke_changeset(consent, %{revoked_at: revoked_at})
|
||||
assert {:ok, updated_consent} = Repo.update(changeset)
|
||||
assert updated_consent.revoked_at == revoked_at
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
defmodule Towerops.Workers.AgentLatencyEvaluatorTest do
|
||||
use Towerops.DataCase, async: false
|
||||
use Oban.Testing, repo: Towerops.Repo
|
||||
|
||||
import Towerops.AccountsFixtures
|
||||
import Towerops.OrganizationsFixtures
|
||||
|
|
@ -10,6 +11,10 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do
|
|||
alias Towerops.Workers.AgentLatencyEvaluator
|
||||
|
||||
describe "perform/1" do
|
||||
test "returns :ok when no reassignment candidates exist" do
|
||||
assert :ok = perform_job(AgentLatencyEvaluator, %{})
|
||||
end
|
||||
|
||||
test "reassigns device to faster agent when 20%+ improvement available" do
|
||||
user = user_fixture()
|
||||
org = organization_fixture(user.id)
|
||||
|
|
@ -440,5 +445,153 @@ defmodule Towerops.Workers.AgentLatencyEvaluatorTest do
|
|||
assert updated_site1.agent_token_id == fast_agent.id
|
||||
assert updated_site2.agent_token_id == fast_agent.id
|
||||
end
|
||||
|
||||
test "broadcasts PubSub event when device is reassigned" do
|
||||
user = user_fixture()
|
||||
org = organization_fixture(user.id)
|
||||
{:ok, slow_agent, _} = Agents.create_agent_token(org.id, "Slow Agent")
|
||||
{:ok, fast_agent, _} = Agents.create_agent_token(org.id, "Fast Agent")
|
||||
|
||||
{:ok, site} =
|
||||
Sites.create_site(%{
|
||||
name: "Test Site",
|
||||
organization_id: org.id,
|
||||
agent_token_id: slow_agent.id
|
||||
})
|
||||
|
||||
{:ok, device} =
|
||||
Towerops.Devices.create_device(%{
|
||||
name: "Router",
|
||||
ip_address: "192.168.1.1",
|
||||
site_id: site.id,
|
||||
snmp_enabled: true,
|
||||
snmp_community: "public",
|
||||
snmp_version: "2c"
|
||||
})
|
||||
|
||||
# Create checks showing significant improvement
|
||||
for _ <- 1..15 do
|
||||
Monitoring.create_check(%{
|
||||
device_id: device.id,
|
||||
agent_token_id: slow_agent.id,
|
||||
status: :success,
|
||||
response_time_ms: 100,
|
||||
checked_at: DateTime.utc_now()
|
||||
})
|
||||
|
||||
Monitoring.create_check(%{
|
||||
device_id: device.id,
|
||||
agent_token_id: fast_agent.id,
|
||||
status: :success,
|
||||
response_time_ms: 50,
|
||||
checked_at: DateTime.utc_now()
|
||||
})
|
||||
end
|
||||
|
||||
# Subscribe to PubSub
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:latency")
|
||||
|
||||
# Trigger evaluation
|
||||
assert :ok = perform_job(AgentLatencyEvaluator, %{})
|
||||
|
||||
# Verify PubSub broadcast was sent
|
||||
assert_received {:device_reassigned, candidate}
|
||||
assert candidate.device_id == device.id
|
||||
assert candidate.best_agent_token_id == fast_agent.id
|
||||
assert candidate.current_agent_token_id == slow_agent.id
|
||||
assert candidate.improvement_percent >= 20
|
||||
end
|
||||
|
||||
test "does not broadcast when no reassignment occurs" do
|
||||
user = user_fixture()
|
||||
org = organization_fixture(user.id)
|
||||
{:ok, agent1, _} = Agents.create_agent_token(org.id, "Agent 1")
|
||||
|
||||
{:ok, site} =
|
||||
Sites.create_site(%{
|
||||
name: "Test Site",
|
||||
organization_id: org.id,
|
||||
agent_token_id: agent1.id
|
||||
})
|
||||
|
||||
{:ok, device} =
|
||||
Towerops.Devices.create_device(%{
|
||||
name: "Router",
|
||||
ip_address: "192.168.1.1",
|
||||
site_id: site.id,
|
||||
snmp_enabled: true,
|
||||
snmp_community: "public",
|
||||
snmp_version: "2c"
|
||||
})
|
||||
|
||||
# Create checks with only one agent (no alternative)
|
||||
for _ <- 1..15 do
|
||||
Monitoring.create_check(%{
|
||||
device_id: device.id,
|
||||
agent_token_id: agent1.id,
|
||||
status: :success,
|
||||
response_time_ms: 100,
|
||||
checked_at: DateTime.utc_now()
|
||||
})
|
||||
end
|
||||
|
||||
# Subscribe to PubSub
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:latency")
|
||||
|
||||
# Trigger evaluation
|
||||
assert :ok = perform_job(AgentLatencyEvaluator, %{})
|
||||
|
||||
# Verify no broadcast was sent
|
||||
refute_received {:device_reassigned, _}
|
||||
end
|
||||
|
||||
test "handles reassignment failures gracefully" do
|
||||
user = user_fixture()
|
||||
org = organization_fixture(user.id)
|
||||
{:ok, slow_agent, _} = Agents.create_agent_token(org.id, "Slow Agent")
|
||||
{:ok, fast_agent, _} = Agents.create_agent_token(org.id, "Fast Agent")
|
||||
|
||||
{:ok, site} =
|
||||
Sites.create_site(%{
|
||||
name: "Test Site",
|
||||
organization_id: org.id,
|
||||
agent_token_id: slow_agent.id
|
||||
})
|
||||
|
||||
{:ok, device} =
|
||||
Towerops.Devices.create_device(%{
|
||||
name: "Router",
|
||||
ip_address: "192.168.1.1",
|
||||
site_id: site.id,
|
||||
snmp_enabled: true,
|
||||
snmp_community: "public",
|
||||
snmp_version: "2c"
|
||||
})
|
||||
|
||||
# Create checks showing improvement
|
||||
for _ <- 1..15 do
|
||||
Monitoring.create_check(%{
|
||||
device_id: device.id,
|
||||
agent_token_id: slow_agent.id,
|
||||
status: :success,
|
||||
response_time_ms: 100,
|
||||
checked_at: DateTime.utc_now()
|
||||
})
|
||||
|
||||
Monitoring.create_check(%{
|
||||
device_id: device.id,
|
||||
agent_token_id: fast_agent.id,
|
||||
status: :success,
|
||||
response_time_ms: 50,
|
||||
checked_at: DateTime.utc_now()
|
||||
})
|
||||
end
|
||||
|
||||
# Delete the site to cause a failure during reassignment
|
||||
Sites.delete_site(site)
|
||||
|
||||
# Worker should complete successfully despite the error
|
||||
assert :ok = perform_job(AgentLatencyEvaluator, %{})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
defmodule Towerops.Workers.StaleAgentWorkerTest do
|
||||
use Towerops.DataCase, async: false
|
||||
use Oban.Testing, repo: Towerops.Repo
|
||||
|
||||
import Towerops.AccountsFixtures
|
||||
import Towerops.OrganizationsFixtures
|
||||
|
|
@ -8,6 +9,150 @@ defmodule Towerops.Workers.StaleAgentWorkerTest do
|
|||
alias Towerops.Agents.AgentToken
|
||||
alias Towerops.Workers.StaleAgentWorker
|
||||
|
||||
describe "perform/1" do
|
||||
setup do
|
||||
user = user_fixture()
|
||||
organization = organization_fixture(user.id)
|
||||
{:ok, organization: organization}
|
||||
end
|
||||
|
||||
test "returns :ok when no stale agents exist" do
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
end
|
||||
|
||||
test "returns :ok when all agents are fresh", %{organization: org} do
|
||||
{:ok, agent, _token} = Agents.create_agent_token(org.id, "Fresh Agent")
|
||||
|
||||
# Update heartbeat to now
|
||||
Agents.update_agent_token_heartbeat(agent.id, "192.168.1.1", %{})
|
||||
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
end
|
||||
|
||||
test "processes stale agents and broadcasts PubSub event", %{organization: org} do
|
||||
{:ok, agent, _token} = Agents.create_agent_token(org.id, "Stale Agent")
|
||||
|
||||
# Set last_seen_at to 15 minutes ago
|
||||
stale_time = DateTime.add(DateTime.utc_now(), -15, :minute)
|
||||
|
||||
Towerops.Repo.update_all(
|
||||
from(a in AgentToken, where: a.id == ^agent.id),
|
||||
set: [last_seen_at: stale_time]
|
||||
)
|
||||
|
||||
# Subscribe to PubSub to verify broadcast
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
|
||||
# Verify PubSub broadcast was sent
|
||||
assert_received {:agents_stale, stale_agents}
|
||||
assert length(stale_agents) == 1
|
||||
assert hd(stale_agents).id == agent.id
|
||||
end
|
||||
|
||||
test "broadcasts newly stale agents (10-15 minutes)", %{organization: org} do
|
||||
{:ok, agent, _token} = Agents.create_agent_token(org.id, "Newly Stale")
|
||||
|
||||
# Set last_seen_at to 12 minutes ago (within newly stale window)
|
||||
stale_time = DateTime.add(DateTime.utc_now(), -12, :minute)
|
||||
|
||||
Towerops.Repo.update_all(
|
||||
from(a in AgentToken, where: a.id == ^agent.id),
|
||||
set: [last_seen_at: stale_time]
|
||||
)
|
||||
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
|
||||
assert_received {:agents_stale, stale_agents}
|
||||
assert length(stale_agents) == 1
|
||||
assert hd(stale_agents).id == agent.id
|
||||
assert hd(stale_agents).organization_id == org.id
|
||||
end
|
||||
|
||||
test "broadcasts long-term stale agents (>15 minutes)", %{organization: org} do
|
||||
{:ok, agent, _token} = Agents.create_agent_token(org.id, "Long-term Stale")
|
||||
|
||||
# Set last_seen_at to 30 minutes ago
|
||||
stale_time = DateTime.add(DateTime.utc_now(), -30, :minute)
|
||||
|
||||
Towerops.Repo.update_all(
|
||||
from(a in AgentToken, where: a.id == ^agent.id),
|
||||
set: [last_seen_at: stale_time]
|
||||
)
|
||||
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
|
||||
assert_received {:agents_stale, stale_agents}
|
||||
assert length(stale_agents) == 1
|
||||
assert hd(stale_agents).id == agent.id
|
||||
end
|
||||
|
||||
test "handles mix of newly stale and long-term stale agents", %{organization: org} do
|
||||
{:ok, newly_stale, _} = Agents.create_agent_token(org.id, "Newly Stale")
|
||||
{:ok, long_term_stale, _} = Agents.create_agent_token(org.id, "Long-term Stale")
|
||||
|
||||
# Newly stale: 12 minutes ago
|
||||
newly_stale_time = DateTime.add(DateTime.utc_now(), -12, :minute)
|
||||
# Long-term stale: 20 minutes ago
|
||||
long_term_time = DateTime.add(DateTime.utc_now(), -20, :minute)
|
||||
|
||||
Towerops.Repo.update_all(
|
||||
from(a in AgentToken, where: a.id == ^newly_stale.id),
|
||||
set: [last_seen_at: newly_stale_time]
|
||||
)
|
||||
|
||||
Towerops.Repo.update_all(
|
||||
from(a in AgentToken, where: a.id == ^long_term_stale.id),
|
||||
set: [last_seen_at: long_term_time]
|
||||
)
|
||||
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
|
||||
# Verify both agents are included in PubSub broadcast
|
||||
assert_received {:agents_stale, stale_agents}
|
||||
assert length(stale_agents) == 2
|
||||
|
||||
stale_ids = Enum.map(stale_agents, & &1.id)
|
||||
assert newly_stale.id in stale_ids
|
||||
assert long_term_stale.id in stale_ids
|
||||
end
|
||||
|
||||
test "does not broadcast when no stale agents exist" do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
|
||||
refute_received {:agents_stale, _}
|
||||
end
|
||||
|
||||
test "preloads organization association for stale agents", %{organization: org} do
|
||||
{:ok, agent, _token} = Agents.create_agent_token(org.id, "Stale Agent")
|
||||
|
||||
stale_time = DateTime.add(DateTime.utc_now(), -15, :minute)
|
||||
|
||||
Towerops.Repo.update_all(
|
||||
from(a in AgentToken, where: a.id == ^agent.id),
|
||||
set: [last_seen_at: stale_time]
|
||||
)
|
||||
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
|
||||
assert :ok = perform_job(StaleAgentWorker, %{})
|
||||
|
||||
assert_received {:agents_stale, [stale_agent]}
|
||||
# Verify organization is preloaded
|
||||
assert %Ecto.Association.NotLoaded{} != stale_agent.organization
|
||||
assert stale_agent.organization.id == org.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "find_stale_agents/0" do
|
||||
setup do
|
||||
user = user_fixture()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue