PSPDFKit-labs/bypass

Bypass hangs in Bypass.do_verify_expectations/2 when using hackney inside a task with a timeout

開放

#75 建立於 2019年1月15日

 (1 則留言) (0 個反應) (0 位負責人)Elixir (89 個分叉)batch import
help wanted

倉庫指標

星標
 (847 顆星)
PR 合併指標
 (30 天內沒有已合併 PR)

描述

I want to test that I'm able to abort a request that takes too long for any reason. I decided to use a task to wrap my request, the task is shut down after a timeout. I use bypass in my test to simulate a request that takes longer than the timeout value.

When using httpc to make the request the test succeeds. When using hackney to make the request, the test hangs in Bypass.do_verify_expectations/2.

I use {:hackney, "~> 1.15"} and {:bypass, "~> 1.0.0", only: :test}. Below is the test runner output and the code for the two tests.

1) test bypass with hackney (HackneyBypassTest)
     test/peertube_index/hackney_bypass_test.exs:5
     ** (ExUnit.TimeoutError) on_exit callback timed out after 2000ms. You can change the timeout:
     
       1. per test by setting "@tag timeout: x"
       2. per case by setting "@moduletag timeout: x"
       3. globally via "ExUnit.start(timeout: x)" configuration
       4. or set it to infinity per run by calling "mix test --trace"
          (useful when using IEx.pry)
     
     Timeouts are given as integers in milliseconds.
     
     stacktrace:
       (stdlib) gen.erl:169: :gen.do_call/4
       (elixir) lib/gen_server.ex:921: GenServer.call/3
       (bypass) lib/bypass.ex:71: Bypass.do_verify_expectations/2
       (ex_unit) lib/ex_unit/on_exit_handler.ex:140: ExUnit.OnExitHandler.exec_callback/1
       (ex_unit) lib/ex_unit/on_exit_handler.ex:126: ExUnit.OnExitHandler.on_exit_runner_loop/0
defmodule HackneyBypassTest do
  use ExUnit.Case

  @tag timeout: 2000
  test "bypass with hackney" do
    bypass = Bypass.open
    reponse_delay = 600
    timeout = reponse_delay - 100

    Bypass.expect(bypass, "GET", "/", fn conn ->
      Process.sleep(reponse_delay)
      Plug.Conn.resp(conn, 200, "response data")
    end)

    request = Task.async(fn ->
      :hackney.get("http://localhost:#{bypass.port}", [], "", [follow_redirect: true, with_body: true])
    end)
    result =
    case Task.yield(request, timeout) || Task.shutdown(request) do
      {:ok, result} ->
        {:ok, result}
      nil ->
        {:error, :timeout}
    end

    assert result == {:error, :timeout}
    IO.puts "DEBUG: End of test reached"
  end

  test "bypass with httpc" do
    bypass = Bypass.open
    reponse_delay = 600
    timeout = reponse_delay - 100

    Bypass.expect(bypass, "GET", "/", fn conn ->
      Process.sleep(reponse_delay)
      Plug.Conn.resp(conn, 200, "response data")
    end)

    request = Task.async(fn ->
      :httpc.request(:get, {String.to_charlist("http://localhost:#{bypass.port}"), []}, [], body_format: :binary)
    end)
    result =
    case Task.yield(request, timeout) || Task.shutdown(request) do
      {:ok, result} ->
        {:ok, result}
      nil ->
        {:error, :timeout}
    end

    assert result == {:error, :timeout}
    IO.puts "DEBUG: End of test reached"
  end
end

貢獻者指南