defmodule ToweropsWeb.AgentLiveTest do use ToweropsWeb.ConnCase import Ecto.Query import Phoenix.LiveViewTest alias Towerops.Agents setup :register_and_log_in_user setup %{user: user} do {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id) %{organization: organization} end describe "Index" do test "lists all agent tokens", %{conn: conn, organization: organization} do {:ok, _agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1") {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents") assert html =~ "Remote Agents" assert html =~ "Agent 1" end test "displays empty state when no agents", %{conn: conn, organization: organization} do {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents") assert html =~ "No agents" assert html =~ "Get started by creating your first remote agent" end test "creates new agent and shows token modal", %{conn: conn, organization: organization} do {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents") html = view |> form("#new-agent-form form", %{name: "Test Agent"}) |> render_submit() assert html =~ "Agent Created Successfully" assert html =~ "Test Agent" assert html =~ "Copy this token now" end test "revokes agent", %{conn: conn, organization: organization} do {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1") {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents") html = view |> element("button", "Revoke") |> render_click() assert html =~ "Revoked" # Verify agent was actually revoked updated_token = Towerops.Repo.get!(Agents.AgentToken, agent_token.id) refute updated_token.enabled end test "closes token modal", %{conn: conn, organization: organization} do {:ok, view, _html} = live(conn, ~p"/orgs/#{organization.slug}/agents") # Create agent to show modal view |> form("#new-agent-form form", %{name: "Test Agent"}) |> render_submit() # Close modal html = view |> element("button", "I've Saved the Token") |> render_click() refute html =~ "Agent Created Successfully" end test "requires authentication", %{organization: organization} do conn = build_conn() {:error, redirect} = live(conn, ~p"/orgs/#{organization.slug}/agents") assert {:redirect, %{to: path}} = redirect assert path == ~p"/users/log-in" end test "displays agent with warning status", %{conn: conn, organization: organization} do {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1") # Update last_seen_at to 3 minutes ago (warning status) three_minutes_ago = DateTime.add(DateTime.utc_now(), -180, :second) Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1") Towerops.Repo.update_all( from(t in Agents.AgentToken, where: t.id == ^agent_token.id), set: [last_seen_at: three_minutes_ago] ) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents") assert html =~ "Warning" assert html =~ "3m ago" end test "displays agent with offline status", %{conn: conn, organization: organization} do {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1") # Update last_seen_at to 10 minutes ago (offline status) ten_minutes_ago = DateTime.add(DateTime.utc_now(), -600, :second) Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1") Towerops.Repo.update_all( from(t in Agents.AgentToken, where: t.id == ^agent_token.id), set: [last_seen_at: ten_minutes_ago] ) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents") assert html =~ "Offline" assert html =~ "10m ago" end test "displays agent last seen time in hours", %{conn: conn, organization: organization} do {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1") # Update last_seen_at to 2 hours ago two_hours_ago = DateTime.add(DateTime.utc_now(), -7200, :second) Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1") Towerops.Repo.update_all( from(t in Agents.AgentToken, where: t.id == ^agent_token.id), set: [last_seen_at: two_hours_ago] ) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents") assert html =~ "2h ago" end test "displays agent last seen time in days", %{conn: conn, organization: organization} do {:ok, agent_token, _token} = Agents.create_agent_token(organization.id, "Agent 1") # Update last_seen_at to 2 days ago two_days_ago = DateTime.add(DateTime.utc_now(), -172_800, :second) Agents.update_agent_token_heartbeat(agent_token.id, "127.0.0.1") Towerops.Repo.update_all( from(t in Agents.AgentToken, where: t.id == ^agent_token.id), set: [last_seen_at: two_days_ago] ) {:ok, _view, html} = live(conn, ~p"/orgs/#{organization.slug}/agents") assert html =~ "2d ago" end end end