tests for mastodon_api_controller.ex
authorMaksim Pechnikov <parallel588@gmail.com>
Fri, 6 Sep 2019 18:50:00 +0000 (21:50 +0300)
committerMaksim Pechnikov <parallel588@gmail.com>
Fri, 6 Sep 2019 18:50:00 +0000 (21:50 +0300)
lib/pleroma/object.ex
lib/pleroma/user.ex
lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
lib/pleroma/web/oauth/app.ex
lib/pleroma/web/twitter_api/twitter_api.ex
test/web/mastodon_api/mastodon_api_controller_test.exs
test/web/oauth/app_test.exs [new file with mode: 0644]

index d58eb7f7deeb8e9734cd339fe98faa8c992b95ac..4398b973915626ff53795cbf016ca4543d7e7620 100644 (file)
@@ -228,4 +228,11 @@ defmodule Pleroma.Object do
       _ -> :noop
     end
   end
+
+  @doc "Updates data field of an object"
+  def update_data(%Object{data: data} = object, attrs \\ %{}) do
+    object
+    |> Object.change(%{data: Map.merge(data || %{}, attrs)})
+    |> Repo.update()
+  end
 end
index 3aa245f2aa43f60389fc8a8f43023de09a39268e..d9db985a65b75ae3aead2a4807163e8d04812677 100644 (file)
@@ -499,6 +499,11 @@ defmodule Pleroma.User do
     |> Repo.all()
   end
 
+  def get_all_by_ids(ids) do
+    from(u in __MODULE__, where: u.id in ^ids)
+    |> Repo.all()
+  end
+
   # This is mostly an SPC migration fix. This guesses the user nickname by taking the last part
   # of the ap_id and the domain and tries to get that user
   def get_by_guessed_nickname(ap_id) do
@@ -770,6 +775,19 @@ defmodule Pleroma.User do
     |> update_and_set_cache()
   end
 
+  def update_mascot(user, url) do
+    info_changeset =
+      User.Info.mascot_update(
+        user.info,
+        url
+      )
+
+    user
+    |> change()
+    |> put_embed(:info, info_changeset)
+    |> update_and_set_cache()
+  end
+
   @spec maybe_fetch_follow_information(User.t()) :: User.t()
   def maybe_fetch_follow_information(user) do
     with {:ok, user} <- fetch_follow_information(user) do
@@ -917,9 +935,7 @@ defmodule Pleroma.User do
 
   def unsubscribe(unsubscriber, %{ap_id: ap_id}) do
     with %User{} = user <- get_cached_by_ap_id(ap_id) do
-      info_cng =
-        user.info
-        |> User.Info.remove_from_subscribers(unsubscriber.ap_id)
+      info_cng = User.Info.remove_from_subscribers(user.info, unsubscriber.ap_id)
 
       change(user)
       |> put_embed(:info, info_cng)
index 8dfad7a54e8d695c664508c6398e269b201e76e6..e4e0a7ac979efa96696894bd9ec3529b2f659ef8 100644 (file)
@@ -447,8 +447,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
          grouped_activities <- Enum.group_by(activities, fn %{id: id} -> id < activity.id end) do
       result = %{
         ancestors:
-          StatusView.render(
-            "index.json",
+          StatusView.render("index.json",
             for: user,
             activities: grouped_activities[true] || [],
             as: :activity
@@ -456,8 +455,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
           |> Enum.reverse(),
         # credo:disable-for-previous-line Credo.Check.Refactor.PipeChainStart
         descendants:
-          StatusView.render(
-            "index.json",
+          StatusView.render("index.json",
             for: user,
             activities: grouped_activities[false] || [],
             as: :activity
@@ -746,9 +744,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def relationships(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    id = List.wrap(id)
-    q = from(u in User, where: u.id in ^id)
-    targets = Repo.all(q)
+    targets = User.get_all_by_ids(List.wrap(id))
 
     conn
     |> put_view(AccountView)
@@ -758,19 +754,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   # Instead of returning a 400 when no "id" params is present, Mastodon returns an empty array.
   def relationships(%{assigns: %{user: _user}} = conn, _), do: json(conn, [])
 
-  def update_media(%{assigns: %{user: user}} = conn, data) do
-    with %Object{} = object <- Repo.get(Object, data["id"]),
+  def update_media(
+        %{assigns: %{user: user}} = conn,
+        %{"id" => id, "description" => description} = _
+      )
+      when is_binary(description) do
+    with %Object{} = object <- Repo.get(Object, id),
          true <- Object.authorize_mutation(object, user),
-         true <- is_binary(data["description"]),
-         description <- data["description"] do
-      new_data = %{object.data | "name" => description}
-
-      {:ok, _} =
-        object
-        |> Object.change(%{data: new_data})
-        |> Repo.update()
-
-      attachment_data = Map.put(new_data, "id", object.id)
+         {:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do
+      attachment_data = Map.put(data, "id", object.id)
 
       conn
       |> put_view(StatusView)
@@ -778,6 +770,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
+  def update_media(_conn, _data), do: {:error, :bad_request}
+
   def upload(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
     with {:ok, object} <-
            ActivityPub.upload(
@@ -796,34 +790,23 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   def set_mascot(%{assigns: %{user: user}} = conn, %{"file" => file}) do
     with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)),
          %{} = attachment_data <- Map.put(object.data, "id", object.id),
-         %{type: type} = rendered <-
-           StatusView.render("attachment.json", %{attachment: attachment_data}) do
-      # Reject if not an image
-      if type == "image" do
-        # Sure!
-        # Save to the user's info
-        info_changeset = User.Info.mascot_update(user.info, rendered)
-
-        user_changeset =
-          user
-          |> Changeset.change()
-          |> Changeset.put_embed(:info, info_changeset)
-
-        {:ok, _user} = User.update_and_set_cache(user_changeset)
-
-        conn
-        |> json(rendered)
-      else
+         %{type: "image"} = rendered <-
+           StatusView.render("attachment.json", %{attachment: attachment_data}),
+         {:ok, _user} = User.update_mascot(user, rendered) do
+      json(conn, rendered)
+    else
+      %{type: _type} = _ ->
         render_error(conn, :unsupported_media_type, "mascots can only be images")
-      end
+
+      e ->
+        e
     end
   end
 
   def get_mascot(%{assigns: %{user: user}} = conn, _params) do
     mascot = User.get_mascot(user)
 
-    conn
-    |> json(mascot)
+    json(conn, mascot)
   end
 
   def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do
@@ -1119,10 +1102,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
       |> put_view(AccountView)
       |> render("relationship.json", %{user: user, target: subscription_target})
     else
-      {:error, message} ->
-        conn
-        |> put_status(:forbidden)
-        |> json(%{error: message})
+      nil -> {:error, :not_found}
+      e -> e
     end
   end
 
@@ -1133,10 +1114,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
       |> put_view(AccountView)
       |> render("relationship.json", %{user: user, target: subscription_target})
     else
-      {:error, message} ->
-        conn
-        |> put_status(:forbidden)
-        |> json(%{error: message})
+      nil -> {:error, :not_found}
+      e -> e
     end
   end
 
@@ -1207,8 +1186,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 
   def account_lists(%{assigns: %{user: user}} = conn, %{"id" => account_id}) do
     lists = Pleroma.List.get_lists_account_belongs(user, account_id)
-    res = ListView.render("lists.json", lists: lists)
-    json(conn, res)
+
+    conn
+    |> put_view(ListView)
+    |> render("index.json", %{lists: lists})
   end
 
   def list_timeline(%{assigns: %{user: user}} = conn, %{"list_id" => id} = params) do
@@ -1363,7 +1344,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   @doc "Local Mastodon FE login init action"
   def login(conn, %{"code" => auth_token}) do
     with {:ok, app} <- get_or_make_app(),
-         %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id),
+         {:ok, auth} <- Authorization.get_by_token(app, auth_token),
          {:ok, token} <- Token.exchange_token(app, auth) do
       conn
       |> put_session(:oauth_token, token.token)
@@ -1375,9 +1356,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   def login(conn, _) do
     with {:ok, app} <- get_or_make_app() do
       path =
-        o_auth_path(
-          conn,
-          :authorize,
+        o_auth_path(conn, :authorize,
           response_type: "code",
           client_id: app.client_id,
           redirect_uri: ".",
@@ -1399,31 +1378,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
+  @spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
   defp get_or_make_app do
-    find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
-    scopes = ["read", "write", "follow", "push"]
-
-    with %App{} = app <- Repo.get_by(App, find_attrs) do
-      {:ok, app} =
-        if app.scopes == scopes do
-          {:ok, app}
-        else
-          app
-          |> Changeset.change(%{scopes: scopes})
-          |> Repo.update()
-        end
-
-      {:ok, app}
-    else
-      _e ->
-        cs =
-          App.register_changeset(
-            %App{},
-            Map.put(find_attrs, :scopes, scopes)
-          )
-
-        Repo.insert(cs)
-    end
+    App.get_or_make(
+      %{client_name: @local_mastodon_name, redirect_uris: "."},
+      ["read", "write", "follow", "push"]
+    )
   end
 
   def logout(conn, _) do
@@ -1432,26 +1392,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     |> redirect(to: "/")
   end
 
-  def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    Logger.debug("Unimplemented, returning unmodified relationship")
-
-    with %User{} = target <- User.get_cached_by_id(id) do
-      conn
-      |> put_view(AccountView)
-      |> render("relationship.json", %{user: user, target: target})
-    end
-  end
-
+  # Stubs for unimplemented mastodon api
+  #
   def empty_array(conn, _) do
     Logger.debug("Unimplemented, returning an empty array")
     json(conn, [])
   end
 
-  def empty_object(conn, _) do
-    Logger.debug("Unimplemented, returning an empty object")
-    json(conn, %{})
-  end
-
   def get_filters(%{assigns: %{user: user}} = conn, _) do
     filters = Filter.get_filters(user)
     res = FilterView.render("filters.json", filters: filters)
@@ -1570,7 +1517,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
       json(conn, data)
     else
       _e ->
-        %{}
+        json(conn, %{})
     end
   end
 
@@ -1623,7 +1570,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  def account_register(%{assigns: %{app: _app}} = conn, _params) do
+  def account_register(%{assigns: %{app: _app}} = conn, _) do
     render_error(conn, :bad_request, "Missing parameters")
   end
 
@@ -1682,15 +1629,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  def try_render(conn, target, params)
-      when is_binary(target) do
+  defp try_render(conn, target, params)
+       when is_binary(target) do
     case render(conn, target, params) do
       nil -> render_error(conn, :not_implemented, "Can't display this activity")
       res -> res
     end
   end
 
-  def try_render(conn, _, _) do
+  defp try_render(conn, _, _) do
     render_error(conn, :not_implemented, "Can't display this activity")
   end
 
index ddcdb18718b39c7486b3dee5a871145bcb965001..cc3fb1ce55e992796fa587f253a61c0523f8dfa1 100644 (file)
@@ -5,6 +5,7 @@
 defmodule Pleroma.Web.OAuth.App do
   use Ecto.Schema
   import Ecto.Changeset
+  alias Pleroma.Repo
 
   @type t :: %__MODULE__{}
 
@@ -39,4 +40,29 @@ defmodule Pleroma.Web.OAuth.App do
       changeset
     end
   end
+
+  @doc """
+  Gets app by attrs or create new  with attrs.
+  And updates the scopes if need.
+  """
+  @spec get_or_make(map(), list(String.t())) :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
+  def get_or_make(attrs, scopes) do
+    with %__MODULE__{} = app <- Repo.get_by(__MODULE__, attrs) do
+      update_scopes(app, scopes)
+    else
+      _e ->
+        %__MODULE__{}
+        |> register_changeset(Map.put(attrs, :scopes, scopes))
+        |> Repo.insert()
+    end
+  end
+
+  defp update_scopes(%__MODULE__{} = app, []), do: {:ok, app}
+  defp update_scopes(%__MODULE__{scopes: scopes} = app, scopes), do: {:ok, app}
+
+  defp update_scopes(%__MODULE__{} = app, scopes) do
+    app
+    |> change(%{scopes: scopes})
+    |> Repo.update()
+  end
 end
index 8eda762c72e7ac04e88ae9664d7876202fb632b0..bfd83890239e470b3ae5f58f882deb8bb923736e 100644 (file)
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
     captcha_enabled = Pleroma.Config.get([Pleroma.Captcha, :enabled])
     # true if captcha is disabled or enabled and valid, false otherwise
     captcha_ok =
-      if !captcha_enabled do
+      if not captcha_enabled do
         :ok
       else
         Pleroma.Captcha.validate(
index e18f8f0d1df842035d08ab14f8738204c07adab2..a331d6455401ac44ab6d76978e989b12c159e6d0 100644 (file)
@@ -1551,6 +1551,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert to_string(other_user.id) == relationship["id"]
     end
+
+    test "returns an empty list when bad request", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/relationships", %{})
+
+      assert [] = json_response(conn, 200)
+    end
   end
 
   describe "media upload" do
@@ -1752,70 +1763,72 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
-  test "mascot upload", %{conn: conn} do
-    user = insert(:user)
+  describe "/api/v1/pleroma/mascot" do
+    test "mascot upload", %{conn: conn} do
+      user = insert(:user)
 
-    non_image_file = %Plug.Upload{
-      content_type: "audio/mpeg",
-      path: Path.absname("test/fixtures/sound.mp3"),
-      filename: "sound.mp3"
-    }
+      non_image_file = %Plug.Upload{
+        content_type: "audio/mpeg",
+        path: Path.absname("test/fixtures/sound.mp3"),
+        filename: "sound.mp3"
+      }
 
-    conn =
-      conn
-      |> assign(:user, user)
-      |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
+      conn =
+        conn
+        |> assign(:user, user)
+        |> put("/api/v1/pleroma/mascot", %{"file" => non_image_file})
 
-    assert json_response(conn, 415)
+      assert json_response(conn, 415)
 
-    file = %Plug.Upload{
-      content_type: "image/jpg",
-      path: Path.absname("test/fixtures/image.jpg"),
-      filename: "an_image.jpg"
-    }
+      file = %Plug.Upload{
+        content_type: "image/jpg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
 
-    conn =
-      build_conn()
-      |> assign(:user, user)
-      |> put("/api/v1/pleroma/mascot", %{"file" => file})
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> put("/api/v1/pleroma/mascot", %{"file" => file})
 
-    assert %{"id" => _, "type" => image} = json_response(conn, 200)
-  end
+      assert %{"id" => _, "type" => image} = json_response(conn, 200)
+    end
 
-  test "mascot retrieving", %{conn: conn} do
-    user = insert(:user)
-    # When user hasn't set a mascot, we should just get pleroma tan back
-    conn =
-      conn
-      |> assign(:user, user)
-      |> get("/api/v1/pleroma/mascot")
+    test "mascot retrieving", %{conn: conn} do
+      user = insert(:user)
+      # When user hasn't set a mascot, we should just get pleroma tan back
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/pleroma/mascot")
 
-    assert %{"url" => url} = json_response(conn, 200)
-    assert url =~ "pleroma-fox-tan-smol"
+      assert %{"url" => url} = json_response(conn, 200)
+      assert url =~ "pleroma-fox-tan-smol"
 
-    # When a user sets their mascot, we should get that back
-    file = %Plug.Upload{
-      content_type: "image/jpg",
-      path: Path.absname("test/fixtures/image.jpg"),
-      filename: "an_image.jpg"
-    }
+      # When a user sets their mascot, we should get that back
+      file = %Plug.Upload{
+        content_type: "image/jpg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
 
-    conn =
-      build_conn()
-      |> assign(:user, user)
-      |> put("/api/v1/pleroma/mascot", %{"file" => file})
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> put("/api/v1/pleroma/mascot", %{"file" => file})
 
-    assert json_response(conn, 200)
+      assert json_response(conn, 200)
 
-    user = User.get_cached_by_id(user.id)
+      user = User.get_cached_by_id(user.id)
 
-    conn =
-      build_conn()
-      |> assign(:user, user)
-      |> get("/api/v1/pleroma/mascot")
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> get("/api/v1/pleroma/mascot")
 
-    assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
-    assert url =~ "an_image"
+      assert %{"url" => url, "type" => "image"} = json_response(conn, 200)
+      assert url =~ "an_image"
+    end
   end
 
   test "hashtag timeline", %{conn: conn} do
@@ -2183,23 +2196,51 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
-  test "subscribing / unsubscribing to a user", %{conn: conn} do
-    user = insert(:user)
-    subscription_target = insert(:user)
+  describe "subscribing / unsubscribing" do
+    test "subscribing / unsubscribing to a user", %{conn: conn} do
+      user = insert(:user)
+      subscription_target = insert(:user)
 
-    conn =
-      conn
-      |> assign(:user, user)
-      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
 
-    assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
+      assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
 
-    conn =
-      build_conn()
-      |> assign(:user, user)
-      |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
+      conn =
+        build_conn()
+        |> assign(:user, user)
+        |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
+
+      assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
+    end
+  end
+
+  describe "subscribing" do
+    test "returns 404 when subscription_target not found", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/pleroma/accounts/target_id/subscribe")
+
+      assert %{"error" => "Record not found"} = json_response(conn, 404)
+    end
+  end
+
+  describe "unsubscribing" do
+    test "returns 404 when subscription_target not found", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/pleroma/accounts/target_id/unsubscribe")
 
-    assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
+      assert %{"error" => "Record not found"} = json_response(conn, 404)
+    end
   end
 
   test "getting a list of mutes", %{conn: conn} do
@@ -2814,6 +2855,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
                }
              }
     end
+
+    test "returns empty object when id invalid", %{conn: conn} do
+      response =
+        conn
+        |> get("/api/v1/statuses/9eoozpwTul5mjSEDRI/card")
+        |> json_response(200)
+
+      assert response == %{}
+    end
   end
 
   test "bookmarks" do
@@ -3133,6 +3183,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       assert conn.status == 302
       assert redirected_to(conn) == path
     end
+  end
+
+  describe "GET /web/login" do
+    test "redirects to /oauth/authorize", %{conn: conn} do
+      app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
+      conn = get(conn, "/web/login", %{})
+
+      assert conn.status == 302
+
+      assert redirected_to(conn) ==
+               "/oauth/authorize?response_type=code&client_id=#{app.client_id}&redirect_uri=.&scope=read+write+follow+push"
+    end
 
     test "redirects to the getting-started page when referer is not present", %{conn: conn} do
       app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
@@ -3143,6 +3205,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       assert conn.status == 302
       assert redirected_to(conn) == "/web/getting-started"
     end
+
+    test "redirects to the getting-started page when user assigned", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/web/login", %{})
+
+      assert conn.status == 302
+      assert redirected_to(conn) == "/web/getting-started"
+    end
   end
 
   describe "scheduled activities" do
@@ -3401,6 +3475,17 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   end
 
   describe "create account by app" do
+    setup do
+      valid_params = %{
+        username: "lain",
+        email: "lain@example.org",
+        password: "PlzDontHackLain",
+        agreement: true
+      }
+
+      [valid_params: valid_params]
+    end
+
     test "Account registration via Application", %{conn: conn} do
       conn =
         conn
@@ -3444,6 +3529,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
           username: "lain",
           email: "lain@example.org",
           password: "PlzDontHackLain",
+          bio: "Test Bio",
           agreement: true
         })
 
@@ -3462,6 +3548,18 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       assert token_from_db.user.info.confirmation_pending
     end
 
+    test "returns error when user already registred", %{conn: conn, valid_params: valid_params} do
+      _user = insert(:user, email: "lain@example.org")
+      app_token = insert(:oauth_token, user: nil)
+
+      conn =
+        conn
+        |> put_req_header("authorization", "Bearer " <> app_token.token)
+
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 400) == %{"error" => "{\"email\":[\"has already been taken\"]}"}
+    end
+
     test "rate limit", %{conn: conn} do
       app_token = insert(:oauth_token, user: nil)
 
@@ -3505,6 +3603,41 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert json_response(conn, :too_many_requests) == %{"error" => "Throttled"}
     end
+
+    test "returns bad_request if missing required params", %{
+      conn: conn,
+      valid_params: valid_params
+    } do
+      app_token = insert(:oauth_token, user: nil)
+
+      conn =
+        conn
+        |> put_req_header("authorization", "Bearer " <> app_token.token)
+
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 200)
+
+      Enum.each(valid_params, fn {attr, _} ->
+        res =
+          conn
+          |> Map.put(
+            :remote_ip,
+            {:rand.uniform(15), :rand.uniform(15), :rand.uniform(15), :rand.uniform(15)}
+          )
+          |> post("/api/v1/accounts", Map.delete(valid_params, attr))
+
+        assert json_response(res, 400) == %{"error" => "Missing parameters"}
+      end)
+    end
+
+    test "returns forbidden if token is invalid", %{conn: conn, valid_params: valid_params} do
+      conn =
+        conn
+        |> put_req_header("authorization", "Bearer " <> "invalid-token")
+
+      res = post(conn, "/api/v1/accounts", valid_params)
+      assert json_response(res, 403) == %{"error" => "Invalid credentials"}
+    end
   end
 
   describe "GET /api/v1/polls/:id" do
@@ -3988,4 +4121,115 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
              ]
     end
   end
+
+  describe "PUT /api/v1/media/:id" do
+    setup do
+      actor = insert(:user)
+
+      file = %Plug.Upload{
+        content_type: "image/jpg",
+        path: Path.absname("test/fixtures/image.jpg"),
+        filename: "an_image.jpg"
+      }
+
+      {:ok, %Object{} = object} =
+        ActivityPub.upload(
+          file,
+          actor: User.ap_id(actor),
+          description: "test-m"
+        )
+
+      [actor: actor, object: object]
+    end
+
+    test "updates name of media", %{conn: conn, actor: actor, object: object} do
+      media =
+        conn
+        |> assign(:user, actor)
+        |> put("/api/v1/media/#{object.id}", %{"description" => "test-media"})
+        |> json_response(:ok)
+
+      assert media["description"] == "test-media"
+      assert refresh_record(object).data["name"] == "test-media"
+    end
+
+    test "returns error wheb request is bad", %{conn: conn, actor: actor, object: object} do
+      media =
+        conn
+        |> assign(:user, actor)
+        |> put("/api/v1/media/#{object.id}", %{})
+        |> json_response(400)
+
+      assert media == %{"error" => "bad_request"}
+    end
+  end
+
+  describe "DELETE /auth/sign_out" do
+    test "redirect to root page", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> delete("/auth/sign_out")
+
+      assert conn.status == 302
+      assert redirected_to(conn) == "/"
+    end
+  end
+
+  describe "GET /api/v1/accounts/:id/lists - account_lists" do
+    test "returns lists to which the account belongs", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+      assert {:ok, %Pleroma.List{} = list} = Pleroma.List.create("Test List", user)
+      {:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
+
+      res =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/#{other_user.id}/lists")
+        |> json_response(200)
+
+      assert res == [%{"id" => to_string(list.id), "title" => "Test List"}]
+    end
+  end
+
+  describe "empty_array, stubs for mastodon api" do
+    test "GET /api/v1/accounts/:id/identity_proofs", %{conn: conn} do
+      user = insert(:user)
+
+      res =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/accounts/#{user.id}/identity_proofs")
+        |> json_response(200)
+
+      assert res == []
+    end
+
+    test "GET /api/v1/endorsements", %{conn: conn} do
+      user = insert(:user)
+
+      res =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/endorsements")
+        |> json_response(200)
+
+      assert res == []
+    end
+
+    test "GET /api/v1/trends", %{conn: conn} do
+      user = insert(:user)
+
+      res =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/trends")
+        |> json_response(200)
+
+      assert res == []
+    end
+  end
 end
diff --git a/test/web/oauth/app_test.exs b/test/web/oauth/app_test.exs
new file mode 100644 (file)
index 0000000..195b8c1
--- /dev/null
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.OAuth.AppTest do
+  use Pleroma.DataCase
+
+  alias Pleroma.Web.OAuth.App
+  import Pleroma.Factory
+
+  describe "get_or_make/2" do
+    test "gets exist app" do
+      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
+      app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]}))
+      {:ok, %App{} = exist_app} = App.get_or_make(attrs, [])
+      assert exist_app == app
+    end
+
+    test "make app" do
+      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
+      {:ok, %App{} = app} = App.get_or_make(attrs, ["write"])
+      assert app.scopes == ["write"]
+    end
+
+    test "gets exist app and updates scopes" do
+      attrs = %{client_name: "Mastodon-Local", redirect_uris: "."}
+      app = insert(:oauth_app, Map.merge(attrs, %{scopes: ["read", "write"]}))
+      {:ok, %App{} = exist_app} = App.get_or_make(attrs, ["read", "write", "follow", "push"])
+      assert exist_app.id == app.id
+      assert exist_app.scopes == ["read", "write", "follow", "push"]
+    end
+  end
+end