aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/federation/federation_test.exs47
-rw-r--r--test/support/cluster.ex218
-rw-r--r--test/test_helper.exs3
-rw-r--r--test/user_test.exs78
-rw-r--r--test/web/activity_pub/transmogrifier_test.exs5
-rw-r--r--test/web/admin_api/admin_api_controller_test.exs1
-rw-r--r--test/web/mastodon_api/views/account_view_test.exs11
-rw-r--r--test/web/streamer/streamer_test.exs2
8 files changed, 300 insertions, 65 deletions
diff --git a/test/federation/federation_test.exs b/test/federation/federation_test.exs
new file mode 100644
index 000000000..45800568a
--- /dev/null
+++ b/test/federation/federation_test.exs
@@ -0,0 +1,47 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Integration.FederationTest do
+ use Pleroma.DataCase
+ @moduletag :federated
+ import Pleroma.Cluster
+
+ setup_all do
+ Pleroma.Cluster.spawn_default_cluster()
+ :ok
+ end
+
+ @federated1 :"federated1@127.0.0.1"
+ describe "federated cluster primitives" do
+ test "within/2 captures local bindings and executes block on remote node" do
+ captured_binding = :captured
+
+ result =
+ within @federated1 do
+ user = Pleroma.Factory.insert(:user)
+ {captured_binding, node(), user}
+ end
+
+ assert {:captured, @federated1, user} = result
+ refute Pleroma.User.get_by_id(user.id)
+ assert user.id == within(@federated1, do: Pleroma.User.get_by_id(user.id)).id
+ end
+
+ test "runs webserver on customized port" do
+ {nickname, url, url_404} =
+ within @federated1 do
+ import Pleroma.Web.Router.Helpers
+ user = Pleroma.Factory.insert(:user)
+ user_url = account_url(Pleroma.Web.Endpoint, :show, user)
+ url_404 = account_url(Pleroma.Web.Endpoint, :show, "not-exists")
+
+ {user.nickname, user_url, url_404}
+ end
+
+ assert {:ok, {{_, 200, _}, _headers, body}} = :httpc.request(~c"#{url}")
+ assert %{"acct" => ^nickname} = Jason.decode!(body)
+ assert {:ok, {{_, 404, _}, _headers, _body}} = :httpc.request(~c"#{url_404}")
+ end
+ end
+end
diff --git a/test/support/cluster.ex b/test/support/cluster.ex
new file mode 100644
index 000000000..deb37f361
--- /dev/null
+++ b/test/support/cluster.ex
@@ -0,0 +1,218 @@
+defmodule Pleroma.Cluster do
+ @moduledoc """
+ Facilities for managing a cluster of slave VM's for federated testing.
+
+ ## Spawning the federated cluster
+
+ `spawn_cluster/1` spawns a map of slave nodes that are started
+ within the running VM. During startup, the slave node is sent all configuration
+ from the parent node, as well as all code. After receiving configuration and
+ code, the slave then starts all applications currently running on the parent.
+ The configuration passed to `spawn_cluster/1` overrides any parent application
+ configuration for the provided OTP app and key. This is useful for customizing
+ the Ecto database, Phoenix webserver ports, etc.
+
+ For example, to start a single federated VM named ":federated1", with the
+ Pleroma Endpoint running on port 4123, and with a database named
+ "pleroma_test1", you would run:
+
+ endpoint_conf = Application.fetch_env!(:pleroma, Pleroma.Web.Endpoint)
+ repo_conf = Application.fetch_env!(:pleroma, Pleroma.Repo)
+
+ Pleroma.Cluster.spawn_cluster(%{
+ :"federated1@127.0.0.1" => [
+ {:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test1")},
+ {:pleroma, Pleroma.Web.Endpoint,
+ Keyword.merge(endpoint_conf, http: [port: 4011], url: [port: 4011], server: true)}
+ ]
+ })
+
+ *Note*: application configuration for a given key is not merged,
+ so any customization requires first fetching the existing values
+ and merging yourself by providing the merged configuration,
+ such as above with the endpoint config and repo config.
+
+ ## Executing code within a remote node
+
+ Use the `within/2` macro to execute code within the context of a remote
+ federated node. The code block captures all local variable bindings from
+ the parent's context and returns the result of the expression after executing
+ it on the remote node. For example:
+
+ import Pleroma.Cluster
+
+ parent_value = 123
+
+ result =
+ within :"federated1@127.0.0.1" do
+ {node(), parent_value}
+ end
+
+ assert result == {:"federated1@127.0.0.1, 123}
+
+ *Note*: while local bindings are captured and available within the block,
+ other parent contexts like required, aliased, or imported modules are not
+ in scope. Those will need to be reimported/aliases/required within the block
+ as `within/2` is a remote procedure call.
+ """
+
+ @extra_apps Pleroma.Mixfile.application()[:extra_applications]
+
+ @doc """
+ Spawns the default Pleroma federated cluster.
+
+ Values before may be customized as needed for the test suite.
+ """
+ def spawn_default_cluster do
+ endpoint_conf = Application.fetch_env!(:pleroma, Pleroma.Web.Endpoint)
+ repo_conf = Application.fetch_env!(:pleroma, Pleroma.Repo)
+
+ spawn_cluster(%{
+ :"federated1@127.0.0.1" => [
+ {:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test_federated1")},
+ {:pleroma, Pleroma.Web.Endpoint,
+ Keyword.merge(endpoint_conf, http: [port: 4011], url: [port: 4011], server: true)}
+ ],
+ :"federated2@127.0.0.1" => [
+ {:pleroma, Pleroma.Repo, Keyword.merge(repo_conf, database: "pleroma_test_federated2")},
+ {:pleroma, Pleroma.Web.Endpoint,
+ Keyword.merge(endpoint_conf, http: [port: 4012], url: [port: 4012], server: true)}
+ ]
+ })
+ end
+
+ @doc """
+ Spawns a configured map of federated nodes.
+
+ See `Pleroma.Cluster` module documentation for details.
+ """
+ def spawn_cluster(node_configs) do
+ # Turn node into a distributed node with the given long name
+ :net_kernel.start([:"primary@127.0.0.1"])
+
+ # Allow spawned nodes to fetch all code from this node
+ {:ok, _} = :erl_boot_server.start([])
+ allow_boot("127.0.0.1")
+
+ silence_logger_warnings(fn ->
+ node_configs
+ |> Enum.map(&Task.async(fn -> start_slave(&1) end))
+ |> Enum.map(&Task.await(&1, 60_000))
+ end)
+ end
+
+ @doc """
+ Executes block of code again remote node.
+
+ See `Pleroma.Cluster` module documentation for details.
+ """
+ defmacro within(node, do: block) do
+ quote do
+ rpc(unquote(node), unquote(__MODULE__), :eval_quoted, [
+ unquote(Macro.escape(block)),
+ binding()
+ ])
+ end
+ end
+
+ @doc false
+ def eval_quoted(block, binding) do
+ {result, _binding} = Code.eval_quoted(block, binding, __ENV__)
+ result
+ end
+
+ defp start_slave({node_host, override_configs}) do
+ log(node_host, "booting federated VM")
+ {:ok, node} = :slave.start(~c"127.0.0.1", node_name(node_host), vm_args())
+ add_code_paths(node)
+ load_apps_and_transfer_configuration(node, override_configs)
+ ensure_apps_started(node)
+ {:ok, node}
+ end
+
+ def rpc(node, module, function, args) do
+ :rpc.block_call(node, module, function, args)
+ end
+
+ defp vm_args do
+ ~c"-loader inet -hosts 127.0.0.1 -setcookie #{:erlang.get_cookie()}"
+ end
+
+ defp allow_boot(host) do
+ {:ok, ipv4} = :inet.parse_ipv4_address(~c"#{host}")
+ :ok = :erl_boot_server.add_slave(ipv4)
+ end
+
+ defp add_code_paths(node) do
+ rpc(node, :code, :add_paths, [:code.get_path()])
+ end
+
+ defp load_apps_and_transfer_configuration(node, override_configs) do
+ Enum.each(Application.loaded_applications(), fn {app_name, _, _} ->
+ app_name
+ |> Application.get_all_env()
+ |> Enum.each(fn {key, primary_config} ->
+ rpc(node, Application, :put_env, [app_name, key, primary_config, [persistent: true]])
+ end)
+ end)
+
+ Enum.each(override_configs, fn {app_name, key, val} ->
+ rpc(node, Application, :put_env, [app_name, key, val, [persistent: true]])
+ end)
+ end
+
+ defp log(node, msg), do: IO.puts("[#{node}] #{msg}")
+
+ defp ensure_apps_started(node) do
+ loaded_names = Enum.map(Application.loaded_applications(), fn {name, _, _} -> name end)
+ app_names = @extra_apps ++ (loaded_names -- @extra_apps)
+
+ rpc(node, Application, :ensure_all_started, [:mix])
+ rpc(node, Mix, :env, [Mix.env()])
+ rpc(node, __MODULE__, :prepare_database, [])
+
+ log(node, "starting application")
+
+ Enum.reduce(app_names, MapSet.new(), fn app, loaded ->
+ if Enum.member?(loaded, app) do
+ loaded
+ else
+ {:ok, started} = rpc(node, Application, :ensure_all_started, [app])
+ MapSet.union(loaded, MapSet.new(started))
+ end
+ end)
+ end
+
+ @doc false
+ def prepare_database do
+ log(node(), "preparing database")
+ repo_config = Application.get_env(:pleroma, Pleroma.Repo)
+ repo_config[:adapter].storage_down(repo_config)
+ repo_config[:adapter].storage_up(repo_config)
+
+ {:ok, _, _} =
+ Ecto.Migrator.with_repo(Pleroma.Repo, fn repo ->
+ Ecto.Migrator.run(repo, :up, log: false, all: true)
+ end)
+
+ Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
+ {:ok, _} = Application.ensure_all_started(:ex_machina)
+ end
+
+ defp silence_logger_warnings(func) do
+ prev_level = Logger.level()
+ Logger.configure(level: :error)
+ res = func.()
+ Logger.configure(level: prev_level)
+
+ res
+ end
+
+ defp node_name(node_host) do
+ node_host
+ |> to_string()
+ |> String.split("@")
+ |> Enum.at(0)
+ |> String.to_atom()
+ end
+end
diff --git a/test/test_helper.exs b/test/test_helper.exs
index c8dbee010..241ad1f94 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -3,7 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
-ExUnit.start(exclude: os_exclude)
+ExUnit.start(exclude: [:federated | os_exclude])
+
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)
{:ok, _} = Application.ensure_all_started(:ex_machina)
diff --git a/test/user_test.exs b/test/user_test.exs
index 1f3062201..f9ca2fea2 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -1011,9 +1011,9 @@ defmodule Pleroma.UserTest do
{:ok, user} = User.follow(user, user2)
{:ok, _user} = User.deactivate(user)
- info = User.get_cached_user_info(user2)
+ user2 = User.get_cached_by_id(user2.id)
- assert info.follower_count == 0
+ assert user2.follower_count == 0
assert [] = User.get_followers(user2)
end
@@ -1027,10 +1027,10 @@ defmodule Pleroma.UserTest do
{:ok, _user} = User.deactivate(user)
- info = User.get_cached_user_info(user2)
+ user2 = User.get_cached_by_id(user2.id)
assert refresh_record(user2).following_count == 0
- assert info.following_count == 0
+ assert user2.following_count == 0
assert User.following_count(user2) == 0
assert [] = User.get_friends(user2)
end
@@ -1232,13 +1232,12 @@ defmodule Pleroma.UserTest do
describe "caching" do
test "invalidate_cache works" do
user = insert(:user)
- _user_info = User.get_cached_user_info(user)
+ User.set_cache(user)
User.invalidate_cache(user)
{:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
{:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
- {:ok, nil} = Cachex.get(:user_cache, "user_info:#{user.id}")
end
test "User.delete() plugs any possible zombie objects" do
@@ -1395,7 +1394,7 @@ defmodule Pleroma.UserTest do
{:ok, _user_relationship} = User.block(user, follower)
user = refresh_record(user)
- assert User.user_info(user).follower_count == 2
+ assert user.follower_count == 2
end
describe "list_inactive_users_query/1" do
@@ -1572,51 +1571,6 @@ defmodule Pleroma.UserTest do
end
end
- describe "set_info_cache/2" do
- setup do
- user = insert(:user)
- {:ok, user: user}
- end
-
- test "update from args", %{user: user} do
- User.set_info_cache(user, %{following_count: 15, follower_count: 18})
-
- %{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
- assert followers == 18
- assert following == 15
- end
-
- test "without args", %{user: user} do
- User.set_info_cache(user, %{})
-
- %{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
- assert followers == 0
- assert following == 0
- end
- end
-
- describe "user_info/2" do
- setup do
- user = insert(:user)
- {:ok, user: user}
- end
-
- test "update from args", %{user: user} do
- %{follower_count: followers, following_count: following} =
- User.user_info(user, %{following_count: 15, follower_count: 18})
-
- assert followers == 18
- assert following == 15
- end
-
- test "without args", %{user: user} do
- %{follower_count: followers, following_count: following} = User.user_info(user)
-
- assert followers == 0
- assert following == 0
- end
- end
-
describe "is_internal_user?/1" do
test "non-internal user returns false" do
user = insert(:user)
@@ -1673,14 +1627,14 @@ defmodule Pleroma.UserTest do
ap_enabled: true
)
- assert User.user_info(other_user).following_count == 0
- assert User.user_info(other_user).follower_count == 0
+ assert other_user.following_count == 0
+ assert other_user.follower_count == 0
{:ok, user} = Pleroma.User.follow(user, other_user)
other_user = Pleroma.User.get_by_id(other_user.id)
- assert User.user_info(user).following_count == 1
- assert User.user_info(other_user).follower_count == 1
+ assert user.following_count == 1
+ assert other_user.follower_count == 1
end
test "syncronizes the counters with the remote instance for the followed when enabled" do
@@ -1696,14 +1650,14 @@ defmodule Pleroma.UserTest do
ap_enabled: true
)
- assert User.user_info(other_user).following_count == 0
- assert User.user_info(other_user).follower_count == 0
+ assert other_user.following_count == 0
+ assert other_user.follower_count == 0
Pleroma.Config.put([:instance, :external_user_synchronization], true)
{:ok, _user} = User.follow(user, other_user)
other_user = User.get_by_id(other_user.id)
- assert User.user_info(other_user).follower_count == 437
+ assert other_user.follower_count == 437
end
test "syncronizes the counters with the remote instance for the follower when enabled" do
@@ -1719,13 +1673,13 @@ defmodule Pleroma.UserTest do
ap_enabled: true
)
- assert User.user_info(other_user).following_count == 0
- assert User.user_info(other_user).follower_count == 0
+ assert other_user.following_count == 0
+ assert other_user.follower_count == 0
Pleroma.Config.put([:instance, :external_user_synchronization], true)
{:ok, other_user} = User.follow(other_user, user)
- assert User.user_info(other_user).following_count == 152
+ assert other_user.following_count == 152
end
end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 0bdd514e9..b31c411dc 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -39,6 +39,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert activity == returned_activity
end
+ @tag capture_log: true
test "it fetches replied-to activities if we don't have them" do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
@@ -533,6 +534,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert object.data["content"] == "this is a private toot"
end
+ @tag capture_log: true
test "it rejects incoming announces with an inlined activity from another origin" do
data =
File.read!("test/fixtures/bogus-mastodon-announce.json")
@@ -814,6 +816,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert Activity.get_by_id(activity.id)
end
+ @tag capture_log: true
test "it works for incoming user deletes" do
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
@@ -1749,6 +1752,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert modified_object["inReplyToAtomUri"] == ""
end
+ @tag capture_log: true
test "returns modified object when allowed incoming reply", %{data: data} do
object_with_reply =
Map.put(
@@ -1868,6 +1872,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
end) =~ "Unsupported URI scheme"
end
+ @tag capture_log: true
test "returns {:ok, %Object{}} for success case" do
assert {:ok, %Object{}} =
Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873")
diff --git a/test/web/admin_api/admin_api_controller_test.exs b/test/web/admin_api/admin_api_controller_test.exs
index bb2ca6a62..32577afee 100644
--- a/test/web/admin_api/admin_api_controller_test.exs
+++ b/test/web/admin_api/admin_api_controller_test.exs
@@ -1923,6 +1923,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
Pleroma.Config.put([:instance, :dynamic_configuration], true)
end
+ @tag capture_log: true
test "create new config setting in db", %{conn: conn} do
conn =
post(conn, "/api/pleroma/admin/config", %{
diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/web/mastodon_api/views/account_view_test.exs
index 53cd26a69..a8edbac70 100644
--- a/test/web/mastodon_api/views/account_view_test.exs
+++ b/test/web/mastodon_api/views/account_view_test.exs
@@ -350,7 +350,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
}
}
- assert expected == AccountView.render("show.json", %{user: user, for: other_user})
+ assert expected ==
+ AccountView.render("show.json", %{user: refresh_record(user), for: other_user})
end
test "returns the settings store if the requesting user is the represented user and it's requested specifically" do
@@ -374,6 +375,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
refute result.display_name == "<marquee> username </marquee>"
end
+ test "never display nil user follow counts" do
+ user = insert(:user, following_count: 0, follower_count: 0)
+ result = AccountView.render("show.json", %{user: user})
+
+ assert result.following_count == 0
+ assert result.followers_count == 0
+ end
+
describe "hiding follows/following" do
test "shows when follows/followers stats are hidden and sets follow/follower count to 0" do
user =
diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs
index 802c22e5d..8911c46b1 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/web/streamer/streamer_test.exs
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.StreamerTest do
alias Pleroma.Web.Streamer.StreamerSocket
alias Pleroma.Web.Streamer.Worker
- @moduletag needs_streamer: true
+ @moduletag needs_streamer: true, capture_log: true
clear_config_all([:instance, :skip_thread_containment])
describe "user streams" do