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

Unified Diff: net/http/http_stream_factory_impl_job_controller_unittest.cc

Issue 1952423002: JobController 2: Remove reference between HttpStreamFactoryImpl::Jobs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@Job_Controller_1
Patch Set: use unmocked Job::Start() and asyncronous Proxy resolution in tests Created 4 years, 5 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
Index: net/http/http_stream_factory_impl_job_controller_unittest.cc
diff --git a/net/http/http_stream_factory_impl_job_controller_unittest.cc b/net/http/http_stream_factory_impl_job_controller_unittest.cc
index bd94d7ddc3fa89cdb49f8f5847f58e79e3994577..999fdb9b32771822c05245447c854d4dec1c8b96 100644
--- a/net/http/http_stream_factory_impl_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_impl_job_controller_unittest.cc
@@ -6,13 +6,19 @@
#include <memory>
+#include "base/run_loop.cc"
+#include "net/dns/mock_host_resolver.h"
#include "net/http/http_basic_stream.h"
#include "net/http/http_stream_factory_impl_request.h"
#include "net/http/http_stream_factory_test_util.h"
+#include "net/proxy/mock_proxy_resolver.h"
+#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_info.h"
#include "net/proxy/proxy_service.h"
+#include "net/quic/test_tools/quic_stream_factory_peer.h"
#include "net/spdy/spdy_test_util_common.h"
#include "net/ssl/ssl_failure_state.h"
+#include "testing/gmock_mutant.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
@@ -28,8 +34,116 @@ void DeleteHttpStreamPointer(const SSLConfig& used_ssl_config,
delete stream;
}
+class HangingProxyResolver : public ProxyResolver {
+ public:
+ HangingProxyResolver() {}
+ ~HangingProxyResolver() override {}
+
+ int GetProxyForURL(const GURL& url,
+ ProxyInfo* results,
+ const CompletionCallback& callback,
+ RequestHandle* request,
+ const BoundNetLog& net_log) override {
+ return ERR_IO_PENDING;
+ }
+
+ void CancelRequest(RequestHandle request) override { NOTREACHED(); }
+
+ LoadState GetLoadState(RequestHandle request) const override {
+ NOTREACHED();
+ return LOAD_STATE_IDLE;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HangingProxyResolver);
+};
+
+class HangingProxyResolverFactory : public ProxyResolverFactory {
+ public:
+ explicit HangingProxyResolverFactory(HangingProxyResolver* resolver)
+ : ProxyResolverFactory(false), resolver_(resolver) {}
+
+ // ProxyResolverFactory override.
+ int CreateProxyResolver(
+ const scoped_refptr<ProxyResolverScriptData>& pac_script,
+ std::unique_ptr<ProxyResolver>* resolver,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* request) override {
+ resolver->reset(new ForwardingProxyResolver(resolver_));
+ return OK;
+ }
+
+ private:
+ HangingProxyResolver* resolver_;
+};
+
+class FailingProxyResolverFactory : public ProxyResolverFactory {
+ public:
+ FailingProxyResolverFactory() : ProxyResolverFactory(false) {}
+
+ // ProxyResolverFactory override.
+ int CreateProxyResolver(
+ const scoped_refptr<ProxyResolverScriptData>& script_data,
+ std::unique_ptr<ProxyResolver>* result,
+ const CompletionCallback& callback,
+ std::unique_ptr<Request>* request) override {
+ return ERR_PAC_SCRIPT_FAILED;
+ }
+};
+
+class FailingHostResolver : public MockHostResolverBase {
+ public:
+ FailingHostResolver() : MockHostResolverBase(false /*use_caching*/) {}
+ ~FailingHostResolver() override {}
+
+ int Resolve(const RequestInfo& info,
+ RequestPriority priority,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ RequestHandle* out_req,
+ const BoundNetLog& net_log) override {
+ return ERR_NAME_NOT_RESOLVED;
+ }
+};
+
+class HangingResolver : public MockHostResolverBase {
+ public:
+ HangingResolver() : MockHostResolverBase(false /*use_caching*/) {}
+ ~HangingResolver() override {}
+
+ int Resolve(const RequestInfo& info,
+ RequestPriority priority,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ RequestHandle* out_req,
+ const BoundNetLog& net_log) override {
+ return ERR_IO_PENDING;
+ }
+
+ void CancelRequest(RequestHandle req) override {}
+};
} // anonymous namespace
+class HttpStreamFactoryImplJobPeer {
+ public:
+ static void Start(HttpStreamFactoryImpl::Job* job,
+ HttpStreamRequest::StreamType stream_type) {
+ // Start() is mocked for MockHttpStreamFactoryImplJob.
+ // This is the alternative method to invoke real Start() method on Job.
+ job->stream_type_ = stream_type;
+ job->StartInternal();
+ }
+};
+
+class JobControllerPeer {
+ public:
+ static void VerifyWaitingTimeForMainJob(
+ HttpStreamFactoryImpl::JobController* job_controller,
+ const base::TimeDelta& delay) {
+ EXPECT_EQ(delay, job_controller->main_job_wait_time_);
+ }
+};
+
class HttpStreamFactoryImplJobControllerTest
: public ::testing::Test,
public ::testing::WithParamInterface<NextProto> {
@@ -37,6 +151,9 @@ class HttpStreamFactoryImplJobControllerTest
HttpStreamFactoryImplJobControllerTest()
: session_deps_(GetParam(), ProxyService::CreateDirect()) {
session_deps_.enable_quic = true;
+ }
+
+ void Initialize() {
session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
factory_ =
static_cast<HttpStreamFactoryImpl*>(session_->http_stream_factory());
@@ -73,6 +190,8 @@ INSTANTIATE_TEST_CASE_P(NextProto,
TEST_P(HttpStreamFactoryImplJobControllerTest,
OnStreamFailedWithNoAlternativeJob) {
+ Initialize();
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("http://www.google.com");
@@ -95,6 +214,8 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
TEST_P(HttpStreamFactoryImplJobControllerTest,
OnStreamReadyWithNoAlternativeJob) {
+ Initialize();
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("http://www.google.com");
@@ -120,6 +241,8 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
// Test we cancel Jobs correctly when the Request is explicitly canceled
// before any Job is bound to Request.
TEST_P(HttpStreamFactoryImplJobControllerTest, CancelJobsBeforeBinding) {
+ Initialize();
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -143,6 +266,8 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, CancelJobsBeforeBinding) {
}
TEST_P(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) {
+ Initialize();
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -178,6 +303,8 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, OnStreamFailedForBothJobs) {
TEST_P(HttpStreamFactoryImplJobControllerTest,
SecondJobFailsAfterFirstJobSucceeds) {
+ Initialize();
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -220,6 +347,8 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
TEST_P(HttpStreamFactoryImplJobControllerTest,
SecondJobSucceedsAfterFirstJobFailed) {
+ Initialize();
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -258,6 +387,8 @@ TEST_P(HttpStreamFactoryImplJobControllerTest,
// Regression test for crbug/621069.
// Get load state after main job fails and before alternative job succeeds.
TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
+ Initialize();
+
HttpRequestInfo request_info;
request_info.method = "GET";
request_info.url = GURL("https://www.google.com");
@@ -296,4 +427,243 @@ TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
ProxyInfo());
}
+TEST_P(HttpStreamFactoryImplJobControllerTest, DoNotResumeMainJobBeforeWait) {
+ // Use failing ProxyResolverFactory which is unable to create ProxyResolver
+ // to stall the alternative job and report to controller to maybe resume the
+ // main job.
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ proxy_config.set_pac_mandatory(true);
+ session_deps_.proxy_service.reset(new ProxyService(
+ base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)),
+ base::WrapUnique(new FailingProxyResolverFactory), nullptr));
+
+ Initialize();
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+ job_factory_.DisableMockStartForJobs();
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ // Wait until OnStreamFailedCallback is executed on the alternative job.
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _, SSL_FAILURE_NONE))
+ .Times(1);
+ EXPECT_CALL(*job_factory_.main_job(), MarkOtherJobComplete(_)).Times(1);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_P(HttpStreamFactoryImplJobControllerTest, InvalidPortForQuic) {
+ // Using a restricted port 101 for QUIC should fail and the alternative job
+ // should post OnStreamFailedCall on the controller to resume the main job.
+ Initialize();
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 101);
+ SetAlternativeService(request_info, alternative_service);
+ job_factory_.DisableMockStartForJobs();
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+
+ EXPECT_TRUE(job_factory_.main_job()->is_waiting());
+
+ // Wait until OnStreamFailedCallback is executed on the alternative job.
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
+ EXPECT_CALL(*job_factory_.main_job(), MarkOtherJobComplete(_)).Times(1);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_P(HttpStreamFactoryImplJobControllerTest,
+ NoAvailableSpdySessionToResumeMainJob) {
+ // Test the alternative job is not resumed when the alternative job is
+ // IO_PENDING for proxy resolution. Once all the proxy resolution succeeds,
+ // the latter part of this test tests controller resumes the main job
+ // when there's no SPDY session for the alternative job.
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(new ProxyService(
+ base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+
+ HangingResolver* host_resolver = new HangingResolver();
+ session_deps_.host_resolver.reset(host_resolver);
+ session_deps_.host_resolver->set_synchronous_mode(false);
+
+ Initialize();
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://www.google.com");
+
+ // Set a SPDY alternative service for the server.
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(NPN_HTTP_2, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+ job_factory_.DisableMockStartForJobs();
Ryan Hamilton 2016/07/19 17:48:15 Discussed offline, let's move to using the 'normal
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ // Both jobs should be created but stalled as proxy resolution not completed.
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ MockAsyncProxyResolver resolver;
+ proxy_resolver_factory->pending_requests()[0]->CompleteNowWithForwarder(
+ net::OK, &resolver);
+
+ // Resolve proxy for the main job which then proceed to wait for the
+ // alternative job which is IO_PENDING.
+ int main_job_request_id =
+ resolver.pending_requests()[0]->url().SchemeIs("http") ? 0 : 1;
+
+ resolver.pending_requests()[main_job_request_id]->results()->UseNamedProxy(
+ "result1:80");
+ resolver.pending_requests()[main_job_request_id]->CompleteNow(net::OK);
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting());
+
+ // Resolve proxy for the alternative job to proceed to create a connection.
+ // Use hanging HostResolver to fail creation of a SPDY session for the
+ // alternative job. The alternative job will be IO_PENDING thus should resume
+ // the main job.
+ resolver.pending_requests()[0]->CompleteNow(net::OK);
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _, _)).Times(0);
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
+ EXPECT_CALL(*job_factory_.main_job(), MarkOtherJobComplete(_)).Times(1);
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_P(HttpStreamFactoryImplJobControllerTest,
+ NoAvailableQuicSessionToResumeMainJob) {
+ // Use failing HostResolver which is unable to resolve the host name for QUIC.
+ // No QUIC session is created and thus should resume the main job.
+ FailingHostResolver* host_resolver = new FailingHostResolver();
+ session_deps_.host_resolver.reset(host_resolver);
+
+ ProxyConfig proxy_config;
+ proxy_config.set_auto_detect(true);
+ // Use asynchronous proxy resolver.
+ MockAsyncProxyResolverFactory* proxy_resolver_factory =
+ new MockAsyncProxyResolverFactory(false);
+ session_deps_.proxy_service.reset(new ProxyService(
+ base::WrapUnique(new ProxyConfigServiceFixed(proxy_config)),
+ base::WrapUnique(proxy_resolver_factory), nullptr));
+
+ Initialize();
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("https://www.google.com");
+
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(QUIC, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+ job_factory_.DisableMockStartForJobs();
+ // Hack to use different URL for the main job to help differentiate the proxy
+ // requests.
+ job_factory_.UseDifferentURLForMainJob(GURL("http://www.google.com"));
+
Zhongyi Shi 2016/07/15 18:42:49 The original url has to use HTTPS so as to racing
eroman 2016/07/15 19:30:33 Does this test specifically need to test using PAC
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ MockAsyncProxyResolver resolver;
+ proxy_resolver_factory->pending_requests()[0]->CompleteNowWithForwarder(
+ net::OK, &resolver);
+
+ // Resolve proxy for the main job which then proceed to wait for the
+ // alternative job which is IO_PENDING.
+ int main_job_request_id =
+ resolver.pending_requests()[0]->url().SchemeIs("http") ? 0 : 1;
+
+ resolver.pending_requests()[main_job_request_id]->results()->UseNamedProxy(
+ "result1:80");
+ resolver.pending_requests()[main_job_request_id]->CompleteNow(net::OK);
+ EXPECT_TRUE(job_controller_->main_job()->is_waiting());
+
+ // Resolve proxy for the alternative job to proceed to create a connection.
+ // Use failing HostResolver to fail creation of a QUIC session for the
+ // alternative job. The alternative job will thus resume the main job.
+ resolver.pending_requests()[0]->results()->UseNamedProxy("result1:80");
+ resolver.pending_requests()[0]->CompleteNow(net::OK);
+
+ // Wait until OnStreamFailedCallback is executed on the alternative job.
+ // Request shouldn't be notified as the main job is still pending status.
+ EXPECT_CALL(request_delegate_, OnStreamFailed(_, _, _)).Times(0);
+ EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
+ EXPECT_CALL(*job_factory_.main_job(), MarkOtherJobComplete(_)).Times(1);
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_P(HttpStreamFactoryImplJobControllerTest, DelayedTCP) {
+ session_deps_.proxy_service.reset(
+ ProxyService::CreateFixedFromPacResult("QUIC mail.example.org:70")
+ .release());
+ HangingResolver* resolver = new HangingResolver();
+ session_deps_.host_resolver.reset(resolver);
+
+ Initialize();
+
+ // Enable delayed TCP and set time delay for waiting job.
+ QuicStreamFactory* quic_stream_factory = session_->quic_stream_factory();
+ test::QuicStreamFactoryPeer::SetDelayTcpRace(quic_stream_factory, true);
+ quic_stream_factory->set_require_confirmation(false);
+ ServerNetworkStats stats1;
+ stats1.srtt = base::TimeDelta::FromMicroseconds(10);
+ session_->http_server_properties()->SetServerNetworkStats(
+ url::SchemeHostPort(GURL("https://mail.example.org:70/")), stats1);
+
+ HttpRequestInfo request_info;
+ request_info.method = "GET";
+ request_info.url = GURL("http://www.google.com");
+
+ // Set a SPDY alternative service for the server.
+ url::SchemeHostPort server(request_info.url);
+ AlternativeService alternative_service(NPN_HTTP_2, server.host(), 443);
+ SetAlternativeService(request_info, alternative_service);
+ job_factory_.DisableMockStartForJobs();
+
+ request_.reset(
+ job_controller_->Start(request_info, &request_delegate_, nullptr,
+ BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+ DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+ EXPECT_TRUE(job_controller_->main_job());
+ EXPECT_TRUE(job_controller_->alternative_job());
+
+ // The alternative job stalls as host resolution hangs when creating the QUIC
+ // request and controller should resume the main job after delay.
+ // Verify the waiting time for delayed main job.
+ EXPECT_CALL(*job_factory_.main_job(), Resume())
+ .WillOnce(Invoke(testing::CreateFunctor(
+ &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_,
+ base::TimeDelta::FromMicroseconds(15))));
+
+ base::RunLoop().RunUntilIdle();
+}
} // namespace net
« no previous file with comments | « net/http/http_stream_factory_impl_job_controller.cc ('k') | net/http/http_stream_factory_impl_request_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698