- 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.
120 lines
3.3 KiB
Elixir
120 lines
3.3 KiB
Elixir
defmodule ToweropsWeb.Plugs.AgentAuthTest do
|
|
use ToweropsWeb.ConnCase, async: false
|
|
|
|
import Towerops.AccountsFixtures
|
|
|
|
alias Towerops.Agents
|
|
alias ToweropsWeb.Plugs.AgentAuth
|
|
|
|
setup %{conn: conn} do
|
|
user = user_fixture()
|
|
{:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
|
|
|
|
{:ok, agent_token, token_string} = Agents.create_agent_token(organization.id, "Test Agent")
|
|
|
|
# Set format to json for API endpoint
|
|
conn =
|
|
conn
|
|
|> Plug.Conn.fetch_query_params()
|
|
|> Phoenix.Controller.put_format("json")
|
|
|
|
%{conn: conn, organization: organization, agent_token: agent_token, token_string: token_string}
|
|
end
|
|
|
|
describe "init/1" do
|
|
test "returns options unchanged" do
|
|
opts = [some: :option]
|
|
assert AgentAuth.init(opts) == opts
|
|
end
|
|
end
|
|
|
|
describe "call/2" do
|
|
test "authenticates valid Bearer token", %{conn: conn, agent_token: agent_token, token_string: token_string} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("authorization", "Bearer #{token_string}")
|
|
|> AgentAuth.call([])
|
|
|
|
assert conn.assigns.current_agent_token.id == agent_token.id
|
|
refute conn.halted
|
|
end
|
|
|
|
test "rejects missing authorization header", %{conn: conn} do
|
|
conn = AgentAuth.call(conn, [])
|
|
|
|
assert conn.status == 401
|
|
assert conn.halted
|
|
end
|
|
|
|
test "rejects invalid Bearer token format", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("authorization", "InvalidFormat token123")
|
|
|> AgentAuth.call([])
|
|
|
|
assert conn.status == 401
|
|
assert conn.halted
|
|
end
|
|
|
|
test "rejects malformed Bearer token", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("authorization", "Bearer")
|
|
|> AgentAuth.call([])
|
|
|
|
assert conn.status == 401
|
|
assert conn.halted
|
|
end
|
|
|
|
test "rejects invalid token value", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("authorization", "Bearer invalid_token_value")
|
|
|> AgentAuth.call([])
|
|
|
|
assert conn.status == 401
|
|
assert conn.halted
|
|
end
|
|
|
|
test "updates agent token heartbeat", %{
|
|
conn: conn,
|
|
agent_token: agent_token,
|
|
token_string: token_string
|
|
} do
|
|
# Get initial last_seen_at
|
|
initial_agent_token = Agents.get_agent_token!(agent_token.id)
|
|
initial_last_seen = initial_agent_token.last_seen_at
|
|
|
|
conn =
|
|
conn
|
|
|> put_req_header("authorization", "Bearer #{token_string}")
|
|
|> AgentAuth.call([])
|
|
|
|
# In test environment, heartbeat update is synchronous
|
|
# Verify heartbeat was updated
|
|
updated_agent_token = Agents.get_agent_token!(agent_token.id)
|
|
|
|
if initial_last_seen do
|
|
assert DateTime.compare(updated_agent_token.last_seen_at, initial_last_seen) in [:gt, :eq]
|
|
else
|
|
assert updated_agent_token.last_seen_at
|
|
end
|
|
|
|
assert updated_agent_token.last_ip == "127.0.0.1"
|
|
refute conn.halted
|
|
end
|
|
|
|
test "handles token verification error gracefully", %{conn: conn} do
|
|
# Use a token that looks valid but doesn't exist
|
|
fake_token = String.duplicate("a", 32)
|
|
|
|
conn =
|
|
conn
|
|
|> put_req_header("authorization", "Bearer #{fake_token}")
|
|
|> AgentAuth.call([])
|
|
|
|
assert conn.status == 401
|
|
assert conn.halted
|
|
end
|
|
end
|
|
end
|