test/openagents_web/controllers/api_extension_controller_test.exs

main at 58e6347eeb72 · 2 KB

defmodule OpenAgentsWeb.ApiExtensionControllerTest do
  use OpenAgentsWeb.ConnCase, async: true

  test "GET /api/v1 lists the issue extension fields an agent can rely on", %{conn: conn} do
    conn = get(conn, ~p"/api/v1")

    assert %{
             "api_version" => "v1",
             "extensions" => %{
               "issue.openagents" => %{
                 "version" => _version,
                 "fields" => fields,
                 "filters" => %{"blocked" => _filter},
                 "endpoints" => endpoints
               }
             }
           } = json_response(conn, 200)

    assert %{"blocked" => %{"type" => "boolean"}} = fields
    assert %{"blocked_by" => %{"type" => "array"}} = fields
    assert %{"blocks" => %{"type" => "array"}} = fields
    assert Enum.any?(endpoints, &String.contains?(&1, "/dependencies"))
  end

  test "GET /api/v1 publishes one route entry for every live API v1 route", %{conn: conn} do
    published =
      conn
      |> get(~p"/api/v1")
      |> json_response(200)
      |> Map.fetch!("routes")

    live =
      OpenAgentsWeb.Router.__routes__()
      |> Enum.filter(&String.starts_with?(&1.path, "/api/v1"))
      |> Enum.map(fn route ->
        {String.upcase(Atom.to_string(route.verb)),
         Regex.replace(~r/:([a-z_]+)/, route.path, fn _whole, segment -> "{#{segment}}" end)}
      end)
      |> MapSet.new()

    assert MapSet.new(published, &{&1["method"], &1["path"]}) == live
  end

  test "every published route names its authority, family, and error contract", %{conn: conn} do
    published =
      conn
      |> get(~p"/api/v1")
      |> json_response(200)
      |> Map.fetch!("routes")

    for route <- published do
      assert route["authority"] in ~w(anonymous optional_bearer required_bearer),
             "#{route["method"]} #{route["path"]} has no authority classification"

      assert route["errors"] in ~w(envelope legacy),
             "#{route["method"]} #{route["path"]} has no error contract classification"

      assert is_binary(route["family"]) and route["family"] != ""
      assert is_boolean(route["mutation"])
    end
  end

  test "GET /api/v1 publishes the error envelope and its stable codes", %{conn: conn} do
    body = conn |> get(~p"/api/v1") |> json_response(200)

    assert body["errors"]["envelope"] == OpenAgentsWeb.ApiError.envelope_keys()

    assert body["errors"]["stable_codes"] ==
             Map.new(OpenAgentsWeb.ApiError.codes(), fn {code, status} -> {code, status} end)

    assert body["errors"]["stable_codes"]["not_found"] == 404
    assert is_binary(body["errors"]["field_errors"])
  end

  test "GET /api/v1 names every family the router serves", %{conn: conn} do
    body = conn |> get(~p"/api/v1") |> json_response(200)

    published = MapSet.new(body["routes"], & &1["family"])

    assert MapSet.new(body["families"]) == published
    assert "issue" in body["families"]
    assert "project" in body["families"]
  end
end