test/openagents_web/controllers/box_fanout_controller_test.exs

main at 58e6347eeb72 · 3 KB

defmodule OpenAgentsWeb.BoxFanoutControllerTest do
  use OpenAgentsWeb.ConnCase, async: false

  alias OpenAgents.Conversations

  setup {Req.Test, :verify_on_exit!}

  setup do
    original_api = Application.get_env(:openagents, :box_api)
    original_key = Application.get_env(:openagents, :box_api_key)

    Application.put_env(
      :openagents,
      :box_api,
      Keyword.merge(original_api || [],
        base_url: "https://box-api.internal",
        poll_interval_ms: 0,
        poll_attempts: 1,
        request_options: [plug: {Req.Test, __MODULE__}, retry_delay: 0]
      )
    )

    Application.put_env(:openagents, :box_api_key, "box-api-fanout-controller-test")

    on_exit(fn ->
      restore_env(:box_api, original_api)
      restore_env(:box_api_key, original_key)
    end)

    :ok
  end

  test "returns a durable admission plan with labels and queue reasons", %{conn: conn} do
    user = github_user("api-token-box-fanout-controller")
    {:ok, conversation} = Conversations.ensure_conversation(user)
    counter = start_supervised!({Agent, fn -> 0 end})
    box_ids = ["bx_ct7xxxxx", "bx_ct7xxxyy"]

    Req.Test.stub(__MODULE__, fn request ->
      case request.method do
        "POST" ->
          number = Agent.get_and_update(counter, fn value -> {value + 1, value + 1} end)
          Req.Test.json(request, box_body(Enum.at(box_ids, number - 1)))

        "PATCH" ->
          box_id = request.request_path |> String.split("/") |> List.last()
          Req.Test.json(request, box_body(box_id))

        "GET" ->
          box_id = request.request_path |> String.split("/") |> List.last()
          Req.Test.json(request, box_body(box_id))
      end
    end)

    response =
      conn
      |> put_box_api_token("box-fanout-controller")
      |> post("/api/v1/conversations/#{conversation.id}/boxes/fanout", %{
        "count" => 3,
        "labels" => ["left", "middle", "right"]
      })
      |> json_response(202)

    assert response["plan"]["requested_count"] == 3
    assert length(response["plan"]["admitted"]) == 2
    assert Enum.all?(response["plan"]["admitted"], &is_binary(&1["box_id"]))

    assert [%{"label" => "right", "queue_reason" => "conversation_active_limit"}] =
             response["plan"]["queued"]
  end

  test "a foreign conversation is indistinguishable from a missing one", %{conn: conn} do
    owner = github_user("box-fanout-foreign-owner")
    foreign = github_user("box-fanout-foreign-account")
    {:ok, conversation} = Conversations.ensure_conversation(owner)

    Req.Test.stub(__MODULE__, fn _request ->
      flunk("foreign conversation must not contact the provider")
    end)

    response =
      conn
      |> put_box_api_token("box-fanout-foreign-account")
      |> post("/api/v1/conversations/#{conversation.id}/boxes/fanout", %{"count" => 1})
      |> json_response(404)

    assert response == %{"error" => %{"code" => "conversation_not_found"}}
    assert foreign.id != owner.id
  end

  defp box_body(box_id) do
    %{
      "box" => %{
        "id" => box_id,
        "state" => "ready",
        "setupStatus" => "done",
        "name" => OpenAgents.Box.provider_ownership_marker()
      }
    }
  end

  defp restore_env(key, nil), do: Application.delete_env(:openagents, key)
  defp restore_env(key, value), do: Application.put_env(:openagents, key, value)
end