|
%%% File : ibrowse_tests.erl
|
|
%%% Authors : Benjamin Lee <http://github.com/benjaminplee>
|
|
%%% Dan Schwabe <http://github.com/dfschwabe>
|
|
%%% Brian Richards <http://github.com/richbria>
|
|
%%% Description : Functional tests of the ibrowse library using a live test HTTP server
|
|
%%% Created : 18 November 2014 by Benjamin Lee <yardspoon@gmail.com>
|
|
|
|
-module(ibrowse_tests).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
-define(PER_TEST_TIMEOUT_SEC, 60).
|
|
-define(TIMEDTEST(Desc, Fun), {Desc, {timeout, ?PER_TEST_TIMEOUT_SEC, fun Fun/0}}).
|
|
|
|
-define(SERVER_PORT, 8181).
|
|
-define(BASE_URL, "http://localhost:" ++ integer_to_list(?SERVER_PORT)).
|
|
-define(SHORT_TIMEOUT_MS, 5000).
|
|
-define(LONG_TIMEOUT_MS, 30000).
|
|
-define(PAUSE_FOR_CONNECTIONS_MS, 4000).
|
|
|
|
%%-compile(export_all).
|
|
|
|
setup() ->
|
|
application:start(crypto),
|
|
application:start(public_key),
|
|
application:start(ssl),
|
|
ibrowse_test_server:start_server(?SERVER_PORT, tcp),
|
|
ibrowse:start(),
|
|
ok.
|
|
|
|
teardown(_) ->
|
|
ibrowse:stop(),
|
|
ibrowse_test_server:stop_server(?SERVER_PORT),
|
|
ok.
|
|
|
|
running_server_fixture_test_() ->
|
|
{foreach,
|
|
fun setup/0,
|
|
fun teardown/1,
|
|
[
|
|
?TIMEDTEST("Simple request can be honored", simple_request),
|
|
?TIMEDTEST("Slow server causes timeout", slow_server_timeout),
|
|
?TIMEDTEST("Pipeline depth goes down with responses", pipeline_depth),
|
|
?TIMEDTEST("Pipelines refill", pipeline_refill),
|
|
?TIMEDTEST("Timeout closes pipe", closing_pipes),
|
|
?TIMEDTEST("Requests are balanced over connections", balanced_connections),
|
|
?TIMEDTEST("Pipeline too small signals retries", small_pipeline),
|
|
?TIMEDTEST("Dest status can be gathered", status)
|
|
]
|
|
}.
|
|
|
|
simple_request() ->
|
|
?assertMatch({ok, "200", _, _}, ibrowse:send_req(?BASE_URL, [], get, [], [])).
|
|
|
|
slow_server_timeout() ->
|
|
?assertMatch({error, req_timedout}, ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [], 5000)).
|
|
|
|
pipeline_depth() ->
|
|
MaxSessions = 2,
|
|
MaxPipeline = 2,
|
|
RequestsSent = 2,
|
|
EmptyPipelineDepth = 0,
|
|
|
|
?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()),
|
|
|
|
Fun = fun() -> ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end,
|
|
times(RequestsSent, fun() -> spawn_link(Fun) end),
|
|
|
|
timer:sleep(?PAUSE_FOR_CONNECTIONS_MS),
|
|
|
|
Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()],
|
|
?assertEqual(MaxSessions, length(Counts)),
|
|
?assertEqual(lists:duplicate(MaxSessions, EmptyPipelineDepth), Counts).
|
|
|
|
pipeline_refill() ->
|
|
MaxSessions = 2,
|
|
MaxPipeline = 2,
|
|
RequestsToFill = MaxSessions * MaxPipeline,
|
|
|
|
%% Send off enough requests to fill sessions and pipelines in rappid succession
|
|
Fun = fun() -> ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end,
|
|
times(RequestsToFill, fun() -> spawn_link(Fun) end),
|
|
timer:sleep(?PAUSE_FOR_CONNECTIONS_MS),
|
|
|
|
% Verify that connections properly reported their completed responses and can still accept more
|
|
?assertMatch({ok, "200", _, _}, ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS)),
|
|
|
|
% and do it again to make sure we really are clear
|
|
times(RequestsToFill, fun() -> spawn_link(Fun) end),
|
|
timer:sleep(?PAUSE_FOR_CONNECTIONS_MS),
|
|
|
|
% Verify that connections properly reported their completed responses and can still accept more
|
|
?assertMatch({ok, "200", _, _}, ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS)).
|
|
|
|
closing_pipes() ->
|
|
MaxSessions = 2,
|
|
MaxPipeline = 2,
|
|
RequestsSent = 2,
|
|
BalancedNumberOfRequestsPerConnection = 1,
|
|
|
|
?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()),
|
|
|
|
Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end,
|
|
times(RequestsSent, fun() -> spawn_link(Fun) end),
|
|
|
|
timer:sleep(?PAUSE_FOR_CONNECTIONS_MS),
|
|
|
|
Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()],
|
|
?assertEqual(MaxSessions, length(Counts)),
|
|
?assertEqual(lists:duplicate(MaxSessions, BalancedNumberOfRequestsPerConnection), Counts),
|
|
|
|
timer:sleep(?SHORT_TIMEOUT_MS),
|
|
|
|
?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()).
|
|
|
|
balanced_connections() ->
|
|
MaxSessions = 4,
|
|
MaxPipeline = 100,
|
|
RequestsSent = 80,
|
|
BalancedNumberOfRequestsPerConnection = 20,
|
|
|
|
?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()),
|
|
|
|
Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?LONG_TIMEOUT_MS) end,
|
|
times(RequestsSent, fun() -> spawn_link(Fun) end),
|
|
|
|
timer:sleep(?PAUSE_FOR_CONNECTIONS_MS),
|
|
|
|
Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()],
|
|
?assertEqual(MaxSessions, length(Counts)),
|
|
|
|
?assertEqual(lists:duplicate(MaxSessions, BalancedNumberOfRequestsPerConnection), Counts).
|
|
|
|
small_pipeline() ->
|
|
MaxSessions = 10,
|
|
MaxPipeline = 10,
|
|
RequestsSent = 100,
|
|
FullRequestsPerConnection = 10,
|
|
|
|
?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()),
|
|
|
|
Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end,
|
|
times(RequestsSent, fun() -> spawn(Fun) end),
|
|
|
|
timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), %% Wait for everyone to get in line
|
|
|
|
ibrowse:show_dest_status("localhost", 8181),
|
|
Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()],
|
|
?assertEqual(MaxSessions, length(Counts)),
|
|
|
|
?assertEqual(lists:duplicate(MaxSessions, FullRequestsPerConnection), Counts),
|
|
|
|
Response = ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS),
|
|
|
|
?assertEqual({error, retry_later}, Response).
|
|
|
|
status() ->
|
|
MaxSessions = 10,
|
|
MaxPipeline = 10,
|
|
RequestsSent = 100,
|
|
|
|
Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end,
|
|
times(RequestsSent, fun() -> spawn(Fun) end),
|
|
|
|
timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), %% Wait for everyone to get in line
|
|
|
|
ibrowse:show_dest_status(),
|
|
ibrowse:show_dest_status("http://localhost:8181").
|
|
|
|
|
|
times(0, _) ->
|
|
ok;
|
|
times(X, Fun) ->
|
|
Fun(),
|
|
times(X - 1, Fun).
|