diff options
Diffstat (limited to 'test/mix')
| -rw-r--r-- | test/mix/pleroma_test.exs | 50 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/app_test.exs | 65 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/config_test.exs | 189 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/count_statuses_test.exs | 39 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/database_test.exs | 175 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/digest_test.exs | 60 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/ecto/migrate_test.exs | 20 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/ecto/rollback_test.exs | 20 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/ecto_test.exs | 15 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/email_test.exs | 127 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/emoji_test.exs | 243 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/frontend_test.exs | 85 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/instance_test.exs | 99 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/refresh_counter_cache_test.exs | 43 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/relay_test.exs | 180 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/robots_txt_test.exs | 45 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/uploads_test.exs | 56 | ||||
| -rw-r--r-- | test/mix/tasks/pleroma/user_test.exs | 614 | 
18 files changed, 2125 insertions, 0 deletions
diff --git a/test/mix/pleroma_test.exs b/test/mix/pleroma_test.exs new file mode 100644 index 000000000..c3e47b285 --- /dev/null +++ b/test/mix/pleroma_test.exs @@ -0,0 +1,50 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.PleromaTest do +  use ExUnit.Case, async: true +  import Mix.Pleroma + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) + +    :ok +  end + +  describe "shell_prompt/1" do +    test "input" do +      send(self(), {:mix_shell_input, :prompt, "Yes"}) + +      answer = shell_prompt("Do you want this?") +      assert_received {:mix_shell, :prompt, [message]} +      assert message =~ "Do you want this?" +      assert answer == "Yes" +    end + +    test "with defval" do +      send(self(), {:mix_shell_input, :prompt, "\n"}) + +      answer = shell_prompt("Do you want this?", "defval") + +      assert_received {:mix_shell, :prompt, [message]} +      assert message =~ "Do you want this? [defval]" +      assert answer == "defval" +    end +  end + +  describe "get_option/3" do +    test "get from options" do +      assert get_option([domain: "some-domain.com"], :domain, "Promt") == "some-domain.com" +    end + +    test "get from prompt" do +      send(self(), {:mix_shell_input, :prompt, "another-domain.com"}) +      assert get_option([], :domain, "Prompt") == "another-domain.com" +    end +  end +end diff --git a/test/mix/tasks/pleroma/app_test.exs b/test/mix/tasks/pleroma/app_test.exs new file mode 100644 index 000000000..71a84ac8e --- /dev/null +++ b/test/mix/tasks/pleroma/app_test.exs @@ -0,0 +1,65 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.AppTest do +  use Pleroma.DataCase, async: true + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) +  end + +  describe "creates new app" do +    test "with default scopes" do +      name = "Some name" +      redirect = "https://example.com" +      Mix.Tasks.Pleroma.App.run(["create", "-n", name, "-r", redirect]) + +      assert_app(name, redirect, ["read", "write", "follow", "push"]) +    end + +    test "with custom scopes" do +      name = "Another name" +      redirect = "https://example.com" + +      Mix.Tasks.Pleroma.App.run([ +        "create", +        "-n", +        name, +        "-r", +        redirect, +        "-s", +        "read,write,follow,push,admin" +      ]) + +      assert_app(name, redirect, ["read", "write", "follow", "push", "admin"]) +    end +  end + +  test "with errors" do +    Mix.Tasks.Pleroma.App.run(["create"]) +    {:mix_shell, :error, ["Creating failed:"]} +    {:mix_shell, :error, ["name: can't be blank"]} +    {:mix_shell, :error, ["redirect_uris: can't be blank"]} +  end + +  defp assert_app(name, redirect, scopes) do +    app = Repo.get_by(Pleroma.Web.OAuth.App, client_name: name) + +    assert_receive {:mix_shell, :info, [message]} +    assert message == "#{name} successfully created:" + +    assert_receive {:mix_shell, :info, [message]} +    assert message == "App client_id: #{app.client_id}" + +    assert_receive {:mix_shell, :info, [message]} +    assert message == "App client_secret: #{app.client_secret}" + +    assert app.scopes == scopes +    assert app.redirect_uris == redirect +  end +end diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs new file mode 100644 index 000000000..f36648829 --- /dev/null +++ b/test/mix/tasks/pleroma/config_test.exs @@ -0,0 +1,189 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.ConfigTest do +  use Pleroma.DataCase + +  import Pleroma.Factory + +  alias Pleroma.ConfigDB +  alias Pleroma.Repo + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +      Application.delete_env(:pleroma, :first_setting) +      Application.delete_env(:pleroma, :second_setting) +    end) + +    :ok +  end + +  setup_all do: clear_config(:configurable_from_database, true) + +  test "error if file with custom settings doesn't exist" do +    Mix.Tasks.Pleroma.Config.migrate_to_db("config/not_existance_config_file.exs") + +    assert_receive {:mix_shell, :info, +                    [ +                      "To migrate settings, you must define custom settings in config/not_existance_config_file.exs." +                    ]}, +                   15 +  end + +  describe "migrate_to_db/1" do +    setup do +      initial = Application.get_env(:quack, :level) +      on_exit(fn -> Application.put_env(:quack, :level, initial) end) +    end + +    @tag capture_log: true +    test "config migration refused when deprecated settings are found" do +      clear_config([:media_proxy, :whitelist], ["domain_without_scheme.com"]) +      assert Repo.all(ConfigDB) == [] + +      Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") + +      assert_received {:mix_shell, :error, [message]} + +      assert message =~ +               "Migration is not allowed until all deprecation warnings have been resolved." +    end + +    test "filtered settings are migrated to db" do +      assert Repo.all(ConfigDB) == [] + +      Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") + +      config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) +      config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"}) +      config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"}) +      refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"}) +      refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"}) +      refute ConfigDB.get_by_params(%{group: ":pleroma", key: ":database"}) + +      assert config1.value == [key: "value", key2: [Repo]] +      assert config2.value == [key: "value2", key2: ["Activity"]] +      assert config3.value == :info +    end + +    test "config table is truncated before migration" do +      insert(:config, key: :first_setting, value: [key: "value", key2: ["Activity"]]) +      assert Repo.aggregate(ConfigDB, :count, :id) == 1 + +      Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs") + +      config = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"}) +      assert config.value == [key: "value", key2: [Repo]] +    end +  end + +  describe "with deletion temp file" do +    setup do +      temp_file = "config/temp.exported_from_db.secret.exs" + +      on_exit(fn -> +        :ok = File.rm(temp_file) +      end) + +      {:ok, temp_file: temp_file} +    end + +    test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do +      insert(:config, key: :setting_first, value: [key: "value", key2: ["Activity"]]) +      insert(:config, key: :setting_second, value: [key: "value2", key2: [Repo]]) +      insert(:config, group: :quack, key: :level, value: :info) + +      Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"]) + +      assert Repo.all(ConfigDB) == [] + +      file = File.read!(temp_file) +      assert file =~ "config :pleroma, :setting_first," +      assert file =~ "config :pleroma, :setting_second," +      assert file =~ "config :quack, :level, :info" +    end + +    test "load a settings with large values and pass to file", %{temp_file: temp_file} do +      insert(:config, +        key: :instance, +        value: [ +          name: "Pleroma", +          email: "example@example.com", +          notify_email: "noreply@example.com", +          description: "A Pleroma instance, an alternative fediverse server", +          limit: 5_000, +          chat_limit: 5_000, +          remote_limit: 100_000, +          upload_limit: 16_000_000, +          avatar_upload_limit: 2_000_000, +          background_upload_limit: 4_000_000, +          banner_upload_limit: 4_000_000, +          poll_limits: %{ +            max_options: 20, +            max_option_chars: 200, +            min_expiration: 0, +            max_expiration: 365 * 24 * 60 * 60 +          }, +          registrations_open: true, +          federating: true, +          federation_incoming_replies_max_depth: 100, +          federation_reachability_timeout_days: 7, +          federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher], +          allow_relay: true, +          public: true, +          quarantined_instances: [], +          managed_config: true, +          static_dir: "instance/static/", +          allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"], +          autofollowed_nicknames: [], +          max_pinned_statuses: 1, +          attachment_links: false, +          max_report_comment_size: 1000, +          safe_dm_mentions: false, +          healthcheck: false, +          remote_post_retention_days: 90, +          skip_thread_containment: true, +          limit_to_local_content: :unauthenticated, +          user_bio_length: 5000, +          user_name_length: 100, +          max_account_fields: 10, +          max_remote_account_fields: 20, +          account_field_name_length: 512, +          account_field_value_length: 2048, +          external_user_synchronization: true, +          extended_nickname_format: true, +          multi_factor_authentication: [ +            totp: [ +              digits: 6, +              period: 30 +            ], +            backup_codes: [ +              number: 2, +              length: 6 +            ] +          ] +        ] +      ) + +      Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"]) + +      assert Repo.all(ConfigDB) == [] +      assert File.exists?(temp_file) +      {:ok, file} = File.read(temp_file) + +      header = +        if Code.ensure_loaded?(Config.Reader) do +          "import Config" +        else +          "use Mix.Config" +        end + +      assert file == +               "#{header}\n\nconfig :pleroma, :instance,\n  name: \"Pleroma\",\n  email: \"example@example.com\",\n  notify_email: \"noreply@example.com\",\n  description: \"A Pleroma instance, an alternative fediverse server\",\n  limit: 5000,\n  chat_limit: 5000,\n  remote_limit: 100_000,\n  upload_limit: 16_000_000,\n  avatar_upload_limit: 2_000_000,\n  background_upload_limit: 4_000_000,\n  banner_upload_limit: 4_000_000,\n  poll_limits: %{\n    max_expiration: 31_536_000,\n    max_option_chars: 200,\n    max_options: 20,\n    min_expiration: 0\n  },\n  registrations_open: true,\n  federating: true,\n  federation_incoming_replies_max_depth: 100,\n  federation_reachability_timeout_days: 7,\n  federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n  allow_relay: true,\n  public: true,\n  quarantined_instances: [],\n  managed_config: true,\n  static_dir: \"instance/static/\",\n  allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n  autofollowed_nicknames: [],\n  max_pinned_statuses: 1,\n  attachment_links: false,\n  max_report_comment_size: 1000,\n  safe_dm_mentions: false,\n  healthcheck: false,\n  remote_post_retention_days: 90,\n  skip_thread_containment: true,\n  limit_to_local_content: :unauthenticated,\n  user_bio_length: 5000,\n  user_name_length: 100,\n  max_account_fields: 10,\n  max_remote_account_fields: 20,\n  account_field_name_length: 512,\n  account_field_value_length: 2048,\n  external_user_synchronization: true,\n  extended_nickname_format: true,\n  multi_factor_authentication: [\n    totp: [digits: 6, period: 30],\n    backup_codes: [number: 2, length: 6]\n  ]\n" +    end +  end +end diff --git a/test/mix/tasks/pleroma/count_statuses_test.exs b/test/mix/tasks/pleroma/count_statuses_test.exs new file mode 100644 index 000000000..c5cd16960 --- /dev/null +++ b/test/mix/tasks/pleroma/count_statuses_test.exs @@ -0,0 +1,39 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.CountStatusesTest do +  use Pleroma.DataCase + +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI + +  import ExUnit.CaptureIO, only: [capture_io: 1] +  import Pleroma.Factory + +  test "counts statuses" do +    user = insert(:user) +    {:ok, _} = CommonAPI.post(user, %{status: "test"}) +    {:ok, _} = CommonAPI.post(user, %{status: "test2"}) + +    user2 = insert(:user) +    {:ok, _} = CommonAPI.post(user2, %{status: "test3"}) + +    user = refresh_record(user) +    user2 = refresh_record(user2) + +    assert %{note_count: 2} = user +    assert %{note_count: 1} = user2 + +    {:ok, user} = User.update_note_count(user, 0) +    {:ok, user2} = User.update_note_count(user2, 0) + +    assert %{note_count: 0} = user +    assert %{note_count: 0} = user2 + +    assert capture_io(fn -> Mix.Tasks.Pleroma.CountStatuses.run([]) end) == "Done\n" + +    assert %{note_count: 2} = refresh_record(user) +    assert %{note_count: 1} = refresh_record(user2) +  end +end diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs new file mode 100644 index 000000000..292a5ef5f --- /dev/null +++ b/test/mix/tasks/pleroma/database_test.exs @@ -0,0 +1,175 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.DatabaseTest do +  use Pleroma.DataCase +  use Oban.Testing, repo: Pleroma.Repo + +  alias Pleroma.Activity +  alias Pleroma.Object +  alias Pleroma.Repo +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI + +  import Pleroma.Factory + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) + +    :ok +  end + +  describe "running remove_embedded_objects" do +    test "it replaces objects with references" do +      user = insert(:user) +      {:ok, activity} = CommonAPI.post(user, %{status: "test"}) +      new_data = Map.put(activity.data, "object", activity.object.data) + +      {:ok, activity} = +        activity +        |> Activity.change(%{data: new_data}) +        |> Repo.update() + +      assert is_map(activity.data["object"]) + +      Mix.Tasks.Pleroma.Database.run(["remove_embedded_objects"]) + +      activity = Activity.get_by_id_with_object(activity.id) +      assert is_binary(activity.data["object"]) +    end +  end + +  describe "prune_objects" do +    test "it prunes old objects from the database" do +      insert(:note) +      deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 + +      date = +        Timex.now() +        |> Timex.shift(days: -deadline) +        |> Timex.to_naive_datetime() +        |> NaiveDateTime.truncate(:second) + +      %{id: id} = +        :note +        |> insert() +        |> Ecto.Changeset.change(%{inserted_at: date}) +        |> Repo.update!() + +      assert length(Repo.all(Object)) == 2 + +      Mix.Tasks.Pleroma.Database.run(["prune_objects"]) + +      assert length(Repo.all(Object)) == 1 +      refute Object.get_by_id(id) +    end +  end + +  describe "running update_users_following_followers_counts" do +    test "following and followers count are updated" do +      [user, user2] = insert_pair(:user) +      {:ok, %User{} = user} = User.follow(user, user2) + +      following = User.following(user) + +      assert length(following) == 2 +      assert user.follower_count == 0 + +      {:ok, user} = +        user +        |> Ecto.Changeset.change(%{follower_count: 3}) +        |> Repo.update() + +      assert user.follower_count == 3 + +      assert :ok == Mix.Tasks.Pleroma.Database.run(["update_users_following_followers_counts"]) + +      user = User.get_by_id(user.id) + +      assert length(User.following(user)) == 2 +      assert user.follower_count == 0 +    end +  end + +  describe "running fix_likes_collections" do +    test "it turns OrderedCollection likes into empty arrays" do +      [user, user2] = insert_pair(:user) + +      {:ok, %{id: id, object: object}} = CommonAPI.post(user, %{status: "test"}) +      {:ok, %{object: object2}} = CommonAPI.post(user, %{status: "test test"}) + +      CommonAPI.favorite(user2, id) + +      likes = %{ +        "first" => +          "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1", +        "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes", +        "totalItems" => 3, +        "type" => "OrderedCollection" +      } + +      new_data = Map.put(object2.data, "likes", likes) + +      object2 +      |> Ecto.Changeset.change(%{data: new_data}) +      |> Repo.update() + +      assert length(Object.get_by_id(object.id).data["likes"]) == 1 +      assert is_map(Object.get_by_id(object2.id).data["likes"]) + +      assert :ok == Mix.Tasks.Pleroma.Database.run(["fix_likes_collections"]) + +      assert length(Object.get_by_id(object.id).data["likes"]) == 1 +      assert Enum.empty?(Object.get_by_id(object2.id).data["likes"]) +    end +  end + +  describe "ensure_expiration" do +    test "it adds to expiration old statuses" do +      activity1 = insert(:note_activity) + +      {:ok, inserted_at, 0} = DateTime.from_iso8601("2015-01-23T23:50:07Z") +      activity2 = insert(:note_activity, %{inserted_at: inserted_at}) + +      %{id: activity_id3} = insert(:note_activity) + +      expires_at = DateTime.add(DateTime.utc_now(), 60 * 61) + +      Pleroma.Workers.PurgeExpiredActivity.enqueue(%{ +        activity_id: activity_id3, +        expires_at: expires_at +      }) + +      Mix.Tasks.Pleroma.Database.run(["ensure_expiration"]) + +      assert_enqueued( +        worker: Pleroma.Workers.PurgeExpiredActivity, +        args: %{activity_id: activity1.id}, +        scheduled_at: +          activity1.inserted_at +          |> DateTime.from_naive!("Etc/UTC") +          |> Timex.shift(days: 365) +      ) + +      assert_enqueued( +        worker: Pleroma.Workers.PurgeExpiredActivity, +        args: %{activity_id: activity2.id}, +        scheduled_at: +          activity2.inserted_at +          |> DateTime.from_naive!("Etc/UTC") +          |> Timex.shift(days: 365) +      ) + +      assert_enqueued( +        worker: Pleroma.Workers.PurgeExpiredActivity, +        args: %{activity_id: activity_id3}, +        scheduled_at: expires_at +      ) +    end +  end +end diff --git a/test/mix/tasks/pleroma/digest_test.exs b/test/mix/tasks/pleroma/digest_test.exs new file mode 100644 index 000000000..69dccb745 --- /dev/null +++ b/test/mix/tasks/pleroma/digest_test.exs @@ -0,0 +1,60 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.DigestTest do +  use Pleroma.DataCase + +  import Pleroma.Factory +  import Swoosh.TestAssertions + +  alias Pleroma.Tests.ObanHelpers +  alias Pleroma.Web.CommonAPI + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) + +    :ok +  end + +  setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true) + +  describe "pleroma.digest test" do +    test "Sends digest to the given user" do +      user1 = insert(:user) +      user2 = insert(:user) + +      Enum.each(0..10, fn i -> +        {:ok, _activity} = +          CommonAPI.post(user1, %{ +            status: "hey ##{i} @#{user2.nickname}!" +          }) +      end) + +      yesterday = +        NaiveDateTime.add( +          NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second), +          -60 * 60 * 24, +          :second +        ) + +      {:ok, yesterday_date} = Timex.format(yesterday, "%F", :strftime) + +      :ok = Mix.Tasks.Pleroma.Digest.run(["test", user2.nickname, yesterday_date]) + +      ObanHelpers.perform_all() + +      assert_receive {:mix_shell, :info, [message]} +      assert message =~ "Digest email have been sent" + +      assert_email_sent( +        to: {user2.name, user2.email}, +        html_body: ~r/here is what you've missed!/i +      ) +    end +  end +end diff --git a/test/mix/tasks/pleroma/ecto/migrate_test.exs b/test/mix/tasks/pleroma/ecto/migrate_test.exs new file mode 100644 index 000000000..43df176a1 --- /dev/null +++ b/test/mix/tasks/pleroma/ecto/migrate_test.exs @@ -0,0 +1,20 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-onl + +defmodule Mix.Tasks.Pleroma.Ecto.MigrateTest do +  use Pleroma.DataCase, async: true +  import ExUnit.CaptureLog +  require Logger + +  test "ecto.migrate info message" do +    level = Logger.level() +    Logger.configure(level: :warn) + +    assert capture_log(fn -> +             Mix.Tasks.Pleroma.Ecto.Migrate.run() +           end) =~ "[info] Already up" + +    Logger.configure(level: level) +  end +end diff --git a/test/mix/tasks/pleroma/ecto/rollback_test.exs b/test/mix/tasks/pleroma/ecto/rollback_test.exs new file mode 100644 index 000000000..0236e35d5 --- /dev/null +++ b/test/mix/tasks/pleroma/ecto/rollback_test.exs @@ -0,0 +1,20 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.Ecto.RollbackTest do +  use Pleroma.DataCase +  import ExUnit.CaptureLog +  require Logger + +  test "ecto.rollback info message" do +    level = Logger.level() +    Logger.configure(level: :warn) + +    assert capture_log(fn -> +             Mix.Tasks.Pleroma.Ecto.Rollback.run() +           end) =~ "[info] Rollback succesfully" + +    Logger.configure(level: level) +  end +end diff --git a/test/mix/tasks/pleroma/ecto_test.exs b/test/mix/tasks/pleroma/ecto_test.exs new file mode 100644 index 000000000..3a028df83 --- /dev/null +++ b/test/mix/tasks/pleroma/ecto_test.exs @@ -0,0 +1,15 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.EctoTest do +  use ExUnit.Case, async: true + +  test "raise on bad path" do +    assert_raise RuntimeError, ~r/Could not find migrations directory/, fn -> +      Mix.Tasks.Pleroma.Ecto.ensure_migrations_path(Pleroma.Repo, +        migrations_path: "some-path" +      ) +    end +  end +end diff --git a/test/mix/tasks/pleroma/email_test.exs b/test/mix/tasks/pleroma/email_test.exs new file mode 100644 index 000000000..9523aefd8 --- /dev/null +++ b/test/mix/tasks/pleroma/email_test.exs @@ -0,0 +1,127 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.EmailTest do +  use Pleroma.DataCase + +  import Swoosh.TestAssertions + +  alias Pleroma.Config +  alias Pleroma.Tests.ObanHelpers + +  import Pleroma.Factory + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) + +    :ok +  end + +  setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true) +  setup do: clear_config([:instance, :account_activation_required], true) + +  describe "pleroma.email test" do +    test "Sends test email with no given address" do +      mail_to = Config.get([:instance, :email]) + +      :ok = Mix.Tasks.Pleroma.Email.run(["test"]) + +      ObanHelpers.perform_all() + +      assert_receive {:mix_shell, :info, [message]} +      assert message =~ "Test email has been sent" + +      assert_email_sent( +        to: mail_to, +        html_body: ~r/a test email was requested./i +      ) +    end + +    test "Sends test email with given address" do +      mail_to = "hewwo@example.com" + +      :ok = Mix.Tasks.Pleroma.Email.run(["test", "--to", mail_to]) + +      ObanHelpers.perform_all() + +      assert_receive {:mix_shell, :info, [message]} +      assert message =~ "Test email has been sent" + +      assert_email_sent( +        to: mail_to, +        html_body: ~r/a test email was requested./i +      ) +    end + +    test "Sends confirmation emails" do +      local_user1 = +        insert(:user, %{ +          confirmation_pending: true, +          confirmation_token: "mytoken", +          deactivated: false, +          email: "local1@pleroma.com", +          local: true +        }) + +      local_user2 = +        insert(:user, %{ +          confirmation_pending: true, +          confirmation_token: "mytoken", +          deactivated: false, +          email: "local2@pleroma.com", +          local: true +        }) + +      :ok = Mix.Tasks.Pleroma.Email.run(["resend_confirmation_emails"]) + +      ObanHelpers.perform_all() + +      assert_email_sent(to: {local_user1.name, local_user1.email}) +      assert_email_sent(to: {local_user2.name, local_user2.email}) +    end + +    test "Does not send confirmation email to inappropriate users" do +      # confirmed user +      insert(:user, %{ +        confirmation_pending: false, +        confirmation_token: "mytoken", +        deactivated: false, +        email: "confirmed@pleroma.com", +        local: true +      }) + +      # remote user +      insert(:user, %{ +        deactivated: false, +        email: "remote@not-pleroma.com", +        local: false +      }) + +      # deactivated user = +      insert(:user, %{ +        deactivated: true, +        email: "deactivated@pleroma.com", +        local: false +      }) + +      # invisible user +      insert(:user, %{ +        deactivated: false, +        email: "invisible@pleroma.com", +        local: true, +        invisible: true +      }) + +      :ok = Mix.Tasks.Pleroma.Email.run(["resend_confirmation_emails"]) + +      ObanHelpers.perform_all() + +      refute_email_sent() +    end +  end +end diff --git a/test/mix/tasks/pleroma/emoji_test.exs b/test/mix/tasks/pleroma/emoji_test.exs new file mode 100644 index 000000000..0fb8603ac --- /dev/null +++ b/test/mix/tasks/pleroma/emoji_test.exs @@ -0,0 +1,243 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.EmojiTest do +  use ExUnit.Case, async: true + +  import ExUnit.CaptureIO +  import Tesla.Mock + +  alias Mix.Tasks.Pleroma.Emoji + +  describe "ls-packs" do +    test "with default manifest as url" do +      mock(fn +        %{ +          method: :get, +          url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/fixtures/emoji/packs/default-manifest.json") +          } +      end) + +      capture_io(fn -> Emoji.run(["ls-packs"]) end) =~ +        "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip" +    end + +    test "with passed manifest as file" do +      capture_io(fn -> +        Emoji.run(["ls-packs", "-m", "test/fixtures/emoji/packs/manifest.json"]) +      end) =~ "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip" +    end +  end + +  describe "get-packs" do +    test "download pack from default manifest" do +      mock(fn +        %{ +          method: :get, +          url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/fixtures/emoji/packs/default-manifest.json") +          } + +        %{ +          method: :get, +          url: "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/fixtures/emoji/packs/blank.png.zip") +          } + +        %{ +          method: :get, +          url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/finmoji.json" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/fixtures/emoji/packs/finmoji.json") +          } +      end) + +      assert capture_io(fn -> Emoji.run(["get-packs", "finmoji"]) end) =~ "Writing pack.json for" + +      emoji_path = +        Path.join( +          Pleroma.Config.get!([:instance, :static_dir]), +          "emoji" +        ) + +      assert File.exists?(Path.join([emoji_path, "finmoji", "pack.json"])) +      on_exit(fn -> File.rm_rf!("test/instance_static/emoji/finmoji") end) +    end + +    test "install local emoji pack" do +      assert capture_io(fn -> +               Emoji.run([ +                 "get-packs", +                 "local", +                 "--manifest", +                 "test/instance_static/local_pack/manifest.json" +               ]) +             end) =~ "Writing pack.json for" + +      on_exit(fn -> File.rm_rf!("test/instance_static/emoji/local") end) +    end + +    test "pack not found" do +      mock(fn +        %{ +          method: :get, +          url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/index.json" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/fixtures/emoji/packs/default-manifest.json") +          } +      end) + +      assert capture_io(fn -> Emoji.run(["get-packs", "not_found"]) end) =~ +               "No pack named \"not_found\" found" +    end + +    test "raise on bad sha256" do +      mock(fn +        %{ +          method: :get, +          url: "https://git.pleroma.social/pleroma/emoji-index/raw/master/packs/blobs_gg.zip" +        } -> +          %Tesla.Env{ +            status: 200, +            body: File.read!("test/fixtures/emoji/packs/blank.png.zip") +          } +      end) + +      assert_raise RuntimeError, ~r/^Bad SHA256 for blobs.gg/, fn -> +        capture_io(fn -> +          Emoji.run(["get-packs", "blobs.gg", "-m", "test/fixtures/emoji/packs/manifest.json"]) +        end) +      end +    end +  end + +  describe "gen-pack" do +    setup do +      url = "https://finland.fi/wp-content/uploads/2017/06/finland-emojis.zip" + +      mock(fn %{ +                method: :get, +                url: ^url +              } -> +        %Tesla.Env{status: 200, body: File.read!("test/fixtures/emoji/packs/blank.png.zip")} +      end) + +      {:ok, url: url} +    end + +    test "with default extensions", %{url: url} do +      name = "pack1" +      pack_json = "#{name}.json" +      files_json = "#{name}_file.json" +      refute File.exists?(pack_json) +      refute File.exists?(files_json) + +      captured = +        capture_io(fn -> +          Emoji.run([ +            "gen-pack", +            url, +            "--name", +            name, +            "--license", +            "license", +            "--homepage", +            "homepage", +            "--description", +            "description", +            "--files", +            files_json, +            "--extensions", +            ".png .gif" +          ]) +        end) + +      assert captured =~ "#{pack_json} has been created with the pack1 pack" +      assert captured =~ "Using .png .gif extensions" + +      assert File.exists?(pack_json) +      assert File.exists?(files_json) + +      on_exit(fn -> +        File.rm!(pack_json) +        File.rm!(files_json) +      end) +    end + +    test "with custom extensions and update existing files", %{url: url} do +      name = "pack2" +      pack_json = "#{name}.json" +      files_json = "#{name}_file.json" +      refute File.exists?(pack_json) +      refute File.exists?(files_json) + +      captured = +        capture_io(fn -> +          Emoji.run([ +            "gen-pack", +            url, +            "--name", +            name, +            "--license", +            "license", +            "--homepage", +            "homepage", +            "--description", +            "description", +            "--files", +            files_json, +            "--extensions", +            " .png   .gif    .jpeg " +          ]) +        end) + +      assert captured =~ "#{pack_json} has been created with the pack2 pack" +      assert captured =~ "Using .png .gif .jpeg extensions" + +      assert File.exists?(pack_json) +      assert File.exists?(files_json) + +      captured = +        capture_io(fn -> +          Emoji.run([ +            "gen-pack", +            url, +            "--name", +            name, +            "--license", +            "license", +            "--homepage", +            "homepage", +            "--description", +            "description", +            "--files", +            files_json, +            "--extensions", +            " .png   .gif    .jpeg " +          ]) +        end) + +      assert captured =~ "#{pack_json} has been updated with the pack2 pack" + +      on_exit(fn -> +        File.rm!(pack_json) +        File.rm!(files_json) +      end) +    end +  end +end diff --git a/test/mix/tasks/pleroma/frontend_test.exs b/test/mix/tasks/pleroma/frontend_test.exs new file mode 100644 index 000000000..6f9ec14cd --- /dev/null +++ b/test/mix/tasks/pleroma/frontend_test.exs @@ -0,0 +1,85 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.FrontendTest do +  use Pleroma.DataCase +  alias Mix.Tasks.Pleroma.Frontend + +  import ExUnit.CaptureIO, only: [capture_io: 1] + +  @dir "test/frontend_static_test" + +  setup do +    File.mkdir_p!(@dir) +    clear_config([:instance, :static_dir], @dir) + +    on_exit(fn -> +      File.rm_rf(@dir) +    end) +  end + +  test "it downloads and unzips a known frontend" do +    clear_config([:frontends, :available], %{ +      "pleroma" => %{ +        "ref" => "fantasy", +        "name" => "pleroma", +        "build_url" => "http://gensokyo.2hu/builds/${ref}" +      } +    }) + +    Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/builds/fantasy"} -> +      %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend_dist.zip")} +    end) + +    capture_io(fn -> +      Frontend.run(["install", "pleroma"]) +    end) + +    assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"])) +  end + +  test "it also works given a file" do +    clear_config([:frontends, :available], %{ +      "pleroma" => %{ +        "ref" => "fantasy", +        "name" => "pleroma", +        "build_dir" => "" +      } +    }) + +    folder = Path.join([@dir, "frontends", "pleroma", "fantasy"]) +    previously_existing = Path.join([folder, "temp"]) +    File.mkdir_p!(folder) +    File.write!(previously_existing, "yey") +    assert File.exists?(previously_existing) + +    capture_io(fn -> +      Frontend.run(["install", "pleroma", "--file", "test/fixtures/tesla_mock/frontend.zip"]) +    end) + +    assert File.exists?(Path.join([folder, "test.txt"])) +    refute File.exists?(previously_existing) +  end + +  test "it downloads and unzips unknown frontends" do +    Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} -> +      %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend.zip")} +    end) + +    capture_io(fn -> +      Frontend.run([ +        "install", +        "unknown", +        "--ref", +        "baka", +        "--build-url", +        "http://gensokyo.2hu/madeup.zip", +        "--build-dir", +        "" +      ]) +    end) + +    assert File.exists?(Path.join([@dir, "frontends", "unknown", "baka", "test.txt"])) +  end +end diff --git a/test/mix/tasks/pleroma/instance_test.exs b/test/mix/tasks/pleroma/instance_test.exs new file mode 100644 index 000000000..8a02710ee --- /dev/null +++ b/test/mix/tasks/pleroma/instance_test.exs @@ -0,0 +1,99 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.InstanceTest do +  use ExUnit.Case + +  setup do +    File.mkdir_p!(tmp_path()) + +    on_exit(fn -> +      File.rm_rf(tmp_path()) +      static_dir = Pleroma.Config.get([:instance, :static_dir], "test/instance_static/") + +      if File.exists?(static_dir) do +        File.rm_rf(Path.join(static_dir, "robots.txt")) +      end + +      Pleroma.Config.put([:instance, :static_dir], static_dir) +    end) + +    :ok +  end + +  defp tmp_path do +    "/tmp/generated_files/" +  end + +  test "running gen" do +    mix_task = fn -> +      Mix.Tasks.Pleroma.Instance.run([ +        "gen", +        "--output", +        tmp_path() <> "generated_config.exs", +        "--output-psql", +        tmp_path() <> "setup.psql", +        "--domain", +        "test.pleroma.social", +        "--instance-name", +        "Pleroma", +        "--admin-email", +        "admin@example.com", +        "--notify-email", +        "notify@example.com", +        "--dbhost", +        "dbhost", +        "--dbname", +        "dbname", +        "--dbuser", +        "dbuser", +        "--dbpass", +        "dbpass", +        "--indexable", +        "y", +        "--db-configurable", +        "y", +        "--rum", +        "y", +        "--listen-port", +        "4000", +        "--listen-ip", +        "127.0.0.1", +        "--uploads-dir", +        "test/uploads", +        "--static-dir", +        "./test/../test/instance/static/", +        "--strip-uploads", +        "y", +        "--dedupe-uploads", +        "n", +        "--anonymize-uploads", +        "n" +      ]) +    end + +    ExUnit.CaptureIO.capture_io(fn -> +      mix_task.() +    end) + +    generated_config = File.read!(tmp_path() <> "generated_config.exs") +    assert generated_config =~ "host: \"test.pleroma.social\"" +    assert generated_config =~ "name: \"Pleroma\"" +    assert generated_config =~ "email: \"admin@example.com\"" +    assert generated_config =~ "notify_email: \"notify@example.com\"" +    assert generated_config =~ "hostname: \"dbhost\"" +    assert generated_config =~ "database: \"dbname\"" +    assert generated_config =~ "username: \"dbuser\"" +    assert generated_config =~ "password: \"dbpass\"" +    assert generated_config =~ "configurable_from_database: true" +    assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]" +    assert generated_config =~ "filters: [Pleroma.Upload.Filter.ExifTool]" +    assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql() +    assert File.exists?(Path.expand("./test/instance/static/robots.txt")) +  end + +  defp generated_setup_psql do +    ~s(CREATE USER dbuser WITH ENCRYPTED PASSWORD 'dbpass';\nCREATE DATABASE dbname OWNER dbuser;\n\\c dbname;\n--Extensions made by ecto.migrate that need superuser access\nCREATE EXTENSION IF NOT EXISTS citext;\nCREATE EXTENSION IF NOT EXISTS pg_trgm;\nCREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";\nCREATE EXTENSION IF NOT EXISTS rum;\n) +  end +end diff --git a/test/mix/tasks/pleroma/refresh_counter_cache_test.exs b/test/mix/tasks/pleroma/refresh_counter_cache_test.exs new file mode 100644 index 000000000..6a1a9ac17 --- /dev/null +++ b/test/mix/tasks/pleroma/refresh_counter_cache_test.exs @@ -0,0 +1,43 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.RefreshCounterCacheTest do +  use Pleroma.DataCase +  alias Pleroma.Web.CommonAPI +  import ExUnit.CaptureIO, only: [capture_io: 1] +  import Pleroma.Factory + +  test "counts statuses" do +    user = insert(:user) +    other_user = insert(:user) + +    CommonAPI.post(user, %{visibility: "public", status: "hey"}) + +    Enum.each(0..1, fn _ -> +      CommonAPI.post(user, %{ +        visibility: "unlisted", +        status: "hey" +      }) +    end) + +    Enum.each(0..2, fn _ -> +      CommonAPI.post(user, %{ +        visibility: "direct", +        status: "hey @#{other_user.nickname}" +      }) +    end) + +    Enum.each(0..3, fn _ -> +      CommonAPI.post(user, %{ +        visibility: "private", +        status: "hey" +      }) +    end) + +    assert capture_io(fn -> Mix.Tasks.Pleroma.RefreshCounterCache.run([]) end) =~ "Done\n" + +    assert %{"direct" => 3, "private" => 4, "public" => 1, "unlisted" => 2} = +             Pleroma.Stats.get_status_visibility_count() +  end +end diff --git a/test/mix/tasks/pleroma/relay_test.exs b/test/mix/tasks/pleroma/relay_test.exs new file mode 100644 index 000000000..cf48e7dda --- /dev/null +++ b/test/mix/tasks/pleroma/relay_test.exs @@ -0,0 +1,180 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.RelayTest do +  alias Pleroma.Activity +  alias Pleroma.User +  alias Pleroma.Web.ActivityPub.ActivityPub +  alias Pleroma.Web.ActivityPub.Relay +  alias Pleroma.Web.ActivityPub.Utils +  use Pleroma.DataCase + +  import Pleroma.Factory + +  setup_all do +    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end) + +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) + +    :ok +  end + +  describe "running follow" do +    test "relay is followed" do +      target_instance = "http://mastodon.example.org/users/admin" + +      Mix.Tasks.Pleroma.Relay.run(["follow", target_instance]) + +      local_user = Relay.get_actor() +      assert local_user.ap_id =~ "/relay" + +      target_user = User.get_cached_by_ap_id(target_instance) +      refute target_user.local + +      activity = Utils.fetch_latest_follow(local_user, target_user) +      assert activity.data["type"] == "Follow" +      assert activity.data["actor"] == local_user.ap_id +      assert activity.data["object"] == target_user.ap_id + +      :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) + +      assert_receive {:mix_shell, :info, +                      [ +                        "http://mastodon.example.org/users/admin - no Accept received (relay didn't follow back)" +                      ]} +    end +  end + +  describe "running unfollow" do +    test "relay is unfollowed" do +      user = insert(:user) +      target_instance = user.ap_id + +      Mix.Tasks.Pleroma.Relay.run(["follow", target_instance]) + +      %User{ap_id: follower_id} = local_user = Relay.get_actor() +      target_user = User.get_cached_by_ap_id(target_instance) +      follow_activity = Utils.fetch_latest_follow(local_user, target_user) +      User.follow(local_user, target_user) +      assert "#{target_instance}/followers" in User.following(local_user) +      Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance]) + +      cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"]) +      assert cancelled_activity.data["state"] == "cancelled" + +      [undo_activity] = +        ActivityPub.fetch_activities([], %{ +          type: "Undo", +          actor_id: follower_id, +          limit: 1, +          skip_preload: true, +          invisible_actors: true +        }) + +      assert undo_activity.data["type"] == "Undo" +      assert undo_activity.data["actor"] == local_user.ap_id +      assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"] +      refute "#{target_instance}/followers" in User.following(local_user) +    end + +    test "unfollow when relay is dead" do +      user = insert(:user) +      target_instance = user.ap_id + +      Mix.Tasks.Pleroma.Relay.run(["follow", target_instance]) + +      %User{ap_id: follower_id} = local_user = Relay.get_actor() +      target_user = User.get_cached_by_ap_id(target_instance) +      follow_activity = Utils.fetch_latest_follow(local_user, target_user) +      User.follow(local_user, target_user) + +      assert "#{target_instance}/followers" in User.following(local_user) + +      Tesla.Mock.mock(fn %{method: :get, url: ^target_instance} -> +        %Tesla.Env{status: 404} +      end) + +      Pleroma.Repo.delete(user) +      Cachex.clear(:user_cache) + +      Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance]) + +      cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"]) +      assert cancelled_activity.data["state"] == "accept" + +      assert [] == +               ActivityPub.fetch_activities( +                 [], +                 %{ +                   type: "Undo", +                   actor_id: follower_id, +                   skip_preload: true, +                   invisible_actors: true +                 } +               ) +    end + +    test "force unfollow when relay is dead" do +      user = insert(:user) +      target_instance = user.ap_id + +      Mix.Tasks.Pleroma.Relay.run(["follow", target_instance]) + +      %User{ap_id: follower_id} = local_user = Relay.get_actor() +      target_user = User.get_cached_by_ap_id(target_instance) +      follow_activity = Utils.fetch_latest_follow(local_user, target_user) +      User.follow(local_user, target_user) + +      assert "#{target_instance}/followers" in User.following(local_user) + +      Tesla.Mock.mock(fn %{method: :get, url: ^target_instance} -> +        %Tesla.Env{status: 404} +      end) + +      Pleroma.Repo.delete(user) +      Cachex.clear(:user_cache) + +      Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance, "--force"]) + +      cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"]) +      assert cancelled_activity.data["state"] == "cancelled" + +      [undo_activity] = +        ActivityPub.fetch_activities( +          [], +          %{type: "Undo", actor_id: follower_id, skip_preload: true, invisible_actors: true} +        ) + +      assert undo_activity.data["type"] == "Undo" +      assert undo_activity.data["actor"] == local_user.ap_id +      assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"] +      refute "#{target_instance}/followers" in User.following(local_user) +    end +  end + +  describe "mix pleroma.relay list" do +    test "Prints relay subscription list" do +      :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) + +      refute_receive {:mix_shell, :info, _} + +      relay_user = Relay.get_actor() + +      ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"] +      |> Enum.each(fn ap_id -> +        {:ok, user} = User.get_or_fetch_by_ap_id(ap_id) +        User.follow(relay_user, user) +      end) + +      :ok = Mix.Tasks.Pleroma.Relay.run(["list"]) + +      assert_receive {:mix_shell, :info, ["https://mstdn.io/users/mayuutann"]} +      assert_receive {:mix_shell, :info, ["http://mastodon.example.org/users/admin"]} +    end +  end +end diff --git a/test/mix/tasks/pleroma/robots_txt_test.exs b/test/mix/tasks/pleroma/robots_txt_test.exs new file mode 100644 index 000000000..7040a0e4e --- /dev/null +++ b/test/mix/tasks/pleroma/robots_txt_test.exs @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.RobotsTxtTest do +  use ExUnit.Case +  use Pleroma.Tests.Helpers +  alias Mix.Tasks.Pleroma.RobotsTxt + +  setup do: clear_config([:instance, :static_dir]) + +  test "creates new dir" do +    path = "test/fixtures/new_dir/" +    file_path = path <> "robots.txt" +    Pleroma.Config.put([:instance, :static_dir], path) + +    on_exit(fn -> +      {:ok, ["test/fixtures/new_dir/", "test/fixtures/new_dir/robots.txt"]} = File.rm_rf(path) +    end) + +    RobotsTxt.run(["disallow_all"]) + +    assert File.exists?(file_path) +    {:ok, file} = File.read(file_path) + +    assert file == "User-Agent: *\nDisallow: /\n" +  end + +  test "to existance folder" do +    path = "test/fixtures/" +    file_path = path <> "robots.txt" +    Pleroma.Config.put([:instance, :static_dir], path) + +    on_exit(fn -> +      :ok = File.rm(file_path) +    end) + +    RobotsTxt.run(["disallow_all"]) + +    assert File.exists?(file_path) +    {:ok, file} = File.read(file_path) + +    assert file == "User-Agent: *\nDisallow: /\n" +  end +end diff --git a/test/mix/tasks/pleroma/uploads_test.exs b/test/mix/tasks/pleroma/uploads_test.exs new file mode 100644 index 000000000..d69e149a8 --- /dev/null +++ b/test/mix/tasks/pleroma/uploads_test.exs @@ -0,0 +1,56 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.UploadsTest do +  alias Pleroma.Upload +  use Pleroma.DataCase + +  import Mock + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) + +    :ok +  end + +  describe "running migrate_local" do +    test "uploads migrated" do +      with_mock Upload, +        store: fn %Upload{name: _file, path: _path}, _opts -> {:ok, %{}} end do +        Mix.Tasks.Pleroma.Uploads.run(["migrate_local", "S3"]) + +        assert_received {:mix_shell, :info, [message]} +        assert message =~ "Migrating files from local" + +        assert_received {:mix_shell, :info, [message]} + +        assert %{"total_count" => total_count} = +                 Regex.named_captures(~r"^Found (?<total_count>\d+) uploads$", message) + +        assert_received {:mix_shell, :info, [message]} + +        # @logevery in Mix.Tasks.Pleroma.Uploads +        count = +          min(50, String.to_integer(total_count)) +          |> to_string() + +        assert %{"count" => ^count, "total_count" => ^total_count} = +                 Regex.named_captures( +                   ~r"^Uploaded (?<count>\d+)/(?<total_count>\d+) files$", +                   message +                 ) +      end +    end + +    test "nonexistent uploader" do +      assert_raise RuntimeError, ~r/The uploader .* is not an existing/, fn -> +        Mix.Tasks.Pleroma.Uploads.run(["migrate_local", "nonexistent"]) +      end +    end +  end +end diff --git a/test/mix/tasks/pleroma/user_test.exs b/test/mix/tasks/pleroma/user_test.exs new file mode 100644 index 000000000..b8c423c48 --- /dev/null +++ b/test/mix/tasks/pleroma/user_test.exs @@ -0,0 +1,614 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.UserTest do +  alias Pleroma.Activity +  alias Pleroma.MFA +  alias Pleroma.Object +  alias Pleroma.Repo +  alias Pleroma.Tests.ObanHelpers +  alias Pleroma.User +  alias Pleroma.Web.CommonAPI +  alias Pleroma.Web.OAuth.Authorization +  alias Pleroma.Web.OAuth.Token + +  use Pleroma.DataCase +  use Oban.Testing, repo: Pleroma.Repo + +  import ExUnit.CaptureIO +  import Mock +  import Pleroma.Factory + +  setup_all do +    Mix.shell(Mix.Shell.Process) + +    on_exit(fn -> +      Mix.shell(Mix.Shell.IO) +    end) + +    :ok +  end + +  describe "running new" do +    test "user is created" do +      # just get random data +      unsaved = build(:user) + +      # prepare to answer yes +      send(self(), {:mix_shell_input, :yes?, true}) + +      Mix.Tasks.Pleroma.User.run([ +        "new", +        unsaved.nickname, +        unsaved.email, +        "--name", +        unsaved.name, +        "--bio", +        unsaved.bio, +        "--password", +        "test", +        "--moderator", +        "--admin" +      ]) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "user will be created" + +      assert_received {:mix_shell, :yes?, [message]} +      assert message =~ "Continue" + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "created" + +      user = User.get_cached_by_nickname(unsaved.nickname) +      assert user.name == unsaved.name +      assert user.email == unsaved.email +      assert user.bio == unsaved.bio +      assert user.is_moderator +      assert user.is_admin +    end + +    test "user is not created" do +      unsaved = build(:user) + +      # prepare to answer no +      send(self(), {:mix_shell_input, :yes?, false}) + +      Mix.Tasks.Pleroma.User.run(["new", unsaved.nickname, unsaved.email]) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "user will be created" + +      assert_received {:mix_shell, :yes?, [message]} +      assert message =~ "Continue" + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "will not be created" + +      refute User.get_cached_by_nickname(unsaved.nickname) +    end +  end + +  describe "running rm" do +    test "user is deleted" do +      clear_config([:instance, :federating], true) +      user = insert(:user) + +      with_mock Pleroma.Web.Federator, +        publish: fn _ -> nil end do +        Mix.Tasks.Pleroma.User.run(["rm", user.nickname]) +        ObanHelpers.perform_all() + +        assert_received {:mix_shell, :info, [message]} +        assert message =~ " deleted" +        assert %{deactivated: true} = User.get_by_nickname(user.nickname) + +        assert called(Pleroma.Web.Federator.publish(:_)) +      end +    end + +    test "a remote user's create activity is deleted when the object has been pruned" do +      user = insert(:user) +      user2 = insert(:user) + +      {:ok, post} = CommonAPI.post(user, %{status: "uguu"}) +      {:ok, post2} = CommonAPI.post(user2, %{status: "test"}) +      obj = Object.normalize(post2) + +      {:ok, like_object, meta} = Pleroma.Web.ActivityPub.Builder.like(user, obj) + +      {:ok, like_activity, _meta} = +        Pleroma.Web.ActivityPub.Pipeline.common_pipeline( +          like_object, +          Keyword.put(meta, :local, true) +        ) + +      like_activity.data["object"] +      |> Pleroma.Object.get_by_ap_id() +      |> Repo.delete() + +      clear_config([:instance, :federating], true) + +      object = Object.normalize(post) +      Object.prune(object) + +      with_mock Pleroma.Web.Federator, +        publish: fn _ -> nil end do +        Mix.Tasks.Pleroma.User.run(["rm", user.nickname]) +        ObanHelpers.perform_all() + +        assert_received {:mix_shell, :info, [message]} +        assert message =~ " deleted" +        assert %{deactivated: true} = User.get_by_nickname(user.nickname) + +        assert called(Pleroma.Web.Federator.publish(:_)) +        refute Pleroma.Repo.get(Pleroma.Activity, like_activity.id) +      end + +      refute Activity.get_by_id(post.id) +    end + +    test "no user to delete" do +      Mix.Tasks.Pleroma.User.run(["rm", "nonexistent"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end + +  describe "running toggle_activated" do +    test "user is deactivated" do +      user = insert(:user) + +      Mix.Tasks.Pleroma.User.run(["toggle_activated", user.nickname]) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ " deactivated" + +      user = User.get_cached_by_nickname(user.nickname) +      assert user.deactivated +    end + +    test "user is activated" do +      user = insert(:user, deactivated: true) + +      Mix.Tasks.Pleroma.User.run(["toggle_activated", user.nickname]) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ " activated" + +      user = User.get_cached_by_nickname(user.nickname) +      refute user.deactivated +    end + +    test "no user to toggle" do +      Mix.Tasks.Pleroma.User.run(["toggle_activated", "nonexistent"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No user" +    end +  end + +  describe "running deactivate" do +    test "user is unsubscribed" do +      followed = insert(:user) +      remote_followed = insert(:user, local: false) +      user = insert(:user) + +      User.follow(user, followed, :follow_accept) +      User.follow(user, remote_followed, :follow_accept) + +      Mix.Tasks.Pleroma.User.run(["deactivate", user.nickname]) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Deactivating" + +      # Note that the task has delay :timer.sleep(500) +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Successfully unsubscribed" + +      user = User.get_cached_by_nickname(user.nickname) +      assert Enum.empty?(Enum.filter(User.get_friends(user), & &1.local)) +      assert user.deactivated +    end + +    test "no user to deactivate" do +      Mix.Tasks.Pleroma.User.run(["deactivate", "nonexistent"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No user" +    end +  end + +  describe "running set" do +    test "All statuses set" do +      user = insert(:user) + +      Mix.Tasks.Pleroma.User.run([ +        "set", +        user.nickname, +        "--admin", +        "--confirmed", +        "--locked", +        "--moderator" +      ]) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Admin status .* true/ + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Confirmation pending .* false/ + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Locked status .* true/ + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Moderator status .* true/ + +      user = User.get_cached_by_nickname(user.nickname) +      assert user.is_moderator +      assert user.locked +      assert user.is_admin +      refute user.confirmation_pending +    end + +    test "All statuses unset" do +      user = +        insert(:user, locked: true, is_moderator: true, is_admin: true, confirmation_pending: true) + +      Mix.Tasks.Pleroma.User.run([ +        "set", +        user.nickname, +        "--no-admin", +        "--no-confirmed", +        "--no-locked", +        "--no-moderator" +      ]) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Admin status .* false/ + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Confirmation pending .* true/ + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Locked status .* false/ + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ ~r/Moderator status .* false/ + +      user = User.get_cached_by_nickname(user.nickname) +      refute user.is_moderator +      refute user.locked +      refute user.is_admin +      assert user.confirmation_pending +    end + +    test "no user to set status" do +      Mix.Tasks.Pleroma.User.run(["set", "nonexistent", "--moderator"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end + +  describe "running reset_password" do +    test "password reset token is generated" do +      user = insert(:user) + +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run(["reset_password", user.nickname]) +             end) =~ "URL:" + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated" +    end + +    test "no user to reset password" do +      Mix.Tasks.Pleroma.User.run(["reset_password", "nonexistent"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end + +  describe "running reset_mfa" do +    test "disables MFA" do +      user = +        insert(:user, +          multi_factor_authentication_settings: %MFA.Settings{ +            enabled: true, +            totp: %MFA.Settings.TOTP{secret: "xx", confirmed: true} +          } +        ) + +      Mix.Tasks.Pleroma.User.run(["reset_mfa", user.nickname]) + +      assert_received {:mix_shell, :info, [message]} +      assert message == "Multi-Factor Authentication disabled for #{user.nickname}" + +      assert %{enabled: false, totp: false} == +               user.nickname +               |> User.get_cached_by_nickname() +               |> MFA.mfa_settings() +    end + +    test "no user to reset MFA" do +      Mix.Tasks.Pleroma.User.run(["reset_password", "nonexistent"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end + +  describe "running invite" do +    test "invite token is generated" do +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run(["invite"]) +             end) =~ "http" + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated user invite token one time" +    end + +    test "token is generated with expires_at" do +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "invite", +                 "--expires-at", +                 Date.to_string(Date.utc_today()) +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated user invite token date limited" +    end + +    test "token is generated with max use" do +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "invite", +                 "--max-use", +                 "5" +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated user invite token reusable" +    end + +    test "token is generated with max use and expires date" do +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "invite", +                 "--max-use", +                 "5", +                 "--expires-at", +                 Date.to_string(Date.utc_today()) +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Generated user invite token reusable date limited" +    end +  end + +  describe "running invites" do +    test "invites are listed" do +      {:ok, invite} = Pleroma.UserInviteToken.create_invite() + +      {:ok, invite2} = +        Pleroma.UserInviteToken.create_invite(%{expires_at: Date.utc_today(), max_use: 15}) + +      # assert capture_io(fn -> +      Mix.Tasks.Pleroma.User.run([ +        "invites" +      ]) + +      #  end) + +      assert_received {:mix_shell, :info, [message]} +      assert_received {:mix_shell, :info, [message2]} +      assert_received {:mix_shell, :info, [message3]} +      assert message =~ "Invites list:" +      assert message2 =~ invite.invite_type +      assert message3 =~ invite2.invite_type +    end +  end + +  describe "running revoke_invite" do +    test "invite is revoked" do +      {:ok, invite} = Pleroma.UserInviteToken.create_invite(%{expires_at: Date.utc_today()}) + +      assert capture_io(fn -> +               Mix.Tasks.Pleroma.User.run([ +                 "revoke_invite", +                 invite.token +               ]) +             end) + +      assert_received {:mix_shell, :info, [message]} +      assert message =~ "Invite for token #{invite.token} was revoked." +    end + +    test "it prints an error message when invite is not exist" do +      Mix.Tasks.Pleroma.User.run(["revoke_invite", "foo"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No invite found" +    end +  end + +  describe "running delete_activities" do +    test "activities are deleted" do +      %{nickname: nickname} = insert(:user) + +      assert :ok == Mix.Tasks.Pleroma.User.run(["delete_activities", nickname]) +      assert_received {:mix_shell, :info, [message]} +      assert message == "User #{nickname} statuses deleted." +    end + +    test "it prints an error message when user is not exist" do +      Mix.Tasks.Pleroma.User.run(["delete_activities", "foo"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end + +  describe "running toggle_confirmed" do +    test "user is confirmed" do +      %{id: id, nickname: nickname} = insert(:user, confirmation_pending: false) + +      assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) +      assert_received {:mix_shell, :info, [message]} +      assert message == "#{nickname} needs confirmation." + +      user = Repo.get(User, id) +      assert user.confirmation_pending +      assert user.confirmation_token +    end + +    test "user is not confirmed" do +      %{id: id, nickname: nickname} = +        insert(:user, confirmation_pending: true, confirmation_token: "some token") + +      assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname]) +      assert_received {:mix_shell, :info, [message]} +      assert message == "#{nickname} doesn't need confirmation." + +      user = Repo.get(User, id) +      refute user.confirmation_pending +      refute user.confirmation_token +    end + +    test "it prints an error message when user is not exist" do +      Mix.Tasks.Pleroma.User.run(["toggle_confirmed", "foo"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end + +  describe "search" do +    test "it returns users matching" do +      user = insert(:user) +      moon = insert(:user, nickname: "moon", name: "fediverse expert moon") +      moot = insert(:user, nickname: "moot") +      kawen = insert(:user, nickname: "kawen", name: "fediverse expert moon") + +      {:ok, user} = User.follow(user, moon) + +      assert [moon.id, kawen.id] == User.Search.search("moon") |> Enum.map(& &1.id) + +      res = User.search("moo") |> Enum.map(& &1.id) +      assert Enum.sort([moon.id, moot.id, kawen.id]) == Enum.sort(res) + +      assert [kawen.id, moon.id] == User.Search.search("expert fediverse") |> Enum.map(& &1.id) + +      assert [moon.id, kawen.id] == +               User.Search.search("expert fediverse", for_user: user) |> Enum.map(& &1.id) +    end +  end + +  describe "signing out" do +    test "it deletes all user's tokens and authorizations" do +      user = insert(:user) +      insert(:oauth_token, user: user) +      insert(:oauth_authorization, user: user) + +      assert Repo.get_by(Token, user_id: user.id) +      assert Repo.get_by(Authorization, user_id: user.id) + +      :ok = Mix.Tasks.Pleroma.User.run(["sign_out", user.nickname]) + +      refute Repo.get_by(Token, user_id: user.id) +      refute Repo.get_by(Authorization, user_id: user.id) +    end + +    test "it prints an error message when user is not exist" do +      Mix.Tasks.Pleroma.User.run(["sign_out", "foo"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "No local user" +    end +  end + +  describe "tagging" do +    test "it add tags to a user" do +      user = insert(:user) + +      :ok = Mix.Tasks.Pleroma.User.run(["tag", user.nickname, "pleroma"]) + +      user = User.get_cached_by_nickname(user.nickname) +      assert "pleroma" in user.tags +    end + +    test "it prints an error message when user is not exist" do +      Mix.Tasks.Pleroma.User.run(["tag", "foo"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "Could not change user tags" +    end +  end + +  describe "untagging" do +    test "it deletes tags from a user" do +      user = insert(:user, tags: ["pleroma"]) +      assert "pleroma" in user.tags + +      :ok = Mix.Tasks.Pleroma.User.run(["untag", user.nickname, "pleroma"]) + +      user = User.get_cached_by_nickname(user.nickname) +      assert Enum.empty?(user.tags) +    end + +    test "it prints an error message when user is not exist" do +      Mix.Tasks.Pleroma.User.run(["untag", "foo"]) + +      assert_received {:mix_shell, :error, [message]} +      assert message =~ "Could not change user tags" +    end +  end + +  describe "bulk confirm and unconfirm" do +    test "confirm all" do +      user1 = insert(:user, confirmation_pending: true) +      user2 = insert(:user, confirmation_pending: true) + +      assert user1.confirmation_pending +      assert user2.confirmation_pending + +      Mix.Tasks.Pleroma.User.run(["confirm_all"]) + +      user1 = User.get_cached_by_nickname(user1.nickname) +      user2 = User.get_cached_by_nickname(user2.nickname) + +      refute user1.confirmation_pending +      refute user2.confirmation_pending +    end + +    test "unconfirm all" do +      user1 = insert(:user, confirmation_pending: false) +      user2 = insert(:user, confirmation_pending: false) +      admin = insert(:user, is_admin: true, confirmation_pending: false) +      mod = insert(:user, is_moderator: true, confirmation_pending: false) + +      refute user1.confirmation_pending +      refute user2.confirmation_pending + +      Mix.Tasks.Pleroma.User.run(["unconfirm_all"]) + +      user1 = User.get_cached_by_nickname(user1.nickname) +      user2 = User.get_cached_by_nickname(user2.nickname) +      admin = User.get_cached_by_nickname(admin.nickname) +      mod = User.get_cached_by_nickname(mod.nickname) + +      assert user1.confirmation_pending +      assert user2.confirmation_pending +      refute admin.confirmation_pending +      refute mod.confirmation_pending +    end +  end +end  | 
