Page MenuHomePhorge

No OneTemporary

Size
18 KB
Referenced Files
None
Subscribers
None
diff --git a/mix.exs b/mix.exs
index f96789d21..ed3864ee6 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,249 +1,249 @@
defmodule Pleroma.Mixfile do
use Mix.Project
def project do
[
app: :pleroma,
version: version("1.0.0"),
elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
elixirc_options: [warnings_as_errors: true],
xref: [exclude: [:eldap]],
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
test_coverage: [tool: ExCoveralls],
# Docs
name: "Pleroma",
homepage_url: "https://pleroma.social/",
source_url: "https://git.pleroma.social/pleroma/pleroma",
docs: [
source_url_pattern:
"https://git.pleroma.social/pleroma/pleroma/blob/develop/%{path}#L%{line}",
logo: "priv/static/static/logo.png",
extras: ["README.md", "CHANGELOG.md"] ++ Path.wildcard("docs/**/*.md"),
groups_for_extras: [
"Installation manuals": Path.wildcard("docs/installation/*.md"),
Configuration: Path.wildcard("docs/config/*.md"),
Administration: Path.wildcard("docs/admin/*.md"),
"Pleroma's APIs and Mastodon API extensions": Path.wildcard("docs/api/*.md")
],
main: "readme",
output: "priv/static/doc"
],
releases: [
pleroma: [
include_executables_for: [:unix],
applications: [ex_syslogger: :load, syslog: :load],
steps: [:assemble, &copy_files/1, &copy_nginx_config/1]
]
]
]
end
def copy_files(%{path: target_path} = release) do
File.cp_r!("./rel/files", target_path)
release
end
def copy_nginx_config(%{path: target_path} = release) do
File.cp!(
"./installation/pleroma.nginx",
Path.join([target_path, "installation", "pleroma.nginx"])
)
release
end
# Configuration for the OTP application.
#
# Type `mix help compile.app` for more information.
def application do
[
mod: {Pleroma.Application, []},
- extra_applications: [:logger, :runtime_tools, :comeonin, :quack],
+ extra_applications: [:logger, :runtime_tools, :comeonin, :quack, :prometheus],
included_applications: [:ex_syslogger]
]
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
# Specifies OAuth dependencies.
defp oauth_deps do
oauth_strategy_packages =
System.get_env("OAUTH_CONSUMER_STRATEGIES")
|> to_string()
|> String.split()
|> Enum.map(fn strategy_entry ->
with [_strategy, dependency] <- String.split(strategy_entry, ":") do
dependency
else
[strategy] -> "ueberauth_#{strategy}"
end
end)
for s <- oauth_strategy_packages, do: {String.to_atom(s), ">= 0.0.0"}
end
# Specifies your project dependencies.
#
# Type `mix help deps` for examples and options.
defp deps do
[
{:phoenix, "~> 1.4.8"},
{:plug_cowboy, "~> 2.0"},
{:phoenix_pubsub, "~> 1.1"},
{:phoenix_ecto, "~> 4.0"},
{:ecto_sql, "~> 3.1"},
{:postgrex, ">= 0.13.5"},
{:gettext, "~> 0.15"},
{:comeonin, "~> 4.1.1"},
{:pbkdf2_elixir, "~> 0.12.3"},
{:trailing_format_plug, "~> 0.0.7"},
{:html_sanitize_ex, "~> 1.3.0"},
{:html_entities, "~> 0.4"},
{:phoenix_html, "~> 2.10"},
{:calendar, "~> 0.17.4"},
{:cachex, "~> 3.0.2"},
{:poison, "~> 3.0", override: true},
{:tesla, "~> 1.2"},
{:jason, "~> 1.0"},
{:mogrify, "~> 0.6.1"},
{:ex_aws, "~> 2.0"},
{:ex_aws_s3, "~> 2.0"},
{:earmark, "~> 1.3"},
{:bbcode, "~> 0.1.1"},
{:ex_machina, "~> 2.3", only: :test},
{:credo, "~> 0.9.3", only: [:dev, :test]},
{:mock, "~> 0.3.3", only: :test},
{:crypt,
git: "https://github.com/msantos/crypt", ref: "1f2b58927ab57e72910191a7ebaeff984382a1d3"},
{:cors_plug, "~> 1.5"},
{:ex_doc, "~> 0.20.2", only: :dev, runtime: false},
{:web_push_encryption, "~> 0.2.1"},
{:swoosh, "~> 0.23.2"},
{:gen_smtp, "~> 0.13"},
{:websocket_client, git: "https://github.com/jeremyong/websocket_client.git", only: :test},
{:floki, "~> 0.20.0"},
{:ex_syslogger, github: "slashmili/ex_syslogger", tag: "1.4.0"},
{:timex, "~> 3.5"},
{:ueberauth, "~> 0.4"},
{:auto_linker,
git: "https://git.pleroma.social/pleroma/auto_linker.git",
ref: "95e8188490e97505c56636c1379ffdf036c1fdde"},
{:http_signatures,
git: "https://git.pleroma.social/pleroma/http_signatures.git",
ref: "9789401987096ead65646b52b5a2ca6bf52fc531"},
{:pleroma_job_queue, "~> 0.2.0"},
{:telemetry, "~> 0.3"},
{:prometheus_ex, "~> 3.0"},
{:prometheus_plugs, "~> 1.1"},
{:prometheus_phoenix, "~> 1.2"},
{:prometheus_ecto, "~> 1.4"},
{:recon, github: "ferd/recon", tag: "2.4.0"},
{:quack, "~> 0.1.1"},
{:benchee, "~> 1.0"},
{:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)},
{:ex_rated, "~> 1.3"},
{:plug_static_index_html, "~> 1.0.0"},
{:excoveralls, "~> 0.11.1", only: :test},
{:mox, "~> 0.5", only: :test}
] ++ oauth_deps()
end
# Aliases are shortcuts or tasks specific to the current project.
# For example, to create, migrate and run the seeds file at once:
#
# $ mix ecto.setup
#
# See the documentation for `Mix` for more info on aliases.
defp aliases do
[
"ecto.migrate": ["pleroma.ecto.migrate"],
"ecto.rollback": ["pleroma.ecto.rollback"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate", "test"]
]
end
# Builds a version string made of:
# * the application version
# * a pre-release if ahead of the tag: the describe string (-count-commithash)
# * branch name
# * build metadata:
# * a build name if `PLEROMA_BUILD_NAME` or `:pleroma, :build_name` is defined
# * the mix environment if different than prod
defp version(version) do
identifier_filter = ~r/[^0-9a-z\-]+/i
# Pre-release version, denoted from patch version with a hyphen
{git_tag, git_pre_release} =
with {tag, 0} <-
System.cmd("git", ["describe", "--tags", "--abbrev=0"], stderr_to_stdout: true),
tag = String.trim(tag),
{describe, 0} <- System.cmd("git", ["describe", "--tags", "--abbrev=8"]),
describe = String.trim(describe),
ahead <- String.replace(describe, tag, "") do
{String.replace_prefix(tag, "v", ""), if(ahead != "", do: String.trim(ahead))}
else
_ ->
{commit_hash, 0} = System.cmd("git", ["rev-parse", "--short", "HEAD"])
{nil, "-0-g" <> String.trim(commit_hash)}
end
if git_tag && version != git_tag do
Mix.shell().error(
"Application version #{inspect(version)} does not match git tag #{inspect(git_tag)}"
)
end
# Branch name as pre-release version component, denoted with a dot
branch_name =
with {branch_name, 0} <- System.cmd("git", ["rev-parse", "--abbrev-ref", "HEAD"]),
branch_name <- System.get_env("PLEROMA_BUILD_BRANCH") || branch_name,
true <- branch_name != "master" do
branch_name =
branch_name
|> String.trim()
|> String.replace(identifier_filter, "-")
"." <> branch_name
end
build_name =
cond do
name = Application.get_env(:pleroma, :build_name) -> name
name = System.get_env("PLEROMA_BUILD_NAME") -> name
true -> nil
end
env_name = if Mix.env() != :prod, do: to_string(Mix.env())
env_override = System.get_env("PLEROMA_BUILD_ENV")
env_name =
case env_override do
nil -> env_name
env_override when env_override in ["", "prod"] -> nil
env_override -> env_override
end
# Build metadata, denoted with a plus sign
build_metadata =
[build_name, env_name]
|> Enum.filter(fn string -> string && string != "" end)
|> Enum.join(".")
|> (fn
"" -> nil
string -> "+" <> String.replace(string, identifier_filter, "-")
end).()
[version, git_pre_release, branch_name, build_metadata]
|> Enum.filter(fn string -> string && string != "" end)
|> Enum.join()
end
end
diff --git a/test/federation/federation_test.exs b/test/federation/federation_test.exs
new file mode 100644
index 000000000..7400d2abc
--- /dev/null
+++ b/test/federation/federation_test.exs
@@ -0,0 +1,43 @@
+# 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
+
+ import Pleroma.Cluster
+
+ @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 = mastodon_api_url(Pleroma.Web.Endpoint, :user, user)
+ url_404 = mastodon_api_url(Pleroma.Web.Endpoint, :user, "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 3e33f0335..d646be50c 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -1,8 +1,9 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
+Pleroma.Cluster.spawn_default_cluster()
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
Mox.defmock(Pleroma.ReverseProxy.ClientMock, for: Pleroma.ReverseProxy.Client)
{:ok, _} = Application.ensure_all_started(:ex_machina)

File Metadata

Mime Type
text/x-diff
Expires
Sun, Aug 9, 3:52 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1724175
Default Alt Text
(18 KB)

Event Timeline