Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1475)

Unified Diff: net/url_request/url_request_unittest.cc

Issue 2130493002: Implement THROTTLED priority semantics. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@NetworkStreamThrottler
Patch Set: Added (currently failing) URLRequest unit test. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« net/base/quantile_estimator_unittest.cc ('K') | « net/net.gypi ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/url_request/url_request_unittest.cc
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index db31eb519d958267d3f8d4bbed519c63ce68b44a..f3845d136c9b55c7fa4a01dc88ac4cd51f95f098 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -385,8 +385,18 @@ class BlockingNetworkDelegate : public TestNetworkDelegate {
USER_CALLBACK, // User takes care of doing a callback. |retval_| and
// |auth_retval_| are ignored. In every blocking stage the
// message loop is quit.
+ USER_NOTIFY, // User is notified by a provided callback of the
+ // blocking, and synchronously returns instructions
+ // for handling it.
};
+ using NotificationCallback =
+ base::Callback<Error(const CompletionCallback&, const URLRequest*)>;
+
+ using NotificationAuthCallback =
+ base::Callback<NetworkDelegate::AuthRequiredResponse(const AuthCallback&,
+ const URLRequest*)>;
+
// Creates a delegate which does not block at all.
explicit BlockingNetworkDelegate(BlockMode block_mode);
@@ -423,6 +433,17 @@ class BlockingNetworkDelegate : public TestNetworkDelegate {
block_on_ = block_on;
}
+ // Only valid if |block_mode_| == USER_NOTIFY
+ void set_notification_callback(
+ const NotificationCallback& notification_callback) {
+ notification_callback_ = notification_callback;
+ }
+
+ void set_notification_auth_callback(
+ const NotificationAuthCallback& notification_auth_callback) {
+ notification_auth_callback_ = notification_auth_callback;
+ }
+
// Allows the user to check in which state did we block.
Stage stage_blocked_for_callback() const {
EXPECT_EQ(USER_CALLBACK, block_mode_);
@@ -461,7 +482,9 @@ class BlockingNetworkDelegate : public TestNetworkDelegate {
// Checks whether we should block in |stage|. If yes, returns an error code
// and optionally sets up callback based on |block_mode_|. If no, returns OK.
- int MaybeBlockStage(Stage stage, const CompletionCallback& callback);
+ int MaybeBlockStage(Stage stage,
+ const URLRequest* request,
+ const CompletionCallback& callback);
// Configuration parameters, can be adjusted by public methods:
const BlockMode block_mode_;
@@ -488,6 +511,10 @@ class BlockingNetworkDelegate : public TestNetworkDelegate {
CompletionCallback callback_;
AuthCallback auth_callback_;
+ // Callback to request user instructions for blocking.
+ NotificationCallback notification_callback_;
+ NotificationAuthCallback notification_auth_callback_;
+
base::WeakPtrFactory<BlockingNetworkDelegate> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(BlockingNetworkDelegate);
@@ -547,7 +574,7 @@ int BlockingNetworkDelegate::OnBeforeURLRequest(
if (!redirect_url_.is_empty())
*new_url = redirect_url_;
- return MaybeBlockStage(ON_BEFORE_URL_REQUEST, callback);
+ return MaybeBlockStage(ON_BEFORE_URL_REQUEST, request, callback);
}
int BlockingNetworkDelegate::OnBeforeStartTransaction(
@@ -556,7 +583,7 @@ int BlockingNetworkDelegate::OnBeforeStartTransaction(
HttpRequestHeaders* headers) {
TestNetworkDelegate::OnBeforeStartTransaction(request, callback, headers);
- return MaybeBlockStage(ON_BEFORE_SEND_HEADERS, callback);
+ return MaybeBlockStage(ON_BEFORE_SEND_HEADERS, request, callback);
}
int BlockingNetworkDelegate::OnHeadersReceived(
@@ -571,7 +598,7 @@ int BlockingNetworkDelegate::OnHeadersReceived(
override_response_headers,
allowed_unsafe_redirect_url);
- return MaybeBlockStage(ON_HEADERS_RECEIVED, callback);
+ return MaybeBlockStage(ON_HEADERS_RECEIVED, request, callback);
}
NetworkDelegate::AuthRequiredResponse BlockingNetworkDelegate::OnAuthRequired(
@@ -609,6 +636,11 @@ NetworkDelegate::AuthRequiredResponse BlockingNetworkDelegate::OnAuthRequired(
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
return AUTH_REQUIRED_RESPONSE_IO_PENDING;
+
+ case USER_NOTIFY:
+ // If the callback returns ERR_IO_PENDING, the user has accepted
+ // responsibility for running the callback in the future.
+ return notification_auth_callback_.Run(callback, request);
}
NOTREACHED();
return AUTH_REQUIRED_RESPONSE_NO_ACTION; // Dummy value.
@@ -623,6 +655,7 @@ void BlockingNetworkDelegate::Reset() {
int BlockingNetworkDelegate::MaybeBlockStage(
BlockingNetworkDelegate::Stage stage,
+ const URLRequest* request,
const CompletionCallback& callback) {
// Check that the user has provided callback for the previous blocked stage.
EXPECT_EQ(NOT_BLOCKED, stage_blocked_for_callback_);
@@ -648,6 +681,11 @@ int BlockingNetworkDelegate::MaybeBlockStage(
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
return ERR_IO_PENDING;
+
+ case USER_NOTIFY:
+ // If the callback returns ERR_IO_PENDING, the user has accepted
+ // responsibility for running the callback in the future.
+ return notification_callback_.Run(callback, request);
}
NOTREACHED();
return 0;
@@ -7843,7 +7881,7 @@ TEST_F(URLRequestTestHTTP, NetworkAccessedClearOnLoadOnlyFromCache) {
EXPECT_FALSE(req->response_info().network_accessed);
}
-// Test that a single job with a throttled priority completes
+// Test that a single job with a THROTTLED priority completes
// correctly in the absence of contention.
TEST_F(URLRequestTestHTTP, ThrottledPriority) {
ASSERT_TRUE(http_test_server()->Start());
@@ -7858,6 +7896,100 @@ TEST_F(URLRequestTestHTTP, ThrottledPriority) {
EXPECT_TRUE(req->status().is_success());
}
+// A class to hold state for responding to USER_NOTIFY callbacks from
+// BlockingNetworkDelegate.
+class NotificationCallbackHandler {
+ public:
+ // Default constructed object doesn't block anything.
+ NotificationCallbackHandler() {}
+
+ void AddURLRequestToBlockList(const URLRequest* request) {
+ requests_to_block_.insert(request);
+ }
+
+ Error ShouldBlockRequest(const CompletionCallback& callback,
+ const URLRequest* request) {
+ if (requests_to_block_.find(request) == requests_to_block_.end()) {
+ return OK;
+ }
+
+ DCHECK(blocked_callbacks_.find(request) == blocked_callbacks_.end());
+ blocked_callbacks_[request] = callback;
+ return ERR_IO_PENDING;
+ }
+
+ // Erases object's memory of blocked callbacks as a side effect.
+ void GetBlockedCallbacks(
+ std::map<const URLRequest*, CompletionCallback>* blocked_callbacks) {
+ blocked_callbacks_.swap(*blocked_callbacks);
+ }
+
+ private:
+ std::set<const URLRequest*> requests_to_block_;
+ std::map<const URLRequest*, CompletionCallback> blocked_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(NotificationCallbackHandler);
+};
+
+TEST_F(URLRequestTestHTTP, MultiThrottledPriority) {
+ ASSERT_TRUE(http_test_server()->Start());
+
+ NotificationCallbackHandler notification_handler;
+ TestDelegate d;
+ BlockingNetworkDelegate network_delegate(
+ BlockingNetworkDelegate::USER_NOTIFY);
+ network_delegate.set_block_on(
+ BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS);
+ network_delegate.set_notification_callback(
+ base::Bind(&NotificationCallbackHandler::ShouldBlockRequest,
+ // Both objects are owned by this function, and
+ // |*network_delegate| will be destroyed first, so
+ // it's safe to pass it an unretained pointer.
+ base::Unretained(&notification_handler)));
+
+ TestURLRequestContext context(true);
+ context.set_network_delegate(&network_delegate);
+ context.Init();
+
+ GURL test_url(http_test_server()->GetURL("/"));
+ std::unique_ptr<URLRequest> req1(
+ context.CreateRequest(test_url, THROTTLED, &d));
+ notification_handler.AddURLRequestToBlockList(req1.get());
+
+ std::unique_ptr<URLRequest> req2(
+ context.CreateRequest(test_url, THROTTLED, &d));
+ notification_handler.AddURLRequestToBlockList(req2.get());
+
+ std::unique_ptr<URLRequest> req3(
+ context.CreateRequest(test_url, THROTTLED, &d));
+ req1->Start();
+ req2->Start();
+ req3->Start();
+ base::RunLoop().RunUntilIdle();
+
+ // The first two requests should be blocked based on the notification
+ // callback, and their status should have blocked the third request.
+ EXPECT_TRUE(req1->status().is_io_pending());
+ EXPECT_TRUE(req2->status().is_io_pending());
+ EXPECT_TRUE(req3->status().is_io_pending());
+
+ std::map<const URLRequest*, CompletionCallback> blocked_callbacks;
+ notification_handler.GetBlockedCallbacks(&blocked_callbacks);
+ ASSERT_EQ(2u, blocked_callbacks.size());
+ ASSERT_TRUE(blocked_callbacks.find(req1.get()) != blocked_callbacks.end());
+ ASSERT_TRUE(blocked_callbacks.find(req2.get()) != blocked_callbacks.end());
+
+ // Unblocking req2 should allow it to run until end *and* then allow req3
+ // to run until it ends.
+ blocked_callbacks[req2.get()].Run(OK);
+ base::RunLoop().RunUntilIdle();
+ notification_handler.GetBlockedCallbacks(&blocked_callbacks);
+ EXPECT_EQ(0u, blocked_callbacks.size());
+ EXPECT_TRUE(req1->status().is_io_pending());
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req2->status().status());
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req3->status().status());
+}
+
TEST_F(URLRequestTestHTTP, RawBodyBytesNoContentEncoding) {
ASSERT_TRUE(http_test_server()->Start());
« net/base/quantile_estimator_unittest.cc ('K') | « net/net.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698