| Index: content/child/throttling_url_loader_unittest.cc
 | 
| diff --git a/content/child/throttling_url_loader_unittest.cc b/content/child/throttling_url_loader_unittest.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..96b8b9194369ff02ebbc6fcddaa7bbd4eefd7416
 | 
| --- /dev/null
 | 
| +++ b/content/child/throttling_url_loader_unittest.cc
 | 
| @@ -0,0 +1,560 @@
 | 
| +// Copyright 2017 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "content/child/throttling_url_loader.h"
 | 
| +#include "base/logging.h"
 | 
| +#include "base/macros.h"
 | 
| +#include "base/message_loop/message_loop.h"
 | 
| +#include "base/run_loop.h"
 | 
| +#include "content/common/url_loader.mojom.h"
 | 
| +#include "content/common/url_loader_factory.mojom.h"
 | 
| +#include "content/public/child/url_loader_throttle.h"
 | 
| +#include "testing/gtest/include/gtest/gtest.h"
 | 
| +
 | 
| +namespace content {
 | 
| +namespace {
 | 
| +
 | 
| +class TestURLLoaderFactory : public mojom::URLLoaderFactory {
 | 
| + public:
 | 
| +  TestURLLoaderFactory() : binding_(this) {
 | 
| +    binding_.Bind(mojo::MakeRequest(&factory_ptr_));
 | 
| +  }
 | 
| +
 | 
| +  mojom::URLLoaderFactoryPtr& factory_ptr() { return factory_ptr_; }
 | 
| +  mojom::URLLoaderClientPtr& client_ptr() { return client_ptr_; }
 | 
| +
 | 
| +  size_t create_loader_and_start_called() const {
 | 
| +    return create_loader_and_start_called_;
 | 
| +  }
 | 
| +
 | 
| +  void NotifyClientOnReceiveResponse() {
 | 
| +    client_ptr_->OnReceiveResponse(ResourceResponseHead(), base::nullopt,
 | 
| +                                   nullptr);
 | 
| +  }
 | 
| +
 | 
| +  void NotifyClientOnReceiveRedirect() {
 | 
| +    client_ptr_->OnReceiveRedirect(net::RedirectInfo(), ResourceResponseHead());
 | 
| +  }
 | 
| +
 | 
| +  void NotifyClientOnComplete(int error_code) {
 | 
| +    ResourceRequestCompletionStatus data;
 | 
| +    data.error_code = error_code;
 | 
| +    client_ptr_->OnComplete(data);
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  // mojom::URLLoaderFactory implementation.
 | 
| +  void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest request,
 | 
| +                            int32_t routing_id,
 | 
| +                            int32_t request_id,
 | 
| +                            uint32_t options,
 | 
| +                            const ResourceRequest& url_request,
 | 
| +                            mojom::URLLoaderClientPtr client) override {
 | 
| +    create_loader_and_start_called_++;
 | 
| +
 | 
| +    client_ptr_ = std::move(client);
 | 
| +  }
 | 
| +
 | 
| +  void SyncLoad(int32_t routing_id,
 | 
| +                int32_t request_id,
 | 
| +                const ResourceRequest& request,
 | 
| +                SyncLoadCallback callback) override {
 | 
| +    NOTREACHED();
 | 
| +  }
 | 
| +
 | 
| +  size_t create_loader_and_start_called_ = 0;
 | 
| +
 | 
| +  mojo::Binding<mojom::URLLoaderFactory> binding_;
 | 
| +  mojom::URLLoaderFactoryPtr factory_ptr_;
 | 
| +  mojom::URLLoaderClientPtr client_ptr_;
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory);
 | 
| +};
 | 
| +
 | 
| +class TestURLLoaderClient : public mojom::URLLoaderClient {
 | 
| + public:
 | 
| +  TestURLLoaderClient() {}
 | 
| +
 | 
| +  size_t on_received_response_called() const {
 | 
| +    return on_received_response_called_;
 | 
| +  }
 | 
| +
 | 
| +  size_t on_received_redirect_called() const {
 | 
| +    return on_received_redirect_called_;
 | 
| +  }
 | 
| +
 | 
| +  size_t on_complete_called() const { return on_complete_called_; }
 | 
| +
 | 
| +  using OnCompleteCallback = base::Callback<void(int error_code)>;
 | 
| +  void set_on_complete_callback(const OnCompleteCallback& callback) {
 | 
| +    on_complete_callback_ = callback;
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  // mojom::URLLoaderClient implementation:
 | 
| +  void OnReceiveResponse(
 | 
| +      const ResourceResponseHead& response_head,
 | 
| +      const base::Optional<net::SSLInfo>& ssl_info,
 | 
| +      mojom::DownloadedTempFilePtr downloaded_file) override {
 | 
| +    on_received_response_called_++;
 | 
| +  }
 | 
| +  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
 | 
| +                         const ResourceResponseHead& response_head) override {
 | 
| +    on_received_redirect_called_++;
 | 
| +  }
 | 
| +  void OnDataDownloaded(int64_t data_len, int64_t encoded_data_len) override {}
 | 
| +  void OnUploadProgress(int64_t current_position,
 | 
| +                        int64_t total_size,
 | 
| +                        OnUploadProgressCallback ack_callback) override {}
 | 
| +  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override {}
 | 
| +  void OnTransferSizeUpdated(int32_t transfer_size_diff) override {}
 | 
| +  void OnStartLoadingResponseBody(
 | 
| +      mojo::ScopedDataPipeConsumerHandle body) override {}
 | 
| +  void OnComplete(const ResourceRequestCompletionStatus& status) override {
 | 
| +    on_complete_called_++;
 | 
| +    if (on_complete_callback_)
 | 
| +      on_complete_callback_.Run(status.error_code);
 | 
| +  }
 | 
| +
 | 
| +  size_t on_received_response_called_ = 0;
 | 
| +  size_t on_received_redirect_called_ = 0;
 | 
| +  size_t on_complete_called_ = 0;
 | 
| +
 | 
| +  OnCompleteCallback on_complete_callback_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TestURLLoaderClient);
 | 
| +};
 | 
| +
 | 
| +class TestURLLoaderThrottle : public URLLoaderThrottle {
 | 
| + public:
 | 
| +  TestURLLoaderThrottle() {}
 | 
| +
 | 
| +  using ThrottleCallback =
 | 
| +      base::Callback<void(URLLoaderThrottle::Delegate* delegate, bool* defer)>;
 | 
| +
 | 
| +  size_t will_start_request_called() const {
 | 
| +    return will_start_request_called_;
 | 
| +  }
 | 
| +  size_t will_redirect_request_called() const {
 | 
| +    return will_redirect_request_called_;
 | 
| +  }
 | 
| +  size_t will_process_response_called() const {
 | 
| +    return will_process_response_called_;
 | 
| +  }
 | 
| +
 | 
| +  void set_will_start_request_callback(const ThrottleCallback& callback) {
 | 
| +    will_start_request_callback_ = callback;
 | 
| +  }
 | 
| +
 | 
| +  void set_will_redirect_request_callback(const ThrottleCallback& callback) {
 | 
| +    will_redirect_request_callback_ = callback;
 | 
| +  }
 | 
| +
 | 
| +  void set_will_process_response_callback(const ThrottleCallback& callback) {
 | 
| +    will_process_response_callback_ = callback;
 | 
| +  }
 | 
| +
 | 
| +  Delegate* delegate() const { return delegate_; }
 | 
| +
 | 
| + private:
 | 
| +  // URLLoaderThrottle implementation.
 | 
| +  void WillStartRequest(const GURL& url,
 | 
| +                        int load_flags,
 | 
| +                        ResourceType resource_type,
 | 
| +                        bool* defer) override {
 | 
| +    will_start_request_called_++;
 | 
| +    if (will_start_request_callback_)
 | 
| +      will_start_request_callback_.Run(delegate_, defer);
 | 
| +  }
 | 
| +
 | 
| +  void WillRedirectRequest(const net::RedirectInfo& redirect_info,
 | 
| +                           bool* defer) override {
 | 
| +    will_redirect_request_called_++;
 | 
| +    if (will_redirect_request_callback_)
 | 
| +      will_redirect_request_callback_.Run(delegate_, defer);
 | 
| +  }
 | 
| +
 | 
| +  void WillProcessResponse(bool* defer) override {
 | 
| +    will_process_response_called_++;
 | 
| +    if (will_process_response_callback_)
 | 
| +      will_process_response_callback_.Run(delegate_, defer);
 | 
| +  }
 | 
| +
 | 
| +  size_t will_start_request_called_ = 0;
 | 
| +  size_t will_redirect_request_called_ = 0;
 | 
| +  size_t will_process_response_called_ = 0;
 | 
| +
 | 
| +  ThrottleCallback will_start_request_callback_;
 | 
| +  ThrottleCallback will_redirect_request_callback_;
 | 
| +  ThrottleCallback will_process_response_callback_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(TestURLLoaderThrottle);
 | 
| +};
 | 
| +
 | 
| +class ThrottlingURLLoaderTest : public testing::Test {
 | 
| + public:
 | 
| +  ThrottlingURLLoaderTest() {}
 | 
| +
 | 
| + protected:
 | 
| +  // testing::Test implementation.
 | 
| +  void SetUp() override {
 | 
| +    auto throttle = base::MakeUnique<TestURLLoaderThrottle>();
 | 
| +    throttle_ = throttle.get();
 | 
| +
 | 
| +    throttles_.push_back(std::move(throttle));
 | 
| +  }
 | 
| +
 | 
| +  void CreateLoaderAndStart() {
 | 
| +    auto request = base::MakeUnique<ResourceRequest>();
 | 
| +    request->url = GURL("http://example.org");
 | 
| +    loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
 | 
| +        factory_.factory_ptr().get(), std::move(throttles_), 0, 0, 0,
 | 
| +        std::move(request), &client_);
 | 
| +    factory_.factory_ptr().FlushForTesting();
 | 
| +  }
 | 
| +
 | 
| +  // Be the first member so it is destroyed last.
 | 
| +  base::MessageLoop message_loop_;
 | 
| +
 | 
| +  std::unique_ptr<ThrottlingURLLoader> loader_;
 | 
| +  std::vector<std::unique_ptr<URLLoaderThrottle>> throttles_;
 | 
| +
 | 
| +  TestURLLoaderFactory factory_;
 | 
| +  TestURLLoaderClient client_;
 | 
| +
 | 
| +  // Owned by |throttles_| or |loader_|.
 | 
| +  TestURLLoaderThrottle* throttle_ = nullptr;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(ThrottlingURLLoaderTest);
 | 
| +};
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, CancelBeforeStart) {
 | 
| +  throttle_->set_will_start_request_callback(
 | 
| +      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
 | 
| +      }));
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +  run_loop.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, factory_.create_loader_and_start_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, DeferBeforeStart) {
 | 
| +  throttle_->set_will_start_request_callback(
 | 
| +      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        *defer = true;
 | 
| +      }));
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::OK, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, factory_.create_loader_and_start_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(0u, client_.on_complete_called());
 | 
| +
 | 
| +  throttle_->delegate()->Resume();
 | 
| +  factory_.factory_ptr().FlushForTesting();
 | 
| +
 | 
| +  EXPECT_EQ(1u, factory_.create_loader_and_start_called());
 | 
| +
 | 
| +  factory_.NotifyClientOnReceiveResponse();
 | 
| +  factory_.NotifyClientOnComplete(net::OK);
 | 
| +
 | 
| +  run_loop.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(1u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, CancelBeforeRedirect) {
 | 
| +  throttle_->set_will_redirect_request_callback(
 | 
| +      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
 | 
| +      }));
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +
 | 
| +  factory_.NotifyClientOnReceiveRedirect();
 | 
| +
 | 
| +  run_loop.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, DeferBeforeRedirect) {
 | 
| +  base::RunLoop run_loop1;
 | 
| +  throttle_->set_will_redirect_request_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure,
 | 
| +         URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        *defer = true;
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop1.QuitClosure()));
 | 
| +
 | 
| +  base::RunLoop run_loop2;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::ERR_UNEXPECTED, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop2.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +
 | 
| +  factory_.NotifyClientOnReceiveRedirect();
 | 
| +
 | 
| +  run_loop1.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  factory_.NotifyClientOnComplete(net::ERR_UNEXPECTED);
 | 
| +
 | 
| +  base::RunLoop run_loop3;
 | 
| +  run_loop3.RunUntilIdle();
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(0u, client_.on_complete_called());
 | 
| +
 | 
| +  throttle_->delegate()->Resume();
 | 
| +  run_loop2.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(1u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, CancelBeforeResponse) {
 | 
| +  throttle_->set_will_process_response_callback(
 | 
| +      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
 | 
| +      }));
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +
 | 
| +  factory_.NotifyClientOnReceiveResponse();
 | 
| +
 | 
| +  run_loop.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, DeferBeforeResponse) {
 | 
| +  base::RunLoop run_loop1;
 | 
| +  throttle_->set_will_process_response_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure,
 | 
| +         URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        *defer = true;
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop1.QuitClosure()));
 | 
| +
 | 
| +  base::RunLoop run_loop2;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::ERR_UNEXPECTED, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop2.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +
 | 
| +  factory_.NotifyClientOnReceiveResponse();
 | 
| +
 | 
| +  run_loop1.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  factory_.NotifyClientOnComplete(net::ERR_UNEXPECTED);
 | 
| +
 | 
| +  base::RunLoop run_loop3;
 | 
| +  run_loop3.RunUntilIdle();
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(0u, client_.on_complete_called());
 | 
| +
 | 
| +  throttle_->delegate()->Resume();
 | 
| +  run_loop2.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(1u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, ResumeNoOpIfNotDeferred) {
 | 
| +  auto resume_callback =
 | 
| +      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        delegate->Resume();
 | 
| +        delegate->Resume();
 | 
| +      });
 | 
| +  throttle_->set_will_start_request_callback(resume_callback);
 | 
| +  throttle_->set_will_redirect_request_callback(resume_callback);
 | 
| +  throttle_->set_will_process_response_callback(resume_callback);
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::OK, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +  factory_.NotifyClientOnReceiveRedirect();
 | 
| +  factory_.NotifyClientOnReceiveResponse();
 | 
| +  factory_.NotifyClientOnComplete(net::OK);
 | 
| +
 | 
| +  run_loop.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(1u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(1u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, CancelNoOpIfAlreadyCanceled) {
 | 
| +  throttle_->set_will_start_request_callback(
 | 
| +      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
 | 
| +        delegate->CancelWithError(net::ERR_UNEXPECTED);
 | 
| +      }));
 | 
| +
 | 
| +  base::RunLoop run_loop;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +  throttle_->delegate()->CancelWithError(net::ERR_INVALID_ARGUMENT);
 | 
| +  run_loop.Run();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, factory_.create_loader_and_start_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +TEST_F(ThrottlingURLLoaderTest, ResumeNoOpIfAlreadyCanceled) {
 | 
| +  throttle_->set_will_process_response_callback(
 | 
| +      base::Bind([](URLLoaderThrottle::Delegate* delegate, bool* defer) {
 | 
| +        delegate->CancelWithError(net::ERR_ACCESS_DENIED);
 | 
| +        delegate->Resume();
 | 
| +      }));
 | 
| +
 | 
| +  base::RunLoop run_loop1;
 | 
| +  client_.set_on_complete_callback(base::Bind(
 | 
| +      [](const base::Closure& quit_closure, int error) {
 | 
| +        EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
 | 
| +        quit_closure.Run();
 | 
| +      },
 | 
| +      run_loop1.QuitClosure()));
 | 
| +
 | 
| +  CreateLoaderAndStart();
 | 
| +
 | 
| +  factory_.NotifyClientOnReceiveResponse();
 | 
| +
 | 
| +  run_loop1.Run();
 | 
| +
 | 
| +  throttle_->delegate()->Resume();
 | 
| +
 | 
| +  base::RunLoop run_loop2;
 | 
| +  run_loop2.RunUntilIdle();
 | 
| +
 | 
| +  EXPECT_EQ(1u, throttle_->will_start_request_called());
 | 
| +  EXPECT_EQ(0u, throttle_->will_redirect_request_called());
 | 
| +  EXPECT_EQ(1u, throttle_->will_process_response_called());
 | 
| +
 | 
| +  EXPECT_EQ(0u, client_.on_received_response_called());
 | 
| +  EXPECT_EQ(0u, client_.on_received_redirect_called());
 | 
| +  EXPECT_EQ(1u, client_.on_complete_called());
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +}  // namespace content
 | 
| 
 |