defmodule Pleroma.HTTP.AdapterHelper.GunTest do
use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
+
import ExUnit.CaptureLog
+ import Mox
+
alias Pleroma.Config
alias Pleroma.Gun.Conn
alias Pleroma.HTTP.AdapterHelper.Gun
alias Pleroma.Pool.Connections
- setup_all do
- {:ok, _} = Registry.start_link(keys: :unique, name: Pleroma.GunMock)
+ setup :verify_on_exit!
+
+ defp gun_mock(_) do
+ gun_mock()
:ok
end
+ defp gun_mock do
+ Pleroma.GunMock
+ |> expect(:open, fn _, _, _ -> Task.start_link(fn -> Process.sleep(1000) end) end)
+ |> expect(:await_up, fn _, _ -> {:ok, :http} end)
+ |> expect(:set_owner, fn _, _ -> :ok end)
+ end
+
describe "options/1" do
clear_config([:http, :adapter]) do
Config.put([:http, :adapter], a: 1, b: 2)
test "https url with default port" do
uri = URI.parse("https://example.com")
- opts = Gun.options(uri)
+ opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
- tls_opts = opts[:tls_opts]
- assert tls_opts[:verify] == :verify_peer
- assert tls_opts[:depth] == 20
- assert tls_opts[:reuse_sessions] == false
+ refute opts[:tls_opts] == []
- assert tls_opts[:verify_fun] ==
+ assert opts[:tls_opts][:verify_fun] ==
{&:ssl_verify_hostname.verify_fun/3, [check_hostname: 'example.com']}
- assert File.exists?(tls_opts[:cacertfile])
+ assert File.exists?(opts[:tls_opts][:cacertfile])
end
test "https ipv4 with default port" do
uri = URI.parse("https://127.0.0.1")
- opts = Gun.options(uri)
+ opts = Gun.options([receive_conn: false], uri)
assert opts[:tls_opts][:verify_fun] ==
{&:ssl_verify_hostname.verify_fun/3, [check_hostname: '127.0.0.1']}
test "https ipv6 with default port" do
uri = URI.parse("https://[2a03:2880:f10c:83:face:b00c:0:25de]")
- opts = Gun.options(uri)
+ opts = Gun.options([receive_conn: false], uri)
assert opts[:tls_opts][:verify_fun] ==
{&:ssl_verify_hostname.verify_fun/3,
test "https url with non standart port" do
uri = URI.parse("https://example.com:115")
- opts = Gun.options(uri)
+ opts = Gun.options([receive_conn: false], uri)
assert opts[:certificates_verification]
assert opts[:transport] == :tls
end
- test "receive conn by default" do
- uri = URI.parse("http://another-domain.com")
- :ok = Conn.open(uri, :gun_connections)
-
- received_opts = Gun.options(uri)
- assert received_opts[:close_conn] == false
- assert is_pid(received_opts[:conn])
- end
-
- test "don't receive conn if receive_conn is false" do
- uri = URI.parse("http://another-domain2.com")
- :ok = Conn.open(uri, :gun_connections)
-
- opts = [receive_conn: false]
- received_opts = Gun.options(opts, uri)
- assert received_opts[:close_conn] == nil
- assert received_opts[:conn] == nil
- end
-
test "get conn on next request" do
+ gun_mock()
level = Application.get_env(:logger, :level)
Logger.configure(level: :debug)
on_exit(fn -> Logger.configure(level: level) end)
end
test "merges with defaul http adapter config" do
- defaults = Gun.options(URI.parse("https://example.com"))
+ defaults = Gun.options([receive_conn: false], URI.parse("https://example.com"))
assert Keyword.has_key?(defaults, :a)
assert Keyword.has_key?(defaults, :b)
end
test "default ssl adapter opts with connection" do
+ gun_mock()
uri = URI.parse("https://some-domain.com")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options(uri)
assert opts[:certificates_verification]
- tls_opts = opts[:tls_opts]
- assert tls_opts[:verify] == :verify_peer
- assert tls_opts[:depth] == 20
- assert tls_opts[:reuse_sessions] == false
+ refute opts[:tls_opts] == []
assert opts[:close_conn] == false
assert is_pid(opts[:conn])
end
end
+ describe "options/1 with receive_conn parameter" do
+ setup :gun_mock
+
+ test "receive conn by default" do
+ uri = URI.parse("http://another-domain.com")
+ :ok = Conn.open(uri, :gun_connections)
+
+ received_opts = Gun.options(uri)
+ assert received_opts[:close_conn] == false
+ assert is_pid(received_opts[:conn])
+ end
+
+ test "don't receive conn if receive_conn is false" do
+ uri = URI.parse("http://another-domain.com")
+ :ok = Conn.open(uri, :gun_connections)
+
+ opts = [receive_conn: false]
+ received_opts = Gun.options(opts, uri)
+ assert received_opts[:close_conn] == nil
+ assert received_opts[:conn] == nil
+ end
+ end
+
describe "after_request/1" do
+ setup :gun_mock
+
test "body_as not chunks" do
uri = URI.parse("http://some-domain.com")
:ok = Conn.open(uri, :gun_connections)
uri = URI.parse("http://127.0.0.1")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options(uri)
- send(:gun_connections, {:gun_up, opts[:conn], :http})
:ok = Gun.after_request(opts)
conn = opts[:conn]
uri = URI.parse("http://[2a03:2880:f10c:83:face:b00c:0:25de]")
:ok = Conn.open(uri, :gun_connections)
opts = Gun.options(uri)
- send(:gun_connections, {:gun_up, opts[:conn], :http})
:ok = Gun.after_request(opts)
conn = opts[:conn]
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelper.HackneyTest do
- use ExUnit.Case
+ use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
alias Pleroma.Config
end
test "add proxy and opts from config", %{uri: uri} do
- proxy = Config.get([:http, :proxy_url])
- Config.put([:http, :proxy_url], "localhost:8123")
- on_exit(fn -> Config.put([:http, :proxy_url], proxy) end)
-
- opts = Hackney.options(uri)
+ opts = Hackney.options([proxy: "localhost:8123"], uri)
assert opts[:a] == 1
assert opts[:b] == 2
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.ConnectionTest do
- use ExUnit.Case
+ use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
+
import ExUnit.CaptureLog
+ import Mox
+
alias Pleroma.Config
alias Pleroma.HTTP.Connection
- setup_all do
- {:ok, _} = Registry.start_link(keys: :unique, name: Pleroma.GunMock)
- :ok
- end
+ setup :verify_on_exit!
describe "parse_host/1" do
test "as atom to charlist" do
uri = URI.parse("https://some-domain.com")
- pid = Process.whereis(:federation)
- :ok = Pleroma.Gun.Conn.open(uri, :gun_connections, genserver_pid: pid)
+ Pleroma.GunMock
+ |> expect(:open, fn 'some-domain.com', 443, _ ->
+ Task.start_link(fn -> Process.sleep(1000) end)
+ end)
+ |> expect(:await_up, fn _, _ -> {:ok, :http2} end)
+ |> expect(:set_owner, fn _, _ -> :ok end)
+
+ :ok = Pleroma.Gun.Conn.open(uri, :gun_connections)
opts = Connection.options(uri)
assert opts[:certificates_verification]
- tls_opts = opts[:tls_opts]
- assert tls_opts[:verify] == :verify_peer
- assert tls_opts[:depth] == 20
- assert tls_opts[:reuse_sessions] == false
+ refute opts[:tls_opts] == []
assert opts[:close_conn] == false
assert is_pid(opts[:conn])
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Pool.ConnectionsTest do
- use ExUnit.Case
+ use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
+
import ExUnit.CaptureLog
+ import Mox
+
alias Pleroma.Gun.Conn
+ alias Pleroma.GunMock
alias Pleroma.Pool.Connections
+ setup :verify_on_exit!
+
setup_all do
+ name = :test_connections
+ {:ok, pid} = Connections.start_link({name, [checkin_timeout: 150]})
{:ok, _} = Registry.start_link(keys: :unique, name: Pleroma.GunMock)
- :ok
+
+ on_exit(fn ->
+ if Process.alive?(pid), do: GenServer.stop(name)
+ end)
+
+ {:ok, name: name}
end
- clear_config([:connections_pool, :retry]) do
- Pleroma.Config.put([:connections_pool, :retry], 5)
+ defp open_mock(num \\ 1) do
+ GunMock
+ |> expect(:open, num, &start_and_register(&1, &2, &3))
+ |> expect(:await_up, num, fn _, _ -> {:ok, :http} end)
+ |> expect(:set_owner, num, fn _, _ -> :ok end)
end
- setup do
- name = :test_connections
- adapter = Application.get_env(:tesla, :adapter)
- Application.put_env(:tesla, :adapter, Tesla.Adapter.Gun)
+ defp connect_mock(mock) do
+ mock
+ |> expect(:connect, &connect(&1, &2))
+ |> expect(:await, &await(&1, &2))
+ end
- {:ok, pid} = Connections.start_link({name, [max_connections: 2, checkin_timeout: 1_500]})
+ defp info_mock(mock), do: expect(mock, :info, &info(&1))
- on_exit(fn ->
- Application.put_env(:tesla, :adapter, adapter)
+ defp start_and_register('gun-not-up.com', _, _), do: {:error, :timeout}
- if Process.alive?(pid) do
- GenServer.stop(name)
+ defp start_and_register(host, port, _) do
+ {:ok, pid} = Task.start_link(fn -> Process.sleep(1000) end)
+
+ scheme =
+ case port do
+ 443 -> "https"
+ _ -> "http"
end
- end)
- {:ok, name: name}
+ Registry.register(GunMock, pid, %{
+ origin_scheme: scheme,
+ origin_host: host,
+ origin_port: port
+ })
+
+ {:ok, pid}
+ end
+
+ defp info(pid) do
+ [{_, info}] = Registry.lookup(GunMock, pid)
+ info
end
+ defp connect(pid, _) do
+ ref = make_ref()
+ Registry.register(GunMock, ref, pid)
+ ref
+ end
+
+ defp await(pid, ref) do
+ [{_, ^pid}] = Registry.lookup(GunMock, ref)
+ {:response, :fin, 200, []}
+ end
+
+ defp now, do: :os.system_time(:second)
+
describe "alive?/2" do
test "is alive", %{name: name} do
assert Connections.alive?(name)
end
test "opens connection and reuse it on next request", %{name: name} do
+ open_mock()
url = "http://some-domain.com"
key = "http:some-domain.com:80"
refute Connections.checkin(url, name)
end
test "reuse connection for idna domains", %{name: name} do
+ open_mock()
url = "http://ですsome-domain.com"
refute Connections.checkin(url, name)
end
test "reuse for ipv4", %{name: name} do
+ open_mock()
url = "http://127.0.0.1"
refute Connections.checkin(url, name)
end
test "reuse for ipv6", %{name: name} do
+ open_mock()
url = "http://[2a03:2880:f10c:83:face:b00c:0:25de]"
refute Connections.checkin(url, name)
end
test "up and down ipv4", %{name: name} do
+ open_mock()
+ |> info_mock()
+ |> allow(self(), name)
+
self = self()
url = "http://127.0.0.1"
:ok = Conn.open(url, name)
test "up and down ipv6", %{name: name} do
self = self()
+
+ open_mock()
+ |> info_mock()
+ |> allow(self, name)
+
url = "http://[2a03:2880:f10c:83:face:b00c:0:25de]"
:ok = Conn.open(url, name)
conn = Connections.checkin(url, name)
end
test "reuses connection based on protocol", %{name: name} do
+ open_mock(2)
http_url = "http://some-domain.com"
http_key = "http:some-domain.com:80"
https_url = "https://some-domain.com"
end
test "connection can't get up", %{name: name} do
+ expect(GunMock, :open, &start_and_register(&1, &2, &3))
url = "http://gun-not-up.com"
assert capture_log(fn ->
test "process gun_down message and then gun_up", %{name: name} do
self = self()
+
+ open_mock()
+ |> info_mock()
+ |> allow(self, name)
+
url = "http://gun-down-and-up.com"
key = "http:gun-down-and-up.com:80"
:ok = Conn.open(url, name)
end
test "async processes get same conn for same domain", %{name: name} do
+ open_mock()
url = "http://some-domain.com"
:ok = Conn.open(url, name)
end
test "remove frequently used and idle", %{name: name} do
+ open_mock(3)
self = self()
http_url = "http://some-domain.com"
https_url = "https://some-domain.com"
describe "with proxy" do
test "as ip", %{name: name} do
+ open_mock()
+ |> connect_mock()
+
url = "http://proxy-string.com"
key = "http:proxy-string.com:80"
:ok = Conn.open(url, name, proxy: {{127, 0, 0, 1}, 8123})
end
test "as host", %{name: name} do
+ open_mock()
+ |> connect_mock()
+
url = "http://proxy-tuple-atom.com"
:ok = Conn.open(url, name, proxy: {'localhost', 9050})
conn = Connections.checkin(url, name)
end
test "as ip and ssl", %{name: name} do
+ open_mock()
+ |> connect_mock()
+
url = "https://proxy-string.com"
:ok = Conn.open(url, name, proxy: {{127, 0, 0, 1}, 8123})
end
test "as host and ssl", %{name: name} do
+ open_mock()
+ |> connect_mock()
+
url = "https://proxy-tuple-atom.com"
:ok = Conn.open(url, name, proxy: {'localhost', 9050})
conn = Connections.checkin(url, name)
end
test "with socks type", %{name: name} do
+ open_mock()
+
url = "http://proxy-socks.com"
:ok = Conn.open(url, name, proxy: {:socks5, 'localhost', 1234})
end
test "with socks4 type and ssl", %{name: name} do
+ open_mock()
url = "https://proxy-socks.com"
:ok = Conn.open(url, name, proxy: {:socks4, 'localhost', 1234})
end
end
- test "count/1", %{name: name} do
+ test "count/1" do
+ name = :test_count
+ {:ok, _} = Connections.start_link({name, [checkin_timeout: 150]})
assert Connections.count(name) == 0
Connections.add_conn(name, "1", %Conn{conn: self()})
assert Connections.count(name) == 1
Connections.remove_conn(name, "1")
assert Connections.count(name) == 0
end
-
- defp now do
- :os.system_time(:second)
- end
end
+++ /dev/null
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.GunMock do
- @behaviour Pleroma.Gun
-
- alias Pleroma.Gun
- alias Pleroma.GunMock
-
- @impl Gun
- def open('some-domain.com', 443, _) do
- {:ok, conn_pid} = Task.start_link(fn -> Process.sleep(1_000) end)
-
- Registry.register(GunMock, conn_pid, %{
- origin_scheme: "https",
- origin_host: 'some-domain.com',
- origin_port: 443
- })
-
- {:ok, conn_pid}
- end
-
- @impl Gun
- def open(ip, port, _)
- when ip in [{10_755, 10_368, 61_708, 131, 64_206, 45_068, 0, 9_694}, {127, 0, 0, 1}] and
- port in [80, 443] do
- {:ok, conn_pid} = Task.start_link(fn -> Process.sleep(1_000) end)
-
- scheme = if port == 443, do: "https", else: "http"
-
- Registry.register(GunMock, conn_pid, %{
- origin_scheme: scheme,
- origin_host: ip,
- origin_port: port
- })
-
- {:ok, conn_pid}
- end
-
- @impl Gun
- def open('localhost', 1234, %{
- protocols: [:socks],
- proxy: {:socks5, 'localhost', 1234},
- socks_opts: %{host: 'proxy-socks.com', port: 80, version: 5}
- }) do
- {:ok, conn_pid} = Task.start_link(fn -> Process.sleep(1_000) end)
-
- Registry.register(GunMock, conn_pid, %{
- origin_scheme: "http",
- origin_host: 'proxy-socks.com',
- origin_port: 80
- })
-
- {:ok, conn_pid}
- end
-
- @impl Gun
- def open('localhost', 1234, %{
- protocols: [:socks],
- proxy: {:socks4, 'localhost', 1234},
- socks_opts: %{
- host: 'proxy-socks.com',
- port: 443,
- protocols: [:http2],
- tls_opts: [],
- transport: :tls,
- version: 4
- }
- }) do
- {:ok, conn_pid} = Task.start_link(fn -> Process.sleep(1_000) end)
-
- Registry.register(GunMock, conn_pid, %{
- origin_scheme: "https",
- origin_host: 'proxy-socks.com',
- origin_port: 443
- })
-
- {:ok, conn_pid}
- end
-
- @impl Gun
- def open('gun-not-up.com', 80, _opts), do: {:error, :timeout}
-
- @impl Gun
- def open('example.com', port, _) when port in [443, 115] do
- {:ok, conn_pid} = Task.start_link(fn -> Process.sleep(1_000) end)
-
- Registry.register(GunMock, conn_pid, %{
- origin_scheme: "https",
- origin_host: 'example.com',
- origin_port: 443
- })
-
- {:ok, conn_pid}
- end
-
- @impl Gun
- def open(domain, 80, _) do
- {:ok, conn_pid} = Task.start_link(fn -> Process.sleep(1_000) end)
-
- Registry.register(GunMock, conn_pid, %{
- origin_scheme: "http",
- origin_host: domain,
- origin_port: 80
- })
-
- {:ok, conn_pid}
- end
-
- @impl Gun
- def open({127, 0, 0, 1}, 8123, _) do
- Task.start_link(fn -> Process.sleep(1_000) end)
- end
-
- @impl Gun
- def open('localhost', 9050, _) do
- Task.start_link(fn -> Process.sleep(1_000) end)
- end
-
- @impl Gun
- def await_up(_pid, _timeout), do: {:ok, :http}
-
- @impl Gun
- def set_owner(_pid, _owner), do: :ok
-
- @impl Gun
- def connect(pid, %{host: _, port: 80}) do
- ref = make_ref()
- Registry.register(GunMock, ref, pid)
- ref
- end
-
- @impl Gun
- def connect(pid, %{host: _, port: 443, protocols: [:http2], transport: :tls}) do
- ref = make_ref()
- Registry.register(GunMock, ref, pid)
- ref
- end
-
- @impl Gun
- def await(pid, ref) do
- [{_, ^pid}] = Registry.lookup(GunMock, ref)
- {:response, :fin, 200, []}
- end
-
- @impl Gun
- def info(pid) do
- [{_, info}] = Registry.lookup(GunMock, pid)
- info
- end
-
- @impl Gun
- def close(_pid), do: :ok
-end
ExUnit.start(exclude: [:federated | os_exclude])
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
+
Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)
+Mox.defmock(Pleroma.GunMock, for: Pleroma.Gun)
+
{:ok, _} = Application.ensure_all_started(:ex_machina)
ExUnit.after_suite(fn _results ->