X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=test%2Fplugs%2Frate_limiter_test.exs;h=78f1ea9e46c83079c59667a7cf058cb9846ee0d5;hb=a182d400d7d5aa414240b156965533c0e9b222d0;hp=b8d6aff89ce87ebc17342f50a8663ed0d3f72070;hpb=e3534f5b3c68f9bf6a10c5fc10aa637ef66ab82e;p=akkoma diff --git a/test/plugs/rate_limiter_test.exs b/test/plugs/rate_limiter_test.exs index b8d6aff89..78f1ea9e4 100644 --- a/test/plugs/rate_limiter_test.exs +++ b/test/plugs/rate_limiter_test.exs @@ -1,3 +1,7 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.Plugs.RateLimiterTest do use ExUnit.Case, async: true use Plug.Test @@ -6,103 +10,188 @@ defmodule Pleroma.Plugs.RateLimiterTest do import Pleroma.Factory - @limiter_name :testing + # Note: each example must work with separate buckets in order to prevent concurrency issues - test "init/1" do - Pleroma.Config.put([:rate_limit, @limiter_name], {1, 1}) + describe "config" do + test "config is required for plug to work" do + limiter_name = :test_init + Pleroma.Config.put([:rate_limit, limiter_name], {1, 1}) - assert {@limiter_name, {1, 1}} == RateLimiter.init(@limiter_name) - assert nil == RateLimiter.init(:foo) - end + assert %{limits: {1, 1}, name: :test_init, opts: [name: :test_init]} == + RateLimiter.init(name: limiter_name) + + assert nil == RateLimiter.init(name: :foo) + end + + test "it restricts based on config values" do + limiter_name = :test_opts + scale = 80 + limit = 5 + + Pleroma.Config.put([:rate_limit, limiter_name], {scale, limit}) + + opts = RateLimiter.init(name: limiter_name) + conn = conn(:get, "/") + + for i <- 1..5 do + conn = RateLimiter.call(conn, opts) + assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) + Process.sleep(10) + end + + conn = RateLimiter.call(conn, opts) + assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) + assert conn.halted + + Process.sleep(50) + + conn = conn(:get, "/") - test "ip/1" do - assert "127.0.0.1" == RateLimiter.ip(%{remote_ip: {127, 0, 0, 1}}) + conn = RateLimiter.call(conn, opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts) + + refute conn.status == Plug.Conn.Status.code(:too_many_requests) + refute conn.resp_body + refute conn.halted + end end - test "it restricts by opts" do - scale = 1000 - limit = 5 + describe "options" do + test "`bucket_name` option overrides default bucket name" do + limiter_name = :test_bucket_name + + Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5}) + + base_bucket_name = "#{limiter_name}:group1" + opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name) + + conn = conn(:get, "/") + + RateLimiter.call(conn, opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, opts) + assert {:err, :not_found} = RateLimiter.inspect_bucket(conn, limiter_name, opts) + end - Pleroma.Config.put([:rate_limit, @limiter_name], {scale, limit}) + test "`params` option allows different queries to be tracked independently" do + limiter_name = :test_params + Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5}) - opts = RateLimiter.init(@limiter_name) - conn = conn(:get, "/") - bucket_name = "#{@limiter_name}:#{RateLimiter.ip(conn)}" + opts = RateLimiter.init(name: limiter_name, params: ["id"]) - conn = RateLimiter.call(conn, opts) - assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + conn = conn(:get, "/?id=1") + conn = Plug.Conn.fetch_query_params(conn) + conn_2 = conn(:get, "/?id=2") - conn = RateLimiter.call(conn, opts) - assert {2, 3, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + RateLimiter.call(conn, opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, opts) + assert {0, 5} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts) + end - conn = RateLimiter.call(conn, opts) - assert {3, 2, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + test "it supports combination of options modifying bucket name" do + limiter_name = :test_options_combo + Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5}) - conn = RateLimiter.call(conn, opts) - assert {4, 1, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + base_bucket_name = "#{limiter_name}:group1" + opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name, params: ["id"]) + id = "100" - conn = RateLimiter.call(conn, opts) - assert {5, 0, to_reset, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + conn = conn(:get, "/?id=#{id}") + conn = Plug.Conn.fetch_query_params(conn) + conn_2 = conn(:get, "/?id=#{101}") - conn = RateLimiter.call(conn, opts) + RateLimiter.call(conn, opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn, base_bucket_name, opts) + assert {0, 5} = RateLimiter.inspect_bucket(conn_2, base_bucket_name, opts) + end + end + + describe "unauthenticated users" do + test "are restricted based on remote IP" do + limiter_name = :test_unauthenticated + Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 5}, {1, 10}]) + + opts = RateLimiter.init(name: limiter_name) - assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) - assert conn.halted + conn = %{conn(:get, "/") | remote_ip: {127, 0, 0, 2}} + conn_2 = %{conn(:get, "/") | remote_ip: {127, 0, 0, 3}} - Process.sleep(to_reset) + for i <- 1..5 do + conn = RateLimiter.call(conn, opts) + assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) + refute conn.halted + end - conn = conn(:get, "/") + conn = RateLimiter.call(conn, opts) - conn = RateLimiter.call(conn, opts) - assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) + assert conn.halted - refute conn.status == Plug.Conn.Status.code(:too_many_requests) - refute conn.resp_body - refute conn.halted + conn_2 = RateLimiter.call(conn_2, opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts) + + refute conn_2.status == Plug.Conn.Status.code(:too_many_requests) + refute conn_2.resp_body + refute conn_2.halted + end end - test "optional limits for authenticated users" do - Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo) + describe "authenticated users" do + setup do + Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo) + + :ok + end - scale = 1000 - limit = 5 - Pleroma.Config.put([:rate_limit, @limiter_name], [{1, 10}, {scale, limit}]) + test "can have limits seperate from unauthenticated connections" do + limiter_name = :test_authenticated - opts = RateLimiter.init(@limiter_name) + scale = 50 + limit = 5 + Pleroma.Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}]) - user = insert(:user) - conn = conn(:get, "/") |> assign(:user, user) - bucket_name = "#{@limiter_name}:#{user.id}" + opts = RateLimiter.init(name: limiter_name) - conn = RateLimiter.call(conn, opts) - assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + user = insert(:user) + conn = conn(:get, "/") |> assign(:user, user) - conn = RateLimiter.call(conn, opts) - assert {2, 3, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + for i <- 1..5 do + conn = RateLimiter.call(conn, opts) + assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) + refute conn.halted + end - conn = RateLimiter.call(conn, opts) - assert {3, 2, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + conn = RateLimiter.call(conn, opts) - conn = RateLimiter.call(conn, opts) - assert {4, 1, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) + assert conn.halted + end - conn = RateLimiter.call(conn, opts) - assert {5, 0, to_reset, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + test "diffrerent users are counted independently" do + limiter_name = :test_authenticated + Pleroma.Config.put([:rate_limit, limiter_name], [{1, 10}, {1000, 5}]) - conn = RateLimiter.call(conn, opts) + opts = RateLimiter.init(name: limiter_name) - assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) - assert conn.halted + user = insert(:user) + conn = conn(:get, "/") |> assign(:user, user) - Process.sleep(to_reset) + user_2 = insert(:user) + conn_2 = conn(:get, "/") |> assign(:user, user_2) - conn = conn(:get, "/") |> assign(:user, user) + for i <- 1..5 do + conn = RateLimiter.call(conn, opts) + assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, opts) + end - conn = RateLimiter.call(conn, opts) - assert {1, 4, _, _, _} = ExRated.inspect_bucket(bucket_name, scale, limit) + conn = RateLimiter.call(conn, opts) + assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) + assert conn.halted - refute conn.status == Plug.Conn.Status.code(:too_many_requests) - refute conn.resp_body - refute conn.halted + conn_2 = RateLimiter.call(conn_2, opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn_2, limiter_name, opts) + refute conn_2.status == Plug.Conn.Status.code(:too_many_requests) + refute conn_2.resp_body + refute conn_2.halted + end end end