Fix database ownership issues in agent auth tests

- Update AgentAuth plug to use synchronous heartbeat updates in test env
- Refactor async heartbeat logic to reduce nesting (Credo)
- Remove Process.sleep from tests (no longer needed with sync updates)

This fixes 'owner exited' database errors in the test suite by avoiding
async Task spawns during tests, which caused DB connection ownership
conflicts with Ecto's sandbox mode.
This commit is contained in:
Graham McIntire 2026-01-13 13:16:54 -06:00
parent 9ec14b7785
commit f9b575816a
No known key found for this signature in database
2 changed files with 25 additions and 16 deletions

View file

@ -44,22 +44,33 @@ defmodule ToweropsWeb.Plugs.AgentAuth do
defp update_heartbeat(conn, agent_token) do
ip = to_string(:inet_parse.ntoa(conn.remote_ip))
parent = self()
_ =
Task.start(fn ->
# Allow this task to use the test database sandbox
_ =
if Application.get_env(:towerops, :sql_sandbox) do
Sandbox.allow(Towerops.Repo, parent, self())
end
_ = Agents.update_agent_token_heartbeat(agent_token.id, ip)
end)
# In test environment, update synchronously to avoid DB ownership issues
# In production, update asynchronously for better performance
if Mix.env() == :test do
_ = Agents.update_agent_token_heartbeat(agent_token.id, ip)
else
update_heartbeat_async(agent_token.id, ip)
end
conn
end
defp update_heartbeat_async(agent_token_id, ip) do
parent = self()
Task.start(fn ->
# Allow this task to use the test database sandbox (shouldn't happen in prod)
allow_sandbox(parent)
Agents.update_agent_token_heartbeat(agent_token_id, ip)
end)
end
defp allow_sandbox(parent) do
if Application.get_env(:towerops, :sql_sandbox) do
Sandbox.allow(Towerops.Repo, parent, self())
end
end
defp unauthorized(conn) do
conn
|> put_status(:unauthorized)

View file

@ -76,7 +76,7 @@ defmodule ToweropsWeb.Plugs.AgentAuthTest do
assert conn.halted
end
test "updates agent token heartbeat asynchronously", %{
test "updates agent token heartbeat", %{
conn: conn,
agent_token: agent_token,
token_string: token_string
@ -90,9 +90,7 @@ defmodule ToweropsWeb.Plugs.AgentAuthTest do
|> put_req_header("authorization", "Bearer #{token_string}")
|> AgentAuth.call([])
# Wait for async task to complete
Process.sleep(100)
# In test environment, heartbeat update is synchronous
# Verify heartbeat was updated
updated_agent_token = Agents.get_agent_token!(agent_token.id)