X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;ds=sidebyside;f=test%2Fpool%2Fconnections_test.exs;h=aeda54875851f171f06505596a7586ce6b02db61;hb=d6f67fa91b00b28d7be9f82bb300f9d650c73744;hp=f766e3b5f9299cf513a3e94150905a9cfac69617;hpb=d9e4b77f8be8249b428a7ef1448c9a2161dee88a;p=akkoma
diff --git a/test/pool/connections_test.exs b/test/pool/connections_test.exs
index f766e3b5f..aeda54875 100644
--- a/test/pool/connections_test.exs
+++ b/test/pool/connections_test.exs
@@ -1,36 +1,85 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2020 Pleroma Authors
# 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
- alias Pleroma.Gun.API
+ import Mox
+
alias Pleroma.Gun.Conn
+ alias Pleroma.GunMock
alias Pleroma.Pool.Connections
+ setup :verify_on_exit!
+
setup_all do
- {:ok, _} = Registry.start_link(keys: :unique, name: API.Mock)
- :ok
+ name = :test_connections
+ {:ok, pid} = Connections.start_link({name, [checkin_timeout: 150]})
+ {:ok, _} = Registry.start_link(keys: :unique, name: Pleroma.GunMock)
+
+ 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)
- on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
+ 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, receive_connection_timeout: 1_500]})
+ defp info_mock(mock), do: expect(mock, :info, &info(&1))
- {:ok, name: name}
+ defp start_and_register('gun-not-up.com', _, _), do: {:error, :timeout}
+
+ 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
+
+ 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)
@@ -42,6 +91,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
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)
@@ -107,6 +157,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
end
test "reuse connection for idna domains", %{name: name} do
+ open_mock()
url = "http://ã§ãsome-domain.com"
refute Connections.checkin(url, name)
@@ -135,6 +186,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
end
test "reuse for ipv4", %{name: name} do
+ open_mock()
url = "http://127.0.0.1"
refute Connections.checkin(url, name)
@@ -178,6 +230,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
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)
@@ -207,6 +260,10 @@ defmodule Pleroma.Pool.ConnectionsTest do
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)
@@ -228,6 +285,11 @@ defmodule Pleroma.Pool.ConnectionsTest do
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)
@@ -247,6 +309,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
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"
@@ -285,17 +348,23 @@ defmodule Pleroma.Pool.ConnectionsTest do
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 ->
refute Conn.open(url, name)
refute Connections.checkin(url, name)
end) =~
- "Received error on opening connection http://gun-not-up.com {:error, :timeout}"
+ "Opening connection to http://gun-not-up.com failed with error {:error, :timeout}"
end
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)
@@ -346,6 +415,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
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)
@@ -378,6 +448,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
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"
@@ -430,309 +501,11 @@ defmodule Pleroma.Pool.ConnectionsTest do
} = Connections.get_state(name)
end
- describe "integration test" do
- @describetag :integration
-
- clear_config(API) do
- Pleroma.Config.put(API, Pleroma.Gun)
- end
-
- test "opens connection and change owner", %{name: name} do
- url = "https://httpbin.org"
- :ok = Conn.open(url, name)
- conn = Connections.checkin(url, name)
-
- pid = Process.whereis(name)
-
- assert :gun.info(conn).owner == pid
- end
-
- test "opens connection and reuse it on next request", %{name: name} do
- url = "http://httpbin.org"
- :ok = Conn.open(url, name)
- Process.sleep(250)
- conn = Connections.checkin(url, name)
-
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- reused_conn = Connections.checkin(url, name)
-
- assert conn == reused_conn
-
- %Connections{
- conns: %{
- "http:httpbin.org:80" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
- end
-
- test "opens ssl connection and reuse it on next request", %{name: name} do
- url = "https://httpbin.org"
- :ok = Conn.open(url, name)
- Process.sleep(1_000)
- conn = Connections.checkin(url, name)
-
- assert is_pid(conn)
- assert Process.alive?(conn)
-
- reused_conn = Connections.checkin(url, name)
-
- assert conn == reused_conn
-
- %Connections{
- conns: %{
- "https:httpbin.org:443" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
- end
-
- test "remove frequently used and idle", %{name: name} do
- self = self()
- https1 = "https://www.google.com"
- https2 = "https://httpbin.org"
-
- :ok = Conn.open(https1, name)
- :ok = Conn.open(https2, name)
- Process.sleep(1_500)
- conn = Connections.checkin(https1, name)
-
- for _ <- 1..4 do
- Connections.checkin(https2, name)
- end
-
- %Connections{
- conns: %{
- "https:httpbin.org:443" => %Conn{
- conn: _,
- gun_state: :up
- },
- "https:www.google.com:443" => %Conn{
- conn: _,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- :ok = Connections.checkout(conn, self, name)
- http = "http://httpbin.org"
- Process.sleep(1_000)
- :ok = Conn.open(http, name)
- conn = Connections.checkin(http, name)
-
- %Connections{
- conns: %{
- "http:httpbin.org:80" => %Conn{
- conn: ^conn,
- gun_state: :up
- },
- "https:httpbin.org:443" => %Conn{
- conn: _,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
- end
-
- test "remove earlier used and idle", %{name: name} do
- self = self()
-
- https1 = "https://www.google.com"
- https2 = "https://httpbin.org"
- :ok = Conn.open(https1, name)
- :ok = Conn.open(https2, name)
- Process.sleep(1_500)
-
- Connections.checkin(https1, name)
- conn = Connections.checkin(https1, name)
-
- Process.sleep(1_000)
- Connections.checkin(https2, name)
- Connections.checkin(https2, name)
-
- %Connections{
- conns: %{
- "https:httpbin.org:443" => %Conn{
- conn: _,
- gun_state: :up
- },
- "https:www.google.com:443" => %Conn{
- conn: ^conn,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
-
- :ok = Connections.checkout(conn, self, name)
- :ok = Connections.checkout(conn, self, name)
-
- http = "http://httpbin.org"
- :ok = Conn.open(http, name)
- Process.sleep(1_000)
-
- conn = Connections.checkin(http, name)
-
- %Connections{
- conns: %{
- "http:httpbin.org:80" => %Conn{
- conn: ^conn,
- gun_state: :up
- },
- "https:httpbin.org:443" => %Conn{
- conn: _,
- gun_state: :up
- }
- }
- } = Connections.get_state(name)
- end
-
- test "doesn't open new conn on pool overflow", %{name: name} do
- self = self()
-
- https1 = "https://www.google.com"
- https2 = "https://httpbin.org"
- :ok = Conn.open(https1, name)
- :ok = Conn.open(https2, name)
- Process.sleep(1_000)
- Connections.checkin(https1, name)
- conn1 = Connections.checkin(https1, name)
- conn2 = Connections.checkin(https2, name)
-
- %Connections{
- conns: %{
- "https:httpbin.org:443" => %Conn{
- conn: ^conn2,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}]
- },
- "https:www.google.com:443" => %Conn{
- conn: ^conn1,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}, {^self, _}]
- }
- }
- } = Connections.get_state(name)
-
- refute Connections.checkin("http://httpbin.org", name)
-
- %Connections{
- conns: %{
- "https:httpbin.org:443" => %Conn{
- conn: ^conn2,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}]
- },
- "https:www.google.com:443" => %Conn{
- conn: ^conn1,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}, {^self, _}]
- }
- }
- } = Connections.get_state(name)
- end
-
- test "get idle connection with the smallest crf", %{
- name: name
- } do
- self = self()
-
- https1 = "https://www.google.com"
- https2 = "https://httpbin.org"
-
- :ok = Conn.open(https1, name)
- :ok = Conn.open(https2, name)
- Process.sleep(1_500)
- Connections.checkin(https1, name)
- Connections.checkin(https2, name)
- Connections.checkin(https1, name)
- conn1 = Connections.checkin(https1, name)
- conn2 = Connections.checkin(https2, name)
-
- %Connections{
- conns: %{
- "https:httpbin.org:443" => %Conn{
- conn: ^conn2,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}, {^self, _}],
- crf: crf2
- },
- "https:www.google.com:443" => %Conn{
- conn: ^conn1,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}, {^self, _}, {^self, _}],
- crf: crf1
- }
- }
- } = Connections.get_state(name)
-
- assert crf1 > crf2
-
- :ok = Connections.checkout(conn1, self, name)
- :ok = Connections.checkout(conn1, self, name)
- :ok = Connections.checkout(conn1, self, name)
-
- :ok = Connections.checkout(conn2, self, name)
- :ok = Connections.checkout(conn2, self, name)
-
- %Connections{
- conns: %{
- "https:httpbin.org:443" => %Conn{
- conn: ^conn2,
- gun_state: :up,
- conn_state: :idle,
- used_by: []
- },
- "https:www.google.com:443" => %Conn{
- conn: ^conn1,
- gun_state: :up,
- conn_state: :idle,
- used_by: []
- }
- }
- } = Connections.get_state(name)
-
- http = "http://httpbin.org"
- :ok = Conn.open(http, name)
- Process.sleep(1_000)
- conn = Connections.checkin(http, name)
-
- %Connections{
- conns: %{
- "https:www.google.com:443" => %Conn{
- conn: ^conn1,
- gun_state: :up,
- conn_state: :idle,
- used_by: [],
- crf: crf1
- },
- "http:httpbin.org:80" => %Conn{
- conn: ^conn,
- gun_state: :up,
- conn_state: :active,
- used_by: [{^self, _}],
- crf: crf
- }
- }
- } = Connections.get_state(name)
-
- assert crf1 > crf
- end
- end
-
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})
@@ -754,6 +527,9 @@ defmodule Pleroma.Pool.ConnectionsTest do
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)
@@ -773,6 +549,9 @@ defmodule Pleroma.Pool.ConnectionsTest do
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})
@@ -793,6 +572,9 @@ defmodule Pleroma.Pool.ConnectionsTest do
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)
@@ -812,6 +594,8 @@ defmodule Pleroma.Pool.ConnectionsTest do
end
test "with socks type", %{name: name} do
+ open_mock()
+
url = "http://proxy-socks.com"
:ok = Conn.open(url, name, proxy: {:socks5, 'localhost', 1234})
@@ -833,6 +617,7 @@ defmodule Pleroma.Pool.ConnectionsTest do
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})
@@ -963,15 +748,13 @@ defmodule Pleroma.Pool.ConnectionsTest do
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