summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/tests
diff options
context:
space:
mode:
authorBrad Payne (Vir Linden) <vir@lindenlab.com>2014-02-25 13:25:40 -0500
committerBrad Payne (Vir Linden) <vir@lindenlab.com>2014-02-25 13:25:40 -0500
commit895d52a399739962c38ddf571e57f85362823dff (patch)
treea404be5fb01219c7f080c10d80017d1d44647dc3 /indra/llcorehttp/tests
parent948c0c559d14b73714652b581886cbcef391ed62 (diff)
parentde8fea13627cc5978b8a6135802a52864a11c39a (diff)
merge viewer-release to sunshine-external
Diffstat (limited to 'indra/llcorehttp/tests')
-rwxr-xr-xindra/llcorehttp/tests/test_httprequest.hpp140
-rwxr-xr-xindra/llcorehttp/tests/test_httpstatus.hpp59
-rwxr-xr-xindra/llcorehttp/tests/test_llcorehttp_peer.py72
3 files changed, 254 insertions, 17 deletions
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
index 0f0876b467..43f7e36da5 100755
--- a/indra/llcorehttp/tests/test_httprequest.hpp
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -1222,7 +1222,7 @@ void HttpRequestTestObjectType::test<12>()
HttpRequest::createService();
// Enable tracing
- HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2);
+ HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);
// Start threading early so that thread memory is invariant
// over the test.
@@ -1340,7 +1340,7 @@ void HttpRequestTestObjectType::test<13>()
HttpRequest::createService();
// Enable tracing
- HttpRequest::setPolicyGlobalOption(LLCore::HttpRequest::GP_TRACE, 2);
+ HttpRequest::setStaticPolicyOption(HttpRequest::PO_TRACE, HttpRequest::DEFAULT_POLICY_ID, 2, NULL);
// Start threading early so that thread memory is invariant
// over the test.
@@ -3175,6 +3175,142 @@ void HttpRequestTestObjectType::test<22>()
}
}
+template <> template <>
+void HttpRequestTestObjectType::test<23>()
+{
+ ScopedCurlInit ready;
+
+ set_test_name("HttpRequest GET 503s with 'Retry-After'");
+
+ // This tests mainly that the code doesn't fall over if
+ // various well- and mis-formed Retry-After headers are
+ // sent along with the response. Direct inspection of
+ // the parsing result isn't supported.
+
+ // Handler can be stack-allocated *if* there are no dangling
+ // references to it after completion of this method.
+ // Create before memory record as the string copy will bump numbers.
+ TestHandler2 handler(this, "handler");
+ std::string url_base(get_base_url() + "/503/"); // path to 503 generators
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+ mHandlerCalls = 0;
+
+ HttpRequest * req = NULL;
+ HttpOptions * opts = NULL;
+
+ try
+ {
+ // Get singletons created
+ HttpRequest::createService();
+
+ // Start threading early so that thread memory is invariant
+ // over the test.
+ HttpRequest::startThread();
+
+ // create a new ref counted object with an implicit reference
+ req = new HttpRequest();
+ ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
+
+ opts = new HttpOptions();
+ opts->setRetries(1); // Retry once only
+ opts->setUseRetryAfter(true); // Try to parse the retry-after header
+
+ // Issue a GET that 503s with valid retry-after
+ mStatus = HttpStatus(503);
+ int url_limit(6);
+ for (int i(0); i < url_limit; ++i)
+ {
+ std::ostringstream url;
+ url << url_base << i << "/";
+ HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
+ 0U,
+ url.str(),
+ 0,
+ 0,
+ opts,
+ NULL,
+ &handler);
+
+ std::ostringstream testtag;
+ testtag << "Valid handle returned for 503 request #" << i;
+ ensure(testtag.str(), handle != LLCORE_HTTP_HANDLE_INVALID);
+ }
+
+
+ // Run the notification pump.
+ int count(0);
+ int limit(LOOP_COUNT_LONG);
+ while (count++ < limit && mHandlerCalls < url_limit)
+ {
+ req->update(0);
+ usleep(LOOP_SLEEP_INTERVAL);
+ }
+ ensure("Request executed in reasonable time", count < limit);
+ ensure("One handler invocation for request", mHandlerCalls == url_limit);
+
+ // Okay, request a shutdown of the servicing thread
+ mStatus = HttpStatus();
+ mHandlerCalls = 0;
+ HttpHandle handle = req->requestStopThread(&handler);
+ ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump again
+ count = 0;
+ limit = LOOP_COUNT_LONG;
+ while (count++ < limit && mHandlerCalls < 1)
+ {
+ req->update(1000000);
+ usleep(LOOP_SLEEP_INTERVAL);
+ }
+ ensure("Second request executed in reasonable time", count < limit);
+ ensure("Second handler invocation", mHandlerCalls == 1);
+
+ // See that we actually shutdown the thread
+ count = 0;
+ limit = LOOP_COUNT_SHORT;
+ while (count++ < limit && ! HttpService::isStopped())
+ {
+ usleep(LOOP_SLEEP_INTERVAL);
+ }
+ ensure("Thread actually stopped running", HttpService::isStopped());
+
+ // release options
+ opts->release();
+ opts = NULL;
+
+ // release the request object
+ delete req;
+ req = NULL;
+
+ // Shut down service
+ HttpRequest::destroyService();
+
+#if defined(WIN32)
+ // Can only do this memory test on Windows. On other platforms,
+ // the LL logging system holds on to memory and produces what looks
+ // like memory leaks...
+
+ // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
+ ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
+#endif
+ }
+ catch (...)
+ {
+ stop_thread(req);
+ if (opts)
+ {
+ opts->release();
+ opts = NULL;
+ }
+ delete req;
+ HttpRequest::destroyService();
+ throw;
+ }
+}
+
+
} // end namespace tut
namespace
diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp
index b5538528c5..0b379836c9 100755
--- a/indra/llcorehttp/tests/test_httpstatus.hpp
+++ b/indra/llcorehttp/tests/test_httpstatus.hpp
@@ -259,6 +259,65 @@ void HttpStatusTestObjectType::test<7>()
ensure(msg == "Unknown error");
}
+
+template <> template <>
+void HttpStatusTestObjectType::test<8>()
+{
+ set_test_name("HttpStatus toHex() nominal function");
+
+ HttpStatus status(404);
+ std::string msg = status.toHex();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(msg == "01940001");
+}
+
+
+template <> template <>
+void HttpStatusTestObjectType::test<9>()
+{
+ set_test_name("HttpStatus toTerseString() nominal function");
+
+ HttpStatus status(404);
+ std::string msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Normal HTTP 404", msg == "Http_404");
+
+ status = HttpStatus(200);
+ msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Normal HTTP 200", msg == "Http_200");
+
+ status = HttpStatus(200, HE_REPLY_ERROR);
+ msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Unsuccessful HTTP 200", msg == "Http_200"); // No distinction for error
+
+ status = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
+ msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Easy couldn't connect error", msg == "Easy_7");
+
+ status = HttpStatus(HttpStatus::EXT_CURL_MULTI, CURLM_OUT_OF_MEMORY);
+ msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Multi out-of-memory error", msg == "Multi_3");
+
+ status = HttpStatus(HttpStatus::LLCORE, HE_OPT_NOT_SET);
+ msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Core option not set error", msg == "Core_7");
+
+ status = HttpStatus(22000, 1);
+ msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Undecodable error", msg == "Unknown_1");
+
+ status = HttpStatus(22000, -1);
+ msg = status.toTerseString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure("Undecodable error 65535", msg == "Unknown_65535");
+}
+
} // end namespace tut
#endif // TEST_HTTP_STATUS_H
diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py
index 3c3af8dc75..04cde651c4 100755
--- a/indra/llcorehttp/tests/test_llcorehttp_peer.py
+++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py
@@ -69,6 +69,15 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
"Content-Range: bytes 0-75/2983",
"Content-Length: 76"
-- '/bug2295/inv_cont_range/0/' Generates HE_INVALID_CONTENT_RANGE error in llcorehttp.
+ - '/503/' Generate 503 responses with various kinds
+ of 'retry-after' headers
+ -- '/503/0/' "Retry-After: 2"
+ -- '/503/1/' "Retry-After: Thu, 31 Dec 2043 23:59:59 GMT"
+ -- '/503/2/' "Retry-After: Fri, 31 Dec 1999 23:59:59 GMT"
+ -- '/503/3/' "Retry-After: "
+ -- '/503/4/' "Retry-After: (*#*(@*(@(")"
+ -- '/503/5/' "Retry-After: aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo"
+ -- '/503/6/' "Retry-After: 1 2 3 4 5 6 7 8 9 10"
Some combinations make no sense, there's no effort to protect
you from that.
@@ -143,22 +152,40 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
if "/sleep/" in self.path:
time.sleep(30)
- if "fail" in self.path:
- status = data.get("status", 500)
- # self.responses maps an int status to a (short, long) pair of
- # strings. We want the longer string. That's why we pass a string
- # pair to get(): the [1] will select the second string, whether it
- # came from self.responses or from our default pair.
- reason = data.get("reason",
- self.responses.get(status,
- ("fail requested",
- "Your request specified failure status %s "
- "without providing a reason" % status))[1])
- debug("fail requested: %s: %r", status, reason)
- self.send_error(status, reason)
+ if "/503/" in self.path:
+ # Tests for various kinds of 'Retry-After' header parsing
+ body = None
+ if "/503/0/" in self.path:
+ self.send_response(503)
+ self.send_header("retry-after", "2")
+ elif "/503/1/" in self.path:
+ self.send_response(503)
+ self.send_header("retry-after", "Thu, 31 Dec 2043 23:59:59 GMT")
+ elif "/503/2/" in self.path:
+ self.send_response(503)
+ self.send_header("retry-after", "Fri, 31 Dec 1999 23:59:59 GMT")
+ elif "/503/3/" in self.path:
+ self.send_response(503)
+ self.send_header("retry-after", "")
+ elif "/503/4/" in self.path:
+ self.send_response(503)
+ self.send_header("retry-after", "(*#*(@*(@(")
+ elif "/503/5/" in self.path:
+ self.send_response(503)
+ self.send_header("retry-after", "aklsjflajfaklsfaklfasfklasdfklasdgahsdhgasdiogaioshdgo")
+ elif "/503/6/" in self.path:
+ self.send_response(503)
+ self.send_header("retry-after", "1 2 3 4 5 6 7 8 9 10")
+ else:
+ # Unknown request
+ self.send_response(400)
+ body = "Unknown /503/ path in server"
if "/reflect/" in self.path:
self.reflect_headers()
+ self.send_header("Content-type", "text/plain")
self.end_headers()
+ if body:
+ self.wfile.write(body)
elif "/bug2295/" in self.path:
# Test for https://jira.secondlife.com/browse/BUG-2295
#
@@ -194,8 +221,7 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
self.end_headers()
if body:
self.wfile.write(body)
- else:
- # Normal response path
+ elif "fail" not in self.path:
data = data.copy() # we're going to modify
# Ensure there's a "reply" key in data, even if there wasn't before
data["reply"] = data.get("reply", llsd.LLSD("success"))
@@ -210,6 +236,22 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler):
self.end_headers()
if withdata:
self.wfile.write(response)
+ else: # fail requested
+ status = data.get("status", 500)
+ # self.responses maps an int status to a (short, long) pair of
+ # strings. We want the longer string. That's why we pass a string
+ # pair to get(): the [1] will select the second string, whether it
+ # came from self.responses or from our default pair.
+ reason = data.get("reason",
+ self.responses.get(status,
+ ("fail requested",
+ "Your request specified failure status %s "
+ "without providing a reason" % status))[1])
+ debug("fail requested: %s: %r", status, reason)
+ self.send_error(status, reason)
+ if "/reflect/" in self.path:
+ self.reflect_headers()
+ self.end_headers()
def reflect_headers(self):
for name in self.headers.keys():