defmodule MicrowavepropWeb.AgentSkillsControllerTest do use MicrowavepropWeb.ConnCase, async: true describe "GET /.well-known/agent-skills/index.json" do test "returns the agent-skills discovery index", %{conn: conn} do conn = get(conn, "/.well-known/agent-skills/index.json") assert conn.status == 200 assert ["application/json" <> _] = get_resp_header(conn, "content-type") body = Jason.decode!(conn.resp_body) assert body["$schema"] =~ "agentskills" assert body["skills"] != [] for skill <- body["skills"] do assert byte_size(skill["name"]) > 0 assert byte_size(skill["type"]) > 0 assert byte_size(skill["description"]) > 0 assert byte_size(skill["url"]) > 0 assert String.match?(skill["sha256"], ~r/^[0-9a-f]{64}$/) end end test "index lists at least fetch-contacts and read-algorithm", %{conn: conn} do conn = get(conn, "/.well-known/agent-skills/index.json") %{"skills" => skills} = Jason.decode!(conn.resp_body) names = Enum.map(skills, & &1["name"]) assert "fetch-contacts" in names assert "read-algorithm" in names end end describe "GET /.well-known/agent-skills/:name/SKILL.md" do test "serves a skill document as markdown", %{conn: conn} do conn = get(conn, "/.well-known/agent-skills/fetch-contacts/SKILL.md") assert conn.status == 200 assert ["text/markdown; charset=utf-8"] = get_resp_header(conn, "content-type") assert conn.resp_body =~ "Fetch contacts dataset" end test "sha256 in the index matches the served document bytes", %{conn: conn} do %{"skills" => skills} = conn |> get("/.well-known/agent-skills/index.json") |> Map.get(:resp_body) |> Jason.decode!() for %{"name" => name, "sha256" => expected} <- skills do doc = get(conn, "/.well-known/agent-skills/#{name}/SKILL.md").resp_body actual = :sha256 |> :crypto.hash(doc) |> Base.encode16(case: :lower) assert actual == expected, "sha256 mismatch for skill #{name}" end end test "returns 404 for unknown skill names", %{conn: conn} do conn = get(conn, "/.well-known/agent-skills/does-not-exist/SKILL.md") assert conn.status == 404 end end end