1%%% File : ibrowse_tests.erl 2%%% Authors : Benjamin Lee <http://github.com/benjaminplee> 3%%% Dan Schwabe <http://github.com/dfschwabe> 4%%% Brian Richards <http://github.com/richbria> 5%%% Description : Functional tests of the ibrowse library using a live test HTTP server 6%%% Created : 18 November 2014 by Benjamin Lee <yardspoon@gmail.com> 7 8-module(ibrowse_tests). 9 10-include_lib("eunit/include/eunit.hrl"). 11-define(PER_TEST_TIMEOUT_SEC, 60). 12-define(TIMEDTEST(Desc, Fun), {Desc, {timeout, ?PER_TEST_TIMEOUT_SEC, fun Fun/0}}). 13 14-define(SERVER_PORT, 8181). 15-define(BASE_URL, "http://localhost:" ++ integer_to_list(?SERVER_PORT)). 16-define(SHORT_TIMEOUT_MS, 5000). 17-define(LONG_TIMEOUT_MS, 30000). 18-define(PAUSE_FOR_CONNECTIONS_MS, 2000). 19 20-compile(export_all). 21 22setup() -> 23 application:start(crypto), 24 application:start(public_key), 25 application:start(ssl), 26 ibrowse_test_server:start_server(?SERVER_PORT, tcp), 27 ibrowse:start(), 28 ok. 29 30teardown(_) -> 31 ibrowse:stop(), 32 ibrowse_test_server:stop_server(?SERVER_PORT), 33 ok. 34 35running_server_fixture_test_() -> 36 {foreach, 37 fun setup/0, 38 fun teardown/1, 39 [ 40 ?TIMEDTEST("Simple request can be honored", simple_request), 41 ?TIMEDTEST("Slow server causes timeout", slow_server_timeout), 42 ?TIMEDTEST("Pipeline depth goes down with responses", pipeline_depth), 43 ?TIMEDTEST("Pipelines refill", pipeline_refill), 44 ?TIMEDTEST("Timeout closes pipe", closing_pipes), 45 ?TIMEDTEST("Requests are balanced over connections", balanced_connections), 46 ?TIMEDTEST("Pipeline too small signals retries", small_pipeline), 47 ?TIMEDTEST("Dest status can be gathered", status) 48 ] 49 }. 50 51simple_request() -> 52 ?assertMatch({ok, "200", _, _}, ibrowse:send_req(?BASE_URL, [], get, [], [])). 53 54slow_server_timeout() -> 55 ?assertMatch({error, req_timedout}, ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [], 5000)). 56 57pipeline_depth() -> 58 MaxSessions = 2, 59 MaxPipeline = 2, 60 RequestsSent = 2, 61 EmptyPipelineDepth = 0, 62 63 ?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()), 64 65 Fun = fun() -> ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end, 66 times(RequestsSent, fun() -> spawn_link(Fun) end), 67 68 timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), 69 70 Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()], 71 ?assertEqual(MaxSessions, length(Counts)), 72 ?assertEqual(lists:duplicate(MaxSessions, EmptyPipelineDepth), Counts). 73 74pipeline_refill() -> 75 MaxSessions = 2, 76 MaxPipeline = 2, 77 RequestsToFill = MaxSessions * MaxPipeline, 78 79 %% Send off enough requests to fill sessions and pipelines in rappid succession 80 Fun = fun() -> ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end, 81 times(RequestsToFill, fun() -> spawn_link(Fun) end), 82 timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), 83 84 % Verify that connections properly reported their completed responses and can still accept more 85 ?assertMatch({ok, "200", _, _}, ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS)), 86 87 % and do it again to make sure we really are clear 88 times(RequestsToFill, fun() -> spawn_link(Fun) end), 89 timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), 90 91 % Verify that connections properly reported their completed responses and can still accept more 92 ?assertMatch({ok, "200", _, _}, ibrowse:send_req(?BASE_URL, [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS)). 93 94closing_pipes() -> 95 MaxSessions = 2, 96 MaxPipeline = 2, 97 RequestsSent = 2, 98 BalancedNumberOfRequestsPerConnection = 1, 99 100 ?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()), 101 102 Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end, 103 times(RequestsSent, fun() -> spawn_link(Fun) end), 104 105 timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), 106 107 Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()], 108 ?assertEqual(MaxSessions, length(Counts)), 109 ?assertEqual(lists:duplicate(MaxSessions, BalancedNumberOfRequestsPerConnection), Counts), 110 111 timer:sleep(?SHORT_TIMEOUT_MS), 112 113 ?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()). 114 115balanced_connections() -> 116 MaxSessions = 4, 117 MaxPipeline = 100, 118 RequestsSent = 80, 119 BalancedNumberOfRequestsPerConnection = 20, 120 121 ?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()), 122 123 Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?LONG_TIMEOUT_MS) end, 124 times(RequestsSent, fun() -> spawn_link(Fun) end), 125 126 timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), 127 128 Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()], 129 ?assertEqual(MaxSessions, length(Counts)), 130 131 ?assertEqual(lists:duplicate(MaxSessions, BalancedNumberOfRequestsPerConnection), Counts). 132 133small_pipeline() -> 134 MaxSessions = 10, 135 MaxPipeline = 10, 136 RequestsSent = 100, 137 FullRequestsPerConnection = 10, 138 139 ?assertEqual([], ibrowse_test_server:get_conn_pipeline_depth()), 140 141 Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end, 142 times(RequestsSent, fun() -> spawn(Fun) end), 143 144 timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), %% Wait for everyone to get in line 145 146 ibrowse:show_dest_status("localhost", 8181), 147 Counts = [Count || {_Pid, Count} <- ibrowse_test_server:get_conn_pipeline_depth()], 148 ?assertEqual(MaxSessions, length(Counts)), 149 150 ?assertEqual(lists:duplicate(MaxSessions, FullRequestsPerConnection), Counts), 151 152 Response = ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS), 153 154 ?assertEqual({error, retry_later}, Response). 155 156status() -> 157 MaxSessions = 10, 158 MaxPipeline = 10, 159 RequestsSent = 100, 160 161 Fun = fun() -> ibrowse:send_req(?BASE_URL ++ "/never_respond", [], get, [], [{max_sessions, MaxSessions}, {max_pipeline_size, MaxPipeline}], ?SHORT_TIMEOUT_MS) end, 162 times(RequestsSent, fun() -> spawn(Fun) end), 163 164 timer:sleep(?PAUSE_FOR_CONNECTIONS_MS), %% Wait for everyone to get in line 165 166 ibrowse:show_dest_status(), 167 ibrowse:show_dest_status("http://localhost:8181"). 168 169 170times(0, _) -> 171 ok; 172times(X, Fun) -> 173 Fun(), 174 times(X - 1, Fun). 175