diff --git a/lib/pleroma/gun/conn.ex b/lib/pleroma/gun/conn.ex index 9e5c2b184..906607b28 100644 --- a/lib/pleroma/gun/conn.ex +++ b/lib/pleroma/gun/conn.ex @@ -6,17 +6,24 @@ defmodule Pleroma.Gun.Conn do @moduledoc """ Struct for gun connection data """ + @type gun_state :: :open | :up | :down + @type conn_state :: :init | :active | :idle + @type t :: %__MODULE__{ conn: pid(), - state: atom(), + gun_state: gun_state(), waiting_pids: [pid()], + conn_state: conn_state(), + used_by: [pid()], last_reference: pos_integer(), crf: float() } defstruct conn: nil, - state: :open, + gun_state: :open, waiting_pids: [], + conn_state: :init, + used_by: [], last_reference: :os.system_time(:second), crf: 1 end diff --git a/lib/pleroma/gun/connections.ex b/lib/pleroma/gun/connections.ex index 73d54e94d..e3d392de7 100644 --- a/lib/pleroma/gun/connections.ex +++ b/lib/pleroma/gun/connections.ex @@ -14,7 +14,7 @@ defmodule Pleroma.Gun.Connections do opts: keyword() } - defstruct conns: %{}, opts: [] + defstruct conns: %{}, opts: [], queue: [] alias Pleroma.Gun.API alias Pleroma.Gun.Conn @@ -27,8 +27,8 @@ defmodule Pleroma.Gun.Connections do @impl true def init(opts), do: {:ok, %__MODULE__{conns: %{}, opts: opts}} - @spec get_conn(String.t(), keyword(), atom()) :: pid() - def get_conn(url, opts \\ [], name \\ :default) do + @spec checkin(String.t(), keyword(), atom()) :: pid() + def checkin(url, opts \\ [], name \\ :default) do opts = Enum.into(opts, %{}) uri = URI.parse(url) @@ -53,7 +53,7 @@ defmodule Pleroma.Gun.Connections do GenServer.call( name, - {:conn, %{opts: opts, uri: uri}} + {:checkin, %{opts: opts, uri: uri}} ) end @@ -68,28 +68,57 @@ defmodule Pleroma.Gun.Connections do GenServer.call(name, {:state}) end + def checkout(conn, pid, name \\ :default) do + GenServer.cast(name, {:checkout, conn, pid}) + end + + def process_queue(name \\ :default) do + GenServer.cast(name, {:process_queue}) + end + @impl true - def handle_call({:conn, %{opts: opts, uri: uri}}, from, state) do + def handle_cast({:checkout, conn_pid, pid}, state) do + {key, conn} = find_conn(state.conns, conn_pid) + used_by = List.keydelete(conn.used_by, pid, 0) + conn_state = if used_by == [], do: :idle, else: conn.conn_state + state = put_in(state.conns[key], %{conn | conn_state: conn_state, used_by: used_by}) + {:noreply, state} + end + + @impl true + def handle_cast({:process_queue}, state) do + case state.queue do + [{from, key, uri, opts} | _queue] -> + try_to_checkin(key, uri, from, state, Map.put(opts, :from_cast, true)) + + [] -> + {:noreply, state} + end + end + + @impl true + def handle_call({:checkin, %{opts: opts, uri: uri}}, from, state) do key = compose_key(uri) case state.conns[key] do - %{conn: conn, state: conn_state, last_reference: reference, crf: last_crf} = current_conn - when conn_state == :up -> + %{conn: conn, gun_state: gun_state} = current_conn when gun_state == :up -> time = current_time() - last_reference = time - reference + last_reference = time - current_conn.last_reference - current_crf = crf(last_reference, 100, last_crf) + current_crf = crf(last_reference, 100, current_conn.crf) state = put_in(state.conns[key], %{ current_conn | last_reference: time, - crf: current_crf + crf: current_crf, + conn_state: :active, + used_by: [from | current_conn.used_by] }) {:reply, conn, state} - %{state: conn_state, waiting_pids: pids} when conn_state in [:open, :down] -> + %{gun_state: gun_state, waiting_pids: pids} when gun_state in [:open, :down] -> state = put_in(state.conns[key].waiting_pids, [from | pids]) {:noreply, state} @@ -99,22 +128,7 @@ defmodule Pleroma.Gun.Connections do if Enum.count(state.conns) < max_connections do open_conn(key, uri, from, state, opts) else - [{close_key, least_used} | _conns] = - state.conns - |> Enum.filter(fn {_k, v} -> v.waiting_pids == [] end) - |> Enum.sort(fn {_x_k, x}, {_y_k, y} -> - x.crf < y.crf and x.last_reference < y.last_reference - end) - - :ok = API.close(least_used.conn) - - state = - put_in( - state.conns, - Map.delete(state.conns, close_key) - ) - - open_conn(key, uri, from, state, opts) + try_to_checkin(key, uri, from, state, opts) end end end @@ -122,14 +136,44 @@ defmodule Pleroma.Gun.Connections do @impl true def handle_call({:state}, _from, state), do: {:reply, state, state} + defp try_to_checkin(key, uri, from, state, opts) do + unused_conns = + state.conns + |> Enum.filter(fn {_k, v} -> + v.conn_state == :idle and v.waiting_pids == [] and v.used_by == [] + end) + |> Enum.sort(fn {_x_k, x}, {_y_k, y} -> + x.crf < y.crf and x.last_reference < y.last_reference + end) + + case unused_conns do + [{close_key, least_used} | _conns] -> + :ok = API.close(least_used.conn) + + state = + put_in( + state.conns, + Map.delete(state.conns, close_key) + ) + + open_conn(key, uri, from, state, opts) + + [] -> + queue = + if List.keymember?(state.queue, from, 0), + do: state.queue, + else: state.queue ++ [{from, key, uri, opts}] + + state = put_in(state.queue, queue) + {:noreply, state} + end + end + @impl true def handle_info({:gun_up, conn_pid, _protocol}, state) do conn_key = compose_key_gun_info(conn_pid) {key, conn} = find_conn(state.conns, conn_pid, conn_key) - # Send to all waiting processes connection pid - Enum.each(conn.waiting_pids, fn waiting_pid -> GenServer.reply(waiting_pid, conn_pid) end) - # Update state of the current connection and set waiting_pids to empty list time = current_time() last_reference = time - conn.last_reference @@ -138,12 +182,17 @@ defmodule Pleroma.Gun.Connections do state = put_in(state.conns[key], %{ conn - | state: :up, + | gun_state: :up, waiting_pids: [], last_reference: time, - crf: current_crf + crf: current_crf, + conn_state: :active, + used_by: conn.waiting_pids ++ conn.used_by }) + # Send to all waiting processes connection pid + Enum.each(conn.waiting_pids, fn waiting_pid -> GenServer.reply(waiting_pid, conn_pid) end) + {:noreply, state} end @@ -154,7 +203,7 @@ defmodule Pleroma.Gun.Connections do Enum.each(conn.waiting_pids, fn waiting_pid -> GenServer.reply(waiting_pid, nil) end) - state = put_in(state.conns[key].state, :down) + state = put_in(state.conns[key].gun_state, :down) {:noreply, state} end @@ -177,7 +226,7 @@ defmodule Pleroma.Gun.Connections do end) end - defp open_conn(key, uri, _from, state, %{proxy: {proxy_host, proxy_port}} = opts) do + defp open_conn(key, uri, from, state, %{proxy: {proxy_host, proxy_port}} = opts) do host = to_charlist(uri.host) port = uri.port @@ -202,9 +251,15 @@ defmodule Pleroma.Gun.Connections do put_in(state.conns[key], %Conn{ conn: conn, waiting_pids: [], - state: :up + gun_state: :up, + conn_state: :active, + used_by: [from] }) + if opts[:from_cast] do + GenServer.reply(from, conn) + end + {:reply, conn, state} else error -> @@ -218,6 +273,13 @@ defmodule Pleroma.Gun.Connections do port = uri.port with {:ok, conn} <- API.open(host, port, opts) do + state = + if opts[:from_cast] do + put_in(state.queue, List.keydelete(state.queue, from, 0)) + else + state + end + state = put_in(state.conns[key], %Conn{ conn: conn, diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex index 39c0fff43..d4e6d0f99 100644 --- a/lib/pleroma/http/connection.ex +++ b/lib/pleroma/http/connection.ex @@ -10,8 +10,7 @@ defmodule Pleroma.HTTP.Connection do @options [ connect_timeout: 10_000, timeout: 20_000, - pool: :federation, - version: :master + pool: :federation ] require Logger @@ -61,7 +60,7 @@ defmodule Pleroma.HTTP.Connection do end defp get_conn_for_gun(url, options, pool) do - case Pleroma.Gun.Connections.get_conn(url, options, pool) do + case Pleroma.Gun.Connections.checkin(url, options, pool) do nil -> options diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex index 5c0d66955..0a7db737f 100644 --- a/lib/pleroma/http/http.ex +++ b/lib/pleroma/http/http.ex @@ -45,15 +45,27 @@ defmodule Pleroma.HTTP do params = Keyword.get(options, :params, []) - %{} - |> Builder.method(method) - |> Builder.url(url) - |> Builder.headers(headers) - |> Builder.opts(options) - |> Builder.add_param(:body, :body, body) - |> Builder.add_param(:query, :query, params) - |> Enum.into([]) - |> (&Tesla.request(Connection.new(options), &1)).() + request = + %{} + |> Builder.method(method) + |> Builder.url(url) + |> Builder.headers(headers) + |> Builder.opts(options) + |> Builder.add_param(:body, :body, body) + |> Builder.add_param(:query, :query, params) + |> Enum.into([]) + + client = Connection.new(options) + response = Tesla.request(client, request) + + if adapter_gun? do + %{adapter: {_, _, [adapter_options]}} = client + pool = adapter_options[:pool] + Pleroma.Gun.Connections.checkout(adapter_options[:conn], self(), pool) + Pleroma.Gun.Connections.process_queue(pool) + end + + response rescue e -> {:error, e} diff --git a/test/gun/connections_test.exs b/test/gun/connections_test.exs index cc3675ad9..39f77070a 100644 --- a/test/gun/connections_test.exs +++ b/test/gun/connections_test.exs @@ -34,12 +34,26 @@ defmodule Gun.ConnectionsTest do end test "opens connection and reuse it on next request", %{name: name, pid: pid} do - conn = Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name) + conn = Connections.checkin("http://some-domain.com", [genserver_pid: pid], name) assert is_pid(conn) assert Process.alive?(conn) - reused_conn = Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name) + self = self() + + %Connections{ + conns: %{ + "http:some-domain.com:80" => %Conn{ + conn: ^conn, + gun_state: :up, + waiting_pids: [], + used_by: [{^self, _}], + conn_state: :active + } + } + } = Connections.get_state(name) + + reused_conn = Connections.checkin("http://some-domain.com", [genserver_pid: pid], name) assert conn == reused_conn @@ -47,23 +61,53 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:some-domain.com:80" => %Conn{ conn: ^conn, - state: :up, - waiting_pids: [] + gun_state: :up, + waiting_pids: [], + used_by: [{^self, _}, {^self, _}], + conn_state: :active + } + } + } = Connections.get_state(name) + + :ok = Connections.checkout(conn, self, name) + + %Connections{ + conns: %{ + "http:some-domain.com:80" => %Conn{ + conn: ^conn, + gun_state: :up, + waiting_pids: [], + used_by: [{^self, _}], + conn_state: :active + } + } + } = Connections.get_state(name) + + :ok = Connections.checkout(conn, self, name) + + %Connections{ + conns: %{ + "http:some-domain.com:80" => %Conn{ + conn: ^conn, + gun_state: :up, + waiting_pids: [], + used_by: [], + conn_state: :idle } } } = Connections.get_state(name) end test "reuses connection based on protocol", %{name: name, pid: pid} do - conn = Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name) + conn = Connections.checkin("http://some-domain.com", [genserver_pid: pid], name) assert is_pid(conn) assert Process.alive?(conn) - https_conn = Connections.get_conn("https://some-domain.com", [genserver_pid: pid], name) + https_conn = Connections.checkin("https://some-domain.com", [genserver_pid: pid], name) refute conn == https_conn - reused_https = Connections.get_conn("https://some-domain.com", [genserver_pid: pid], name) + reused_https = Connections.checkin("https://some-domain.com", [genserver_pid: pid], name) refute conn == reused_https @@ -73,12 +117,12 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:some-domain.com:80" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] }, "https:some-domain.com:443" => %Conn{ conn: ^https_conn, - state: :up, + gun_state: :up, waiting_pids: [] } } @@ -86,7 +130,7 @@ defmodule Gun.ConnectionsTest do end test "process gun_down message", %{name: name, pid: pid} do - conn = Connections.get_conn("http://gun_down.com", [genserver_pid: pid], name) + conn = Connections.checkin("http://gun_down.com", [genserver_pid: pid], name) refute conn @@ -94,7 +138,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:gun_down.com:80" => %Conn{ conn: _, - state: :down, + gun_state: :down, waiting_pids: _ } } @@ -102,7 +146,7 @@ defmodule Gun.ConnectionsTest do end test "process gun_down message and then gun_up", %{name: name, pid: pid} do - conn = Connections.get_conn("http://gun_down_and_up.com", [genserver_pid: pid], name) + conn = Connections.checkin("http://gun_down_and_up.com", [genserver_pid: pid], name) refute conn @@ -110,13 +154,13 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:gun_down_and_up.com:80" => %Conn{ conn: _, - state: :down, + gun_state: :down, waiting_pids: _ } } } = Connections.get_state(name) - conn = Connections.get_conn("http://gun_down_and_up.com", [genserver_pid: pid], name) + conn = Connections.checkin("http://gun_down_and_up.com", [genserver_pid: pid], name) assert is_pid(conn) assert Process.alive?(conn) @@ -125,7 +169,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:gun_down_and_up.com:80" => %Conn{ conn: _, - state: :up, + gun_state: :up, waiting_pids: [] } } @@ -136,7 +180,7 @@ defmodule Gun.ConnectionsTest do tasks = for _ <- 1..5 do Task.async(fn -> - Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name) + Connections.checkin("http://some-domain.com", [genserver_pid: pid], name) end) end @@ -153,7 +197,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:some-domain.com:80" => %Conn{ conn: conn, - state: :up, + gun_state: :up, waiting_pids: [] } } @@ -162,41 +206,49 @@ defmodule Gun.ConnectionsTest do assert Enum.all?(conns, fn res -> res == conn end) end - test "remove frequently used", %{name: name, pid: pid} do - Connections.get_conn("https://some-domain.com", [genserver_pid: pid], name) + test "remove frequently used and idle", %{name: name, pid: pid} do + self = self() + conn1 = Connections.checkin("https://some-domain.com", [genserver_pid: pid], name) - for _ <- 1..4 do - Connections.get_conn("http://some-domain.com", [genserver_pid: pid], name) - end + [conn2 | _conns] = + for _ <- 1..4 do + Connections.checkin("http://some-domain.com", [genserver_pid: pid], name) + end %Connections{ conns: %{ "http:some-domain.com:80" => %Conn{ - conn: _, - state: :up, - waiting_pids: [] + conn: ^conn2, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}, {^self, _}, {^self, _}, {^self, _}] }, "https:some-domain.com:443" => %Conn{ - conn: _, - state: :up, - waiting_pids: [] + conn: ^conn1, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}] } }, opts: [max_connections: 2, timeout: 10] } = Connections.get_state(name) - conn = Connections.get_conn("http://another-domain.com", [genserver_pid: pid], name) + :ok = Connections.checkout(conn1, self, name) + + conn = Connections.checkin("http://another-domain.com", [genserver_pid: pid], name) %Connections{ conns: %{ "http:another-domain.com:80" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] }, "http:some-domain.com:80" => %Conn{ conn: _, - state: :up, + gun_state: :up, waiting_pids: [] } }, @@ -211,12 +263,12 @@ defmodule Gun.ConnectionsTest do api = Pleroma.Config.get([API]) Pleroma.Config.put([API], API.Gun) on_exit(fn -> Pleroma.Config.put([API], api) end) - conn = Connections.get_conn("http://httpbin.org", [], name) + conn = Connections.checkin("http://httpbin.org", [], name) assert is_pid(conn) assert Process.alive?(conn) - reused_conn = Connections.get_conn("http://httpbin.org", [], name) + reused_conn = Connections.checkin("http://httpbin.org", [], name) assert conn == reused_conn @@ -224,7 +276,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:httpbin.org:80" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] } } @@ -235,12 +287,12 @@ defmodule Gun.ConnectionsTest do api = Pleroma.Config.get([API]) Pleroma.Config.put([API], API.Gun) on_exit(fn -> Pleroma.Config.put([API], api) end) - conn = Connections.get_conn("https://httpbin.org", [], name) + conn = Connections.checkin("https://httpbin.org", [], name) assert is_pid(conn) assert Process.alive?(conn) - reused_conn = Connections.get_conn("https://httpbin.org", [], name) + reused_conn = Connections.checkin("https://httpbin.org", [], name) assert conn == reused_conn @@ -248,52 +300,54 @@ defmodule Gun.ConnectionsTest do conns: %{ "https:httpbin.org:443" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] } } } = Connections.get_state(name) end - test "remove frequently used", %{name: name, pid: pid} do + test "remove frequently used and idle", %{name: name, pid: pid} do + self = self() api = Pleroma.Config.get([API]) Pleroma.Config.put([API], API.Gun) on_exit(fn -> Pleroma.Config.put([API], api) end) - Connections.get_conn("https://www.google.com", [genserver_pid: pid], name) + conn = Connections.checkin("https://www.google.com", [genserver_pid: pid], name) for _ <- 1..4 do - Connections.get_conn("https://httpbin.org", [genserver_pid: pid], name) + Connections.checkin("https://httpbin.org", [genserver_pid: pid], name) end %Connections{ conns: %{ "https:httpbin.org:443" => %Conn{ conn: _, - state: :up, + gun_state: :up, waiting_pids: [] }, "https:www.google.com:443" => %Conn{ conn: _, - state: :up, + gun_state: :up, waiting_pids: [] } }, opts: [max_connections: 2, timeout: 10] } = Connections.get_state(name) - conn = Connections.get_conn("http://httpbin.org", [genserver_pid: pid], name) + :ok = Connections.checkout(conn, self, name) + conn = Connections.checkin("http://httpbin.org", [genserver_pid: pid], name) %Connections{ conns: %{ "http:httpbin.org:80" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] }, "https:httpbin.org:443" => %Conn{ conn: _, - state: :up, + gun_state: :up, waiting_pids: [] } }, @@ -301,59 +355,173 @@ defmodule Gun.ConnectionsTest do } = Connections.get_state(name) end - test "remove earlier used", %{name: name, pid: pid} do + test "remove earlier used and idle", %{name: name, pid: pid} do + self = self() api = Pleroma.Config.get([API]) Pleroma.Config.put([API], API.Gun) on_exit(fn -> Pleroma.Config.put([API], api) end) - Connections.get_conn("https://www.google.com", [genserver_pid: pid], name) - Connections.get_conn("https://www.google.com", [genserver_pid: pid], name) + Connections.checkin("https://www.google.com", [genserver_pid: pid], name) + conn = Connections.checkin("https://www.google.com", [genserver_pid: pid], name) Process.sleep(1_000) - Connections.get_conn("https://httpbin.org", [genserver_pid: pid], name) - Connections.get_conn("https://httpbin.org", [genserver_pid: pid], name) + Connections.checkin("https://httpbin.org", [genserver_pid: pid], name) + Connections.checkin("https://httpbin.org", [genserver_pid: pid], name) %Connections{ conns: %{ "https:httpbin.org:443" => %Conn{ conn: _, - state: :up, + gun_state: :up, waiting_pids: [] }, "https:www.google.com:443" => %Conn{ - conn: _, - state: :up, + conn: ^conn, + gun_state: :up, waiting_pids: [] } }, opts: [max_connections: 2, timeout: 10] } = Connections.get_state(name) + :ok = Connections.checkout(conn, self, name) + :ok = Connections.checkout(conn, self, name) Process.sleep(1_000) - conn = Connections.get_conn("http://httpbin.org", [genserver_pid: pid], name) + conn = Connections.checkin("http://httpbin.org", [genserver_pid: pid], name) %Connections{ conns: %{ "http:httpbin.org:80" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] }, "https:httpbin.org:443" => %Conn{ conn: _, - state: :up, + gun_state: :up, waiting_pids: [] } }, opts: [max_connections: 2, timeout: 10] } = Connections.get_state(name) end + + test "doesn't drop active connections on pool overflow addinng new requests to the queue", %{ + name: name, + pid: pid + } do + api = Pleroma.Config.get([API]) + Pleroma.Config.put([API], API.Gun) + on_exit(fn -> Pleroma.Config.put([API], api) end) + + self = self() + Connections.checkin("https://www.google.com", [genserver_pid: pid], name) + conn1 = Connections.checkin("https://www.google.com", [genserver_pid: pid], name) + conn2 = Connections.checkin("https://httpbin.org", [genserver_pid: pid], name) + + %Connections{ + conns: %{ + "https:httpbin.org:443" => %Conn{ + conn: ^conn2, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}] + }, + "https:www.google.com:443" => %Conn{ + conn: ^conn1, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}, {^self, _}] + } + }, + opts: [max_connections: 2, timeout: 10] + } = Connections.get_state(name) + + task = + Task.async(fn -> Connections.checkin("http://httpbin.org", [genserver_pid: pid], name) end) + + task_pid = task.pid + + :ok = Connections.checkout(conn1, self, name) + + Process.sleep(1_000) + + %Connections{ + conns: %{ + "https:httpbin.org:443" => %Conn{ + conn: ^conn2, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}] + }, + "https:www.google.com:443" => %Conn{ + conn: ^conn1, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}] + } + }, + queue: [{{^task_pid, _}, "http:httpbin.org:80", _, _}], + opts: [max_connections: 2, timeout: 10] + } = Connections.get_state(name) + + :ok = Connections.checkout(conn1, self, name) + + %Connections{ + conns: %{ + "https:httpbin.org:443" => %Conn{ + conn: ^conn2, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}] + }, + "https:www.google.com:443" => %Conn{ + conn: ^conn1, + gun_state: :up, + waiting_pids: [], + conn_state: :idle, + used_by: [] + } + }, + queue: [{{^task_pid, _}, "http:httpbin.org:80", _, _}], + opts: [max_connections: 2, timeout: 10] + } = Connections.get_state(name) + + :ok = Connections.process_queue(name) + conn = Task.await(task) + + %Connections{ + conns: %{ + "https:httpbin.org:443" => %Conn{ + conn: ^conn2, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^self, _}] + }, + "http:httpbin.org:80" => %Conn{ + conn: ^conn, + gun_state: :up, + waiting_pids: [], + conn_state: :active, + used_by: [{^task_pid, _}] + } + }, + queue: [], + opts: [max_connections: 2, timeout: 10] + } = Connections.get_state(name) + end end describe "with proxy usage" do test "proxy as ip", %{name: name, pid: pid} do conn = - Connections.get_conn( + Connections.checkin( "http://proxy_string.com", [genserver_pid: pid, proxy: {{127, 0, 0, 1}, 8123}], name @@ -363,7 +531,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:proxy_string.com:80" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] } }, @@ -371,7 +539,7 @@ defmodule Gun.ConnectionsTest do } = Connections.get_state(name) reused_conn = - Connections.get_conn( + Connections.checkin( "http://proxy_string.com", [genserver_pid: pid, proxy: {{127, 0, 0, 1}, 8123}], name @@ -382,7 +550,7 @@ defmodule Gun.ConnectionsTest do test "proxy as host", %{name: name, pid: pid} do conn = - Connections.get_conn( + Connections.checkin( "http://proxy_tuple_atom.com", [genserver_pid: pid, proxy: {'localhost', 9050}], name @@ -392,7 +560,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "http:proxy_tuple_atom.com:80" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] } }, @@ -400,7 +568,7 @@ defmodule Gun.ConnectionsTest do } = Connections.get_state(name) reused_conn = - Connections.get_conn( + Connections.checkin( "http://proxy_tuple_atom.com", [genserver_pid: pid, proxy: {'localhost', 9050}], name @@ -411,7 +579,7 @@ defmodule Gun.ConnectionsTest do test "proxy as ip and ssl", %{name: name, pid: pid} do conn = - Connections.get_conn( + Connections.checkin( "https://proxy_string.com", [genserver_pid: pid, proxy: {{127, 0, 0, 1}, 8123}], name @@ -421,7 +589,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "https:proxy_string.com:443" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] } }, @@ -429,7 +597,7 @@ defmodule Gun.ConnectionsTest do } = Connections.get_state(name) reused_conn = - Connections.get_conn( + Connections.checkin( "https://proxy_string.com", [genserver_pid: pid, proxy: {{127, 0, 0, 1}, 8123}], name @@ -440,7 +608,7 @@ defmodule Gun.ConnectionsTest do test "proxy as host and ssl", %{name: name, pid: pid} do conn = - Connections.get_conn( + Connections.checkin( "https://proxy_tuple_atom.com", [genserver_pid: pid, proxy: {'localhost', 9050}], name @@ -450,7 +618,7 @@ defmodule Gun.ConnectionsTest do conns: %{ "https:proxy_tuple_atom.com:443" => %Conn{ conn: ^conn, - state: :up, + gun_state: :up, waiting_pids: [] } }, @@ -458,7 +626,7 @@ defmodule Gun.ConnectionsTest do } = Connections.get_state(name) reused_conn = - Connections.get_conn( + Connections.checkin( "https://proxy_tuple_atom.com", [genserver_pid: pid, proxy: {'localhost', 9050}], name diff --git a/test/http_test.exs b/test/http_test.exs index 460f8f7c2..b88e3b605 100644 --- a/test/http_test.exs +++ b/test/http_test.exs @@ -71,11 +71,18 @@ defmodule Pleroma.HTTPTest do options = [adapter: [pool: :federation]] - assert {:ok, resp} = - Pleroma.HTTP.request(:get, "https://httpbin.org/user-agent", "", [], options) + assert {:ok, resp} = Pleroma.HTTP.get("https://httpbin.org/user-agent", [], options) adapter_opts = resp.opts[:adapter] + assert resp.status == 200 + assert adapter_opts[:url] == "https://httpbin.org/user-agent" + state = Pleroma.Gun.Connections.get_state(:federation) + conn = state.conns["https:httpbin.org:443"] + + assert conn.conn_state == :idle + assert conn.used_by == [] + assert state.queue == [] end end