root/components/policy/core/common/cloud/external_policy_data_updater_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CreateCallback
  2. SetUp
  3. CreateUpdater
  4. RequestExternalDataFetch
  5. RequestExternalDataFetch
  6. CreateRequest
  7. TEST_F
  8. TEST_F
  9. TEST_F
  10. TEST_F
  11. TEST_F
  12. TEST_F
  13. TEST_F
  14. TEST_F
  15. TEST_F
  16. TEST_F
  17. TEST_F
  18. TEST_F
  19. TEST_F
  20. TEST_F
  21. TEST_F
  22. TEST_F

// Copyright (c) 2013 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 "components/policy/core/common/cloud/external_policy_data_updater.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/test/test_pending_task.h"
#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
#include "components/policy/core/common/cloud/external_policy_data_fetcher.h"
#include "crypto/sha2.h"
#include "net/base/net_errors.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"

using testing::Mock;
using testing::Return;

namespace policy {

namespace {

const char* kExternalPolicyDataKeys[] = {"external_policy_data_1",
                                         "external_policy_data_2",
                                         "external_policy_data_3"};
const char* kExternalPolicyDataURLs[] = {"http://example.com/data_1",
                                         "http://example.com/data_2",
                                         "http://example.com/data_3"};
const char* kExternalPolicyDataPayload = "External policy data";

const int64 kExternalPolicyDataMaxSize = 5 * 1024 * 1024;  // 5 MB.

class MockFetchSuccessCallbackListener {
 public:
  MOCK_METHOD2(OnFetchSuccess, bool(const std::string&, const std::string&));

  ExternalPolicyDataUpdater::FetchSuccessCallback CreateCallback(
      const std::string& key);
};

ExternalPolicyDataUpdater::FetchSuccessCallback
    MockFetchSuccessCallbackListener::CreateCallback(const std::string& key) {
  return base::Bind(&MockFetchSuccessCallbackListener::OnFetchSuccess,
                    base::Unretained(this),
                    key);
}

}  // namespace

class ExternalPolicyDataUpdaterTest : public testing::Test {
 protected:
  virtual void SetUp() OVERRIDE;

  void CreateUpdater(size_t max_parallel_fetches);
  ExternalPolicyDataUpdater::Request CreateRequest(
      const std::string& url) const;
  void RequestExternalDataFetch(int key_index, int url_index);
  void RequestExternalDataFetch(int index);

  net::TestURLFetcherFactory fetcher_factory_;
  MockFetchSuccessCallbackListener callback_listener_;
  scoped_refptr<base::TestSimpleTaskRunner> backend_task_runner_;
  scoped_refptr<base::TestSimpleTaskRunner> io_task_runner_;
  scoped_ptr<ExternalPolicyDataFetcherBackend> fetcher_backend_;
  scoped_ptr<ExternalPolicyDataUpdater> updater_;
};

void ExternalPolicyDataUpdaterTest::SetUp() {
  fetcher_factory_.set_remove_fetcher_on_delete(true);
  backend_task_runner_ = new base::TestSimpleTaskRunner();
  io_task_runner_ = new base::TestSimpleTaskRunner();
}

void ExternalPolicyDataUpdaterTest::CreateUpdater(size_t max_parallel_fetches) {
  fetcher_backend_.reset(new ExternalPolicyDataFetcherBackend(
      io_task_runner_,
      scoped_refptr<net::URLRequestContextGetter>()));
  updater_.reset(new ExternalPolicyDataUpdater(
      backend_task_runner_,
      fetcher_backend_->CreateFrontend(backend_task_runner_),
      max_parallel_fetches));
}

void ExternalPolicyDataUpdaterTest::RequestExternalDataFetch(int key_index,
                                                             int url_index) {
  updater_->FetchExternalData(
      kExternalPolicyDataKeys[key_index],
      CreateRequest(kExternalPolicyDataURLs[url_index]),
      callback_listener_.CreateCallback(kExternalPolicyDataKeys[key_index]));
  io_task_runner_->RunUntilIdle();
  backend_task_runner_->RunPendingTasks();
}

void ExternalPolicyDataUpdaterTest::RequestExternalDataFetch(int index) {
  RequestExternalDataFetch(index, index);
}

ExternalPolicyDataUpdater::Request
    ExternalPolicyDataUpdaterTest::CreateRequest(const std::string& url) const {
  return ExternalPolicyDataUpdater::Request(
      url,
      crypto::SHA256HashString(kExternalPolicyDataPayload),
      kExternalPolicyDataMaxSize);
}

TEST_F(ExternalPolicyDataUpdaterTest, FetchSuccess) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make two fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);

  // Verify that the second fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Complete the first fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[0],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the second fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that no retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, PayloadSizeExceedsLimit) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make two fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);

  // Verify that the second fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Indicate that the payload size will exceed allowed maximum.
  fetcher->delegate()->OnURLFetchDownloadProgress(
      fetcher,
      kExternalPolicyDataMaxSize + 1,
      -1);
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the second fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that a retry has been scheduled for the first fetch.
  EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());
}

TEST_F(ExternalPolicyDataUpdaterTest, FetchFailure) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make two fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);

  // Verify that the second fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Make the first fetch fail due to an interrupted connection.
  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
                                            net::ERR_NETWORK_CHANGED));
  fetcher->delegate()->OnURLFetchComplete(fetcher);
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the second fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that a retry has been scheduled for the first fetch.
  EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());
}

TEST_F(ExternalPolicyDataUpdaterTest, ServerFailure) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make two fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);

  // Verify that the second fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Make the first fetch fail with a server error.
  fetcher->set_response_code(500);
  fetcher->delegate()->OnURLFetchComplete(fetcher);
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the second fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that a retry has been scheduled for the first fetch.
  EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());
}

TEST_F(ExternalPolicyDataUpdaterTest, RetryLimit) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make a fetch request.
  RequestExternalDataFetch(0);

  int fetcher_id = 0;

  // Verify that client failures cause the fetch to be retried three times.
  for (int i = 0; i < 3; ++i) {
    // Verify that the fetch has been (re)started.
    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(fetcher_id);
    ASSERT_TRUE(fetcher);
    EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

    // Make the fetch fail with a client error.
    fetcher->set_response_code(400);
    fetcher->delegate()->OnURLFetchComplete(fetcher);
    backend_task_runner_->RunPendingTasks();
    io_task_runner_->RunUntilIdle();

    // Verify that the fetch is no longer running.
    EXPECT_FALSE(fetcher_factory_.GetFetcherByID(fetcher_id));

    // Verify that a retry has been scheduled.
    EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());

    // Fast-forward time to the scheduled retry.
    backend_task_runner_->RunPendingTasks();
    io_task_runner_->RunUntilIdle();
    EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
    ++fetcher_id;
  }

  // Verify that the fetch has been restarted.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(fetcher_id);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Make the fetch fail once more.
  fetcher->set_response_code(400);
  fetcher->delegate()->OnURLFetchComplete(fetcher);
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();
  ++fetcher_id;

  // Verify that the fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(fetcher_id));

  // Verify that no further retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, RetryWithBackoff) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make a fetch request.
  RequestExternalDataFetch(0);

  base::TimeDelta expected_delay = base::TimeDelta::FromSeconds(60);
  const base::TimeDelta delay_cap = base::TimeDelta::FromHours(12);

  int fetcher_id = 0;

  // The backoff delay is capped at 12 hours, which is reached after 10 retries:
  // 60 * 2^10 == 61440 > 43200 == 12 * 60 * 60
  for (int i = 0; i < 20; ++i) {
    // Verify that the fetch has been (re)started.
    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(fetcher_id);
    ASSERT_TRUE(fetcher);
    EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

    // Make the fetch fail with a server error.
    fetcher->set_response_code(500);
    fetcher->delegate()->OnURLFetchComplete(fetcher);
    backend_task_runner_->RunPendingTasks();
    io_task_runner_->RunUntilIdle();

    // Verify that the fetch is no longer running.
    EXPECT_FALSE(fetcher_factory_.GetFetcherByID(fetcher_id));

    // Verify that a retry has been scheduled.
    EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());

    // Verify that the retry delay has been doubled, with random jitter from 80%
    // to 100%.
    const base::TestPendingTask& task =
        backend_task_runner_->GetPendingTasks().front();
    EXPECT_GT(task.delay,
              base::TimeDelta::FromMilliseconds(
                  0.799 * expected_delay.InMilliseconds()));
    EXPECT_LE(task.delay, expected_delay);

    if (i < 10) {
      // The delay cap has not been reached yet.
      EXPECT_LT(expected_delay, delay_cap);
      expected_delay *= 2;

      if (i == 9) {
        // The last doubling reached the cap.
        EXPECT_GT(expected_delay, delay_cap);
        expected_delay = delay_cap;
      }
    }

    // Fast-forward time to the scheduled retry.
    backend_task_runner_->RunPendingTasks();
    io_task_runner_->RunUntilIdle();
    EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
    ++fetcher_id;
  }
}

TEST_F(ExternalPolicyDataUpdaterTest, HashInvalid) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make two fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);

  // Verify that the second fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Make the first fetch retrieve data whose hash does not match the expected
  // value.
  fetcher->set_response_code(200);
  fetcher->SetResponseString("Invalid external policy data");
  fetcher->delegate()->OnURLFetchComplete(fetcher);
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the second fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that a retry has been scheduled for the first fetch.
  EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());
}

TEST_F(ExternalPolicyDataUpdaterTest, DataRejectedByCallback) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make a fetch request.
  RequestExternalDataFetch(0);

  // Verify that the fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Complete the fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Reject the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[0],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(false));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that a retry has been scheduled.
  EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());

  // Fast-forward time to the scheduled retry.
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());

  // Verify that the fetch has been restarted.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Complete the fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked this time.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[0],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that no retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, URLChanged) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make a fetch request.
  RequestExternalDataFetch(0);

  // Verify that the fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Make another fetch request with the same key but an updated URL.
  RequestExternalDataFetch(0, 1);

  // Verify that the original fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that a new fetch has been started with the updated URL.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that no retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, JobInvalidated) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make two fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);

  // Verify that the second fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Make another fetch request with the same key as the second request but an
  // updated URL.
  RequestExternalDataFetch(1, 2);

  // Verify that the first fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Verify that the second fetch has still not been started.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Make the first fetch fail with a server error.
  fetcher->set_response_code(500);
  fetcher->delegate()->OnURLFetchComplete(fetcher);
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the second fetch was invalidated and the third fetch has been
  // started instead.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());
}

TEST_F(ExternalPolicyDataUpdaterTest, FetchCanceled) {
  // Create an updater that runs one fetch at a time.
  CreateUpdater(1);

  // Make a fetch request.
  RequestExternalDataFetch(0);

  // Verify that the fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Cancel the fetch request.
  updater_->CancelExternalDataFetch(kExternalPolicyDataKeys[0]);
  io_task_runner_->RunUntilIdle();
  backend_task_runner_->RunPendingTasks();

  // Verify that the fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that no retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, ParallelJobs) {
  // Create an updater that runs up to two fetches in parallel.
  CreateUpdater(2);

  // Make three fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);
  RequestExternalDataFetch(2);

  // Verify that the third fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that the second fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that the first fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Complete the first fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[0],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the third fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());

  // Verify that the second fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Complete the second fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[1],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the second fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the third fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());

  // Complete the third fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[2],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the third fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that no retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, ParallelJobsFinishingOutOfOrder) {
  // Create an updater that runs up to two fetches in parallel.
  CreateUpdater(2);

  // Make three fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);
  RequestExternalDataFetch(2);

  // Verify that the third fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Verify that the second fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Complete the second fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[1],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the second fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the third fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());

  // Verify that the first fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Complete the first fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[0],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the third fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());

  // Complete the third fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[2],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the third fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that no retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, ParallelJobsWithRetry) {
  // Create an updater that runs up to two fetches in parallel.
  CreateUpdater(2);

  // Make three fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);
  RequestExternalDataFetch(2);

  // Verify that the third fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that the second fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that the first fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Make the first fetch fail with a client error.
  fetcher->set_response_code(400);
  fetcher->delegate()->OnURLFetchComplete(fetcher);
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();

  // Verify that the first fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the third fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());

  // Verify that a retry has been scheduled for the first fetch.
  EXPECT_EQ(1u, backend_task_runner_->GetPendingTasks().size());

  // Fast-forward time to the scheduled retry.
  backend_task_runner_->RunPendingTasks();
  io_task_runner_->RunUntilIdle();
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());

  // Verify that the first fetch has not been restarted yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(3));

  // Complete the third fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[2],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the third fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that the second fetch is still running
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that the first fetch has been restarted.
  fetcher = fetcher_factory_.GetFetcherByID(3);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Verify that no further retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, ParallelJobsWithCancel) {
  // Create an updater that runs up to two fetches in parallel.
  CreateUpdater(2);

  // Make three fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);
  RequestExternalDataFetch(2);

  // Verify that the third fetch has not been started yet.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that the second fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Verify that the first fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Cancel the fetch request.
  updater_->CancelExternalDataFetch(kExternalPolicyDataKeys[0]);
  io_task_runner_->RunUntilIdle();
  backend_task_runner_->RunPendingTasks();

  // Verify that the fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(0));

  // Verify that the third fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());

  // Verify that the second fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Complete the second fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[1],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the second fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the third fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());

  // Complete the third fetch.
  fetcher->set_response_code(200);
  fetcher->SetResponseString(kExternalPolicyDataPayload);
  fetcher->delegate()->OnURLFetchComplete(fetcher);

  // Accept the data when the callback is invoked.
  EXPECT_CALL(callback_listener_,
              OnFetchSuccess(kExternalPolicyDataKeys[2],
                             kExternalPolicyDataPayload))
      .Times(1)
      .WillOnce(Return(true));
  backend_task_runner_->RunPendingTasks();
  Mock::VerifyAndClearExpectations(&callback_listener_);
  io_task_runner_->RunUntilIdle();

  // Verify that the third fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(2));

  // Verify that no retries have been scheduled.
  EXPECT_TRUE(backend_task_runner_->GetPendingTasks().empty());
}

TEST_F(ExternalPolicyDataUpdaterTest, ParallelJobsWithInvalidatedJob) {
  // Create an updater that runs up to two fetches in parallel.
  CreateUpdater(2);

  // Make two fetch requests.
  RequestExternalDataFetch(0);
  RequestExternalDataFetch(1);

  // Verify that the first fetch has been started.
  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Verify that the second fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(1);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[1]), fetcher->GetOriginalURL());

  // Make another fetch request with the same key as the second request but an
  // updated URL.
  RequestExternalDataFetch(1, 2);

  // Verify that the first fetch is still running.
  fetcher = fetcher_factory_.GetFetcherByID(0);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[0]), fetcher->GetOriginalURL());

  // Verify that the second fetch is no longer running.
  EXPECT_FALSE(fetcher_factory_.GetFetcherByID(1));

  // Verify that the third fetch has been started.
  fetcher = fetcher_factory_.GetFetcherByID(2);
  ASSERT_TRUE(fetcher);
  EXPECT_EQ(GURL(kExternalPolicyDataURLs[2]), fetcher->GetOriginalURL());
}

}  // namespace policy

/* [<][>][^][v][top][bottom][index][help] */