// Copyright 2015 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/browser/background_sync/background_sync_manager.h"

#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_source.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "content/browser/background_sync/background_sync_status.h"
#include "content/browser/browser_thread_impl.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_storage.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/network_change_notifier.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace content {

namespace {

const char kPattern1[] = "https://example.com/a";
const char kPattern2[] = "https://example.com/b";
const char kScript1[] = "https://example.com/a/script.js";
const char kScript2[] = "https://example.com/b/script.js";
const int kRenderProcessId = 99;

void RegisterServiceWorkerCallback(bool* called,
                                   int64* store_registration_id,
                                   ServiceWorkerStatusCode status,
                                   const std::string& status_message,
                                   int64 registration_id) {
  EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
  *called = true;
  *store_registration_id = registration_id;
}

void FindServiceWorkerRegistrationCallback(
    scoped_refptr<ServiceWorkerRegistration>* out_registration,
    ServiceWorkerStatusCode status,
    const scoped_refptr<ServiceWorkerRegistration>& registration) {
  EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status);
  *out_registration = registration;
}

void UnregisterServiceWorkerCallback(bool* called,
                                     ServiceWorkerStatusCode code) {
  EXPECT_EQ(SERVICE_WORKER_OK, code);
  *called = true;
}

void OneShotSuccessfulCallback(
    int* count,
    const scoped_refptr<ServiceWorkerVersion>& active_version,
    const ServiceWorkerVersion::StatusCallback& callback) {
  *count += 1;
  callback.Run(SERVICE_WORKER_OK);
}

void OneShotFailedCallback(
    int* count,
    const scoped_refptr<ServiceWorkerVersion>& active_version,
    const ServiceWorkerVersion::StatusCallback& callback) {
  *count += 1;
  callback.Run(SERVICE_WORKER_ERROR_FAILED);
}

void OneShotDelayedCallback(
    int* count,
    ServiceWorkerVersion::StatusCallback* out_callback,
    const scoped_refptr<ServiceWorkerVersion>& active_version,
    const ServiceWorkerVersion::StatusCallback& callback) {
  *count += 1;
  *out_callback = callback;
}

class TestPowerSource : public base::PowerMonitorSource {
 public:
  void GeneratePowerStateEvent(bool on_battery_power) {
    test_on_battery_power_ = on_battery_power;
    ProcessPowerEvent(POWER_STATE_EVENT);
  }

 private:
  bool IsOnBatteryPowerImpl() final { return test_on_battery_power_; }
  bool test_on_battery_power_ = false;
};

}  // namespace

// A BackgroundSyncManager that can simulate delaying and corrupting the backend
// storage and service worker onsync events.
class TestBackgroundSyncManager : public BackgroundSyncManager {
 public:
  using OneShotCallback =
      base::Callback<void(const scoped_refptr<ServiceWorkerVersion>&,
                          const ServiceWorkerVersion::StatusCallback&)>;

  explicit TestBackgroundSyncManager(
      const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
      : BackgroundSyncManager(service_worker_context) {}

  void DoInit() { Init(); }

  void StoreDataInBackendContinue(
      int64 sw_registration_id,
      const GURL& origin,
      const std::string& key,
      const std::string& data,
      const ServiceWorkerStorage::StatusCallback& callback) {
    BackgroundSyncManager::StoreDataInBackend(sw_registration_id, origin, key,
                                              data, callback);
  }

  void GetDataFromBackendContinue(
      const std::string& key,
      const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
          callback) {
    BackgroundSyncManager::GetDataFromBackend(key, callback);
  }

  void Continue() {
    continuation_.Run();
    continuation_.Reset();
  }

  void set_corrupt_backend(bool corrupt_backend) {
    corrupt_backend_ = corrupt_backend;
  }
  void set_delay_backend(bool delay_backend) { delay_backend_ = delay_backend; }
  void set_one_shot_callback(const OneShotCallback& callback) {
    one_shot_callback_ = callback;
  }

 protected:
  void StoreDataInBackend(
      int64 sw_registration_id,
      const GURL& origin,
      const std::string& key,
      const std::string& data,
      const ServiceWorkerStorage::StatusCallback& callback) override {
    EXPECT_TRUE(continuation_.is_null());
    if (corrupt_backend_) {
      base::ThreadTaskRunnerHandle::Get()->PostTask(
          FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
      return;
    }
    continuation_ =
        base::Bind(&TestBackgroundSyncManager::StoreDataInBackendContinue,
                   base::Unretained(this), sw_registration_id, origin, key,
                   data, callback);
    if (delay_backend_)
      return;

    Continue();
  }

  void GetDataFromBackend(
      const std::string& key,
      const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
          callback) override {
    EXPECT_TRUE(continuation_.is_null());
    if (corrupt_backend_) {
      base::ThreadTaskRunnerHandle::Get()->PostTask(
          FROM_HERE,
          base::Bind(callback, std::vector<std::pair<int64, std::string>>(),
                     SERVICE_WORKER_ERROR_FAILED));
      return;
    }
    continuation_ =
        base::Bind(&TestBackgroundSyncManager::GetDataFromBackendContinue,
                   base::Unretained(this), key, callback);
    if (delay_backend_)
      return;

    Continue();
  }

  void FireOneShotSync(
      const BackgroundSyncRegistration& registration,
      const scoped_refptr<ServiceWorkerVersion>& active_version,
      const ServiceWorkerVersion::StatusCallback& callback) override {
    if (one_shot_callback_.is_null()) {
      BackgroundSyncManager::FireOneShotSync(registration, active_version,
                                             callback);
    } else {
      one_shot_callback_.Run(active_version, callback);
    }
  }

 private:
  bool corrupt_backend_ = false;
  bool delay_backend_ = false;
  base::Closure continuation_;
  OneShotCallback one_shot_callback_;
};

class BackgroundSyncManagerTest : public testing::Test {
 public:
  BackgroundSyncManagerTest()
      : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
        network_change_notifier_(net::NetworkChangeNotifier::CreateMock()),
        test_background_sync_manager_(nullptr),
        callback_status_(BACKGROUND_SYNC_STATUS_OK),
        callback_sw_status_code_(SERVICE_WORKER_OK),
        sync_events_called_(0) {
    sync_options_1_.tag = "foo";
    sync_options_1_.periodicity = SYNC_ONE_SHOT;
    sync_options_1_.network_state = NETWORK_STATE_ONLINE;
    sync_options_1_.power_state = POWER_STATE_AUTO;

    sync_options_2_.tag = "bar";
    sync_options_2_.periodicity = SYNC_ONE_SHOT;
    sync_options_2_.network_state = NETWORK_STATE_ONLINE;
    sync_options_2_.power_state = POWER_STATE_AUTO;
  }

  void SetUp() override {
    helper_.reset(
        new EmbeddedWorkerTestHelper(base::FilePath(), kRenderProcessId));

    power_monitor_source_ = new TestPowerSource();
    // power_monitor_ takes ownership of power_monitor_source.
    power_monitor_.reset(new base::PowerMonitor(
        scoped_ptr<base::PowerMonitorSource>(power_monitor_source_)));

    SetOnBatteryPower(false);

    SetupBackgroundSyncManager();

    // Wait for storage to finish initializing before registering service
    // workers.
    base::RunLoop().RunUntilIdle();
    RegisterServiceWorkers();
  }

  void RegisterServiceWorkers() {
    bool called_1 = false;
    bool called_2 = false;
    helper_->context()->RegisterServiceWorker(
        GURL(kPattern1), GURL(kScript1), NULL,
        base::Bind(&RegisterServiceWorkerCallback, &called_1,
                   &sw_registration_id_1_));

    helper_->context()->RegisterServiceWorker(
        GURL(kPattern2), GURL(kScript2), NULL,
        base::Bind(&RegisterServiceWorkerCallback, &called_2,
                   &sw_registration_id_2_));
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(called_1);
    EXPECT_TRUE(called_2);

    // Register window clients for the service workers
    host_1_.reset(new ServiceWorkerProviderHost(
        34 /* dummy render proces id */, MSG_ROUTING_NONE /* render_frame_id */,
        1 /* dummy provider id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
        helper_->context()->AsWeakPtr(), nullptr));
    host_1_->SetDocumentUrl(GURL(kPattern1));
    host_2_.reset(new ServiceWorkerProviderHost(
        34 /* dummy render proces id */, MSG_ROUTING_NONE /* render_frame_id */,
        1 /* dummy provider id */, SERVICE_WORKER_PROVIDER_FOR_WINDOW,
        helper_->context()->AsWeakPtr(), nullptr));
    host_2_->SetDocumentUrl(GURL(kPattern2));

    // Hang onto the registrations as they need to be "live" when
    // calling BackgroundSyncManager::Register.
    helper_->context_wrapper()->FindRegistrationForId(
        sw_registration_id_1_, GURL(kPattern1).GetOrigin(),
        base::Bind(FindServiceWorkerRegistrationCallback, &sw_registration_1_));

    helper_->context_wrapper()->FindRegistrationForId(
        sw_registration_id_2_, GURL(kPattern1).GetOrigin(),
        base::Bind(FindServiceWorkerRegistrationCallback, &sw_registration_2_));
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(sw_registration_1_);
    EXPECT_TRUE(sw_registration_2_);

    sw_registration_1_->active_version()->AddControllee(host_1_.get());
    sw_registration_2_->active_version()->AddControllee(host_2_.get());
  }

  void RemoveWindowClients() {
    sw_registration_1_->active_version()->RemoveControllee(host_1_.get());
    sw_registration_2_->active_version()->RemoveControllee(host_2_.get());
  }

  void SetNetwork(net::NetworkChangeNotifier::ConnectionType connection_type) {
    net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
        connection_type);
    base::RunLoop().RunUntilIdle();
  }

  void SetOnBatteryPower(bool on_battery_power) {
    power_monitor_source_->GeneratePowerStateEvent(on_battery_power);
    base::RunLoop().RunUntilIdle();
  }

  void StatusAndRegistrationCallback(
      bool* was_called,
      BackgroundSyncStatus status,
      const BackgroundSyncRegistration& registration) {
    *was_called = true;
    callback_status_ = status;
    callback_registration_ = registration;
  }

  void StatusAndRegistrationsCallback(
      bool* was_called,
      BackgroundSyncStatus status,
      const std::vector<BackgroundSyncRegistration>& registrations) {
    *was_called = true;
    callback_status_ = status;
    callback_registrations_ = registrations;
  }

  void StatusCallback(bool* was_called, BackgroundSyncStatus status) {
    *was_called = true;
    callback_status_ = status;
  }

 protected:
  void CreateBackgroundSyncManager() {
    test_background_sync_manager_ =
        new TestBackgroundSyncManager(helper_->context_wrapper());
    background_sync_manager_.reset(test_background_sync_manager_);
  }

  void InitBackgroundSyncManager() {
    test_background_sync_manager_->DoInit();

    // Many tests do not expect the sync event to fire immediately after
    // register (and cleanup up the sync registrations).  Tests can control when
    // the sync event fires by manipulating the network state as needed.
    // NOTE: The setup of the network connection must happen after the
    //       BackgroundSyncManager has been setup.
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
  }

  void SetupBackgroundSyncManager() {
    CreateBackgroundSyncManager();
    InitBackgroundSyncManager();
  }

  void SetupCorruptBackgroundSyncManager() {
    CreateBackgroundSyncManager();
    test_background_sync_manager_->set_corrupt_backend(true);
    InitBackgroundSyncManager();
  }

  void SetupDelayedBackgroundSyncManager() {
    CreateBackgroundSyncManager();
    test_background_sync_manager_->set_delay_backend(true);
    InitBackgroundSyncManager();
  }

  void DeleteBackgroundSyncManager() {
    background_sync_manager_.reset();
    test_background_sync_manager_ = nullptr;
  }

  bool Register(const BackgroundSyncRegistrationOptions& sync_options) {
    return RegisterWithServiceWorkerId(sw_registration_id_1_, sync_options);
  }

  bool RegisterWithServiceWorkerId(
      int64 sw_registration_id,
      const BackgroundSyncRegistrationOptions& options) {
    bool was_called = false;
    background_sync_manager_->Register(
        sw_registration_id, options,
        base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                   base::Unretained(this), &was_called));
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(was_called);
    return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
  }

  bool Unregister(const BackgroundSyncRegistration& sync_registration) {
    return UnregisterWithServiceWorkerId(sw_registration_id_1_,
                                         sync_registration);
  }

  bool UnregisterWithServiceWorkerId(
      int64 sw_registration_id,
      const BackgroundSyncRegistration& sync_registration) {
    bool was_called = false;
    background_sync_manager_->Unregister(
        sw_registration_id, sync_registration.options()->tag,
        sync_registration.options()->periodicity, sync_registration.id(),
        base::Bind(&BackgroundSyncManagerTest::StatusCallback,
                   base::Unretained(this), &was_called));
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(was_called);
    return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
  }

  bool GetRegistration(const BackgroundSyncRegistrationOptions& sync_options) {
    return GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
                                              sync_options);
  }

  bool GetRegistrationWithServiceWorkerId(
      int64 sw_registration_id,
      const BackgroundSyncRegistrationOptions& sync_options) {
    bool was_called = false;
    background_sync_manager_->GetRegistration(
        sw_registration_id, sync_options.tag, sync_options.periodicity,
        base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                   base::Unretained(this), &was_called));
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(was_called);

    if (callback_status_ == BACKGROUND_SYNC_STATUS_OK) {
      EXPECT_STREQ(sync_options.tag.c_str(),
                   callback_registration_.options()->tag.c_str());
    }

    return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
  }

  bool GetRegistrations(SyncPeriodicity periodicity) {
    return GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
                                              periodicity);
  }

  bool GetRegistrationWithServiceWorkerId(int64 sw_registration_id,
                                          SyncPeriodicity periodicity) {
    bool was_called = false;
    background_sync_manager_->GetRegistrations(
        sw_registration_id, periodicity,
        base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationsCallback,
                   base::Unretained(this), &was_called));
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(was_called);

    return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
  }

  void StorageRegistrationCallback(ServiceWorkerStatusCode result) {
    callback_sw_status_code_ = result;
  }

  void UnregisterServiceWorker(uint64 sw_registration_id) {
    bool called = false;
    helper_->context()->UnregisterServiceWorker(
        PatternForSWId(sw_registration_id),
        base::Bind(&UnregisterServiceWorkerCallback, &called));
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(called);
  }

  GURL PatternForSWId(int64 sw_id) {
    EXPECT_TRUE(sw_id == sw_registration_id_1_ ||
                sw_id == sw_registration_id_2_);
    return sw_id == sw_registration_id_1_ ? GURL(kPattern1) : GURL(kPattern2);
  }

  void SetupForSyncEvent(
      const TestBackgroundSyncManager::OneShotCallback& callback) {
    test_background_sync_manager_->set_one_shot_callback(callback);
    SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
  }

  void InitSyncEventTest() {
    SetupForSyncEvent(
        base::Bind(OneShotSuccessfulCallback, &sync_events_called_));
  }

  void InitFailedSyncEventTest() {
    SetupForSyncEvent(base::Bind(OneShotFailedCallback, &sync_events_called_));
  }

  void InitDelayedSyncEventTest() {
    SetupForSyncEvent(base::Bind(OneShotDelayedCallback, &sync_events_called_,
                                 &sync_fired_callback_));
  }

  void RegisterAndVerifySyncEventDelayed(
      const BackgroundSyncRegistrationOptions& sync_options) {
    int sync_events_called = sync_events_called_;
    EXPECT_TRUE(sync_fired_callback_.is_null());

    EXPECT_TRUE(Register(sync_options));

    EXPECT_EQ(sync_events_called + 1, sync_events_called_);
    EXPECT_TRUE(GetRegistration(sync_options_1_));
    EXPECT_FALSE(sync_fired_callback_.is_null());
  }

  TestBrowserThreadBundle browser_thread_bundle_;
  scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
  TestPowerSource* power_monitor_source_;  // owned by power_monitor_
  scoped_ptr<base::PowerMonitor> power_monitor_;
  scoped_ptr<EmbeddedWorkerTestHelper> helper_;
  scoped_ptr<BackgroundSyncManager> background_sync_manager_;
  TestBackgroundSyncManager* test_background_sync_manager_;

  scoped_ptr<ServiceWorkerProviderHost> host_1_;
  scoped_ptr<ServiceWorkerProviderHost> host_2_;
  int64 sw_registration_id_1_;
  int64 sw_registration_id_2_;
  scoped_refptr<ServiceWorkerRegistration> sw_registration_1_;
  scoped_refptr<ServiceWorkerRegistration> sw_registration_2_;

  BackgroundSyncRegistrationOptions sync_options_1_;
  BackgroundSyncRegistrationOptions sync_options_2_;

  // Callback values.
  BackgroundSyncStatus callback_status_;
  BackgroundSyncRegistration callback_registration_;
  std::vector<BackgroundSyncRegistration> callback_registrations_;
  ServiceWorkerStatusCode callback_sw_status_code_;
  int sync_events_called_;
  ServiceWorkerVersion::StatusCallback sync_fired_callback_;
};

TEST_F(BackgroundSyncManagerTest, Register) {
  EXPECT_TRUE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RegistractionIntact) {
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_STREQ(sync_options_1_.tag.c_str(),
               callback_registration_.options()->tag.c_str());
  EXPECT_TRUE(callback_registration_.IsValid());
}

TEST_F(BackgroundSyncManagerTest, RegisterWithoutLiveSWRegistration) {
  sw_registration_1_ = nullptr;
  EXPECT_FALSE(Register(sync_options_1_));
  EXPECT_EQ(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER, callback_status_);
}

TEST_F(BackgroundSyncManagerTest, RegisterWithoutActiveSWRegistration) {
  sw_registration_1_->UnsetVersion(sw_registration_1_->active_version());
  EXPECT_FALSE(Register(sync_options_1_));
  EXPECT_EQ(BACKGROUND_SYNC_STATUS_NO_SERVICE_WORKER, callback_status_);
}

TEST_F(BackgroundSyncManagerTest, RegisterExistingKeepsId) {
  EXPECT_TRUE(Register(sync_options_1_));
  BackgroundSyncRegistration first_registration = callback_registration_;
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(callback_registration_.Equals(first_registration));
  EXPECT_EQ(first_registration.id(), callback_registration_.id());
}

TEST_F(BackgroundSyncManagerTest, RegisterOverwrites) {
  EXPECT_TRUE(Register(sync_options_1_));
  BackgroundSyncRegistration first_registration = callback_registration_;

  sync_options_1_.min_period = 100;
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_LT(first_registration.id(), callback_registration_.id());
  EXPECT_FALSE(callback_registration_.Equals(first_registration));
}

TEST_F(BackgroundSyncManagerTest, RegisterOverlappingPeriodicAndOneShotTags) {
  // Registrations with the same tags but different periodicities should not
  // collide.
  sync_options_1_.tag = "";
  sync_options_2_.tag = "";
  sync_options_1_.periodicity = SYNC_PERIODIC;
  sync_options_2_.periodicity = SYNC_ONE_SHOT;
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_EQ(SYNC_PERIODIC, callback_registration_.options()->periodicity);
  EXPECT_TRUE(GetRegistration(sync_options_2_));
  EXPECT_EQ(SYNC_ONE_SHOT, callback_registration_.options()->periodicity);
}

TEST_F(BackgroundSyncManagerTest, RegisterBadBackend) {
  test_background_sync_manager_->set_corrupt_backend(true);
  EXPECT_FALSE(Register(sync_options_1_));
  test_background_sync_manager_->set_corrupt_backend(false);
  EXPECT_FALSE(Register(sync_options_1_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, TwoRegistrations) {
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationNonExisting) {
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationExisting) {
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationBadBackend) {
  EXPECT_TRUE(Register(sync_options_1_));
  test_background_sync_manager_->set_corrupt_backend(true);
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(Register(sync_options_2_));
  // Registration should have discovered the bad backend and disabled the
  // BackgroundSyncManager.
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  test_background_sync_manager_->set_corrupt_backend(false);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsZero) {
  EXPECT_TRUE(GetRegistrations(SYNC_ONE_SHOT));
  EXPECT_EQ(0u, callback_registrations_.size());
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsOne) {
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(GetRegistrations(sync_options_1_.periodicity));

  EXPECT_EQ(1u, callback_registrations_.size());
  sync_options_1_.Equals(*callback_registrations_[0].options());
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsTwo) {
  EXPECT_EQ(sync_options_1_.periodicity, sync_options_2_.periodicity);

  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
  EXPECT_TRUE(GetRegistrations(sync_options_1_.periodicity));

  EXPECT_EQ(2u, callback_registrations_.size());
  sync_options_1_.Equals(*callback_registrations_[0].options());
  sync_options_2_.Equals(*callback_registrations_[1].options());
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsPeriodicity) {
  sync_options_1_.periodicity = SYNC_ONE_SHOT;
  sync_options_2_.periodicity = SYNC_PERIODIC;
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));

  EXPECT_TRUE(GetRegistrations(SYNC_ONE_SHOT));
  EXPECT_EQ(1u, callback_registrations_.size());
  sync_options_1_.Equals(*callback_registrations_[0].options());

  EXPECT_TRUE(GetRegistrations(SYNC_PERIODIC));
  EXPECT_EQ(1u, callback_registrations_.size());
  sync_options_2_.Equals(*callback_registrations_[0].options());
}

TEST_F(BackgroundSyncManagerTest, GetRegistrationsBadBackend) {
  EXPECT_TRUE(Register(sync_options_1_));
  test_background_sync_manager_->set_corrupt_backend(true);
  EXPECT_TRUE(GetRegistrations(sync_options_1_.periodicity));
  EXPECT_FALSE(Register(sync_options_2_));
  // Registration should have discovered the bad backend and disabled the
  // BackgroundSyncManager.
  EXPECT_FALSE(GetRegistrations(sync_options_1_.periodicity));
  test_background_sync_manager_->set_corrupt_backend(false);
  EXPECT_FALSE(GetRegistrations(sync_options_1_.periodicity));
}

TEST_F(BackgroundSyncManagerTest, Unregister) {
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, UnregisterWrongId) {
  EXPECT_TRUE(Register(sync_options_1_));
  callback_registration_.set_id(callback_registration_.id() + 1);
  EXPECT_FALSE(Unregister(callback_registration_));
}

TEST_F(BackgroundSyncManagerTest, Reregister) {
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_TRUE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, UnregisterNonExisting) {
  BackgroundSyncRegistration nonexistant_registration;
  nonexistant_registration.set_id(1);
  EXPECT_FALSE(Unregister(nonexistant_registration));
  EXPECT_EQ(BACKGROUND_SYNC_STATUS_NOT_FOUND, callback_status_);
}

TEST_F(BackgroundSyncManagerTest, UnregisterSecond) {
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, UnregisterBadBackend) {
  sync_options_1_.min_period += 1;
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
  test_background_sync_manager_->set_corrupt_backend(true);
  EXPECT_FALSE(Unregister(callback_registration_));
  // Unregister should have discovered the bad backend and disabled the
  // BackgroundSyncManager.
  test_background_sync_manager_->set_corrupt_backend(false);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, RegistrationIncreasesId) {
  EXPECT_TRUE(Register(sync_options_1_));
  BackgroundSyncRegistration registered_sync = callback_registration_;
  BackgroundSyncRegistration::RegistrationId cur_id =
      callback_registration_.id();

  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
  EXPECT_LT(cur_id, callback_registration_.id());
  cur_id = callback_registration_.id();

  EXPECT_TRUE(Unregister(registered_sync));
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_LT(cur_id, callback_registration_.id());
}

TEST_F(BackgroundSyncManagerTest, RebootRecovery) {
  EXPECT_TRUE(Register(sync_options_1_));

  SetupBackgroundSyncManager();

  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, RebootRecoveryTwoServiceWorkers) {
  EXPECT_TRUE(
      RegisterWithServiceWorkerId(sw_registration_id_1_, sync_options_1_));
  EXPECT_TRUE(
      RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_2_));

  SetupBackgroundSyncManager();

  EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
                                                 sync_options_1_));
  EXPECT_FALSE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
                                                  sync_options_2_));
  EXPECT_FALSE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
                                                  sync_options_1_));
  EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
                                                 sync_options_2_));

  EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_1_,
                                                 sync_options_1_));
  EXPECT_TRUE(GetRegistrationWithServiceWorkerId(sw_registration_id_2_,
                                                 sync_options_2_));

  EXPECT_TRUE(
      RegisterWithServiceWorkerId(sw_registration_id_1_, sync_options_2_));
  EXPECT_TRUE(
      RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, InitWithBadBackend) {
  SetupCorruptBackgroundSyncManager();

  EXPECT_FALSE(Register(sync_options_1_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, SequentialOperations) {
  // Schedule Init and all of the operations on a delayed backend. Verify that
  // the operations complete sequentially.
  SetupDelayedBackgroundSyncManager();

  const int64 kExpectedInitialId = BackgroundSyncRegistration::kInitialId;

  bool register_called = false;
  bool unregister_called = false;
  bool get_registration_called = false;
  test_background_sync_manager_->Register(
      sw_registration_id_1_, sync_options_1_,
      base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                 base::Unretained(this), &register_called));
  test_background_sync_manager_->Unregister(
      sw_registration_id_1_, sync_options_1_.tag, sync_options_1_.periodicity,
      kExpectedInitialId,
      base::Bind(&BackgroundSyncManagerTest::StatusCallback,
                 base::Unretained(this), &unregister_called));
  test_background_sync_manager_->GetRegistration(
      sw_registration_id_1_, sync_options_1_.tag, sync_options_1_.periodicity,
      base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                 base::Unretained(this), &get_registration_called));

  base::RunLoop().RunUntilIdle();
  // Init should be blocked while loading from the backend.
  EXPECT_FALSE(register_called);
  EXPECT_FALSE(unregister_called);
  EXPECT_FALSE(get_registration_called);

  test_background_sync_manager_->Continue();
  base::RunLoop().RunUntilIdle();
  // Register should be blocked while storing to the backend.
  EXPECT_FALSE(register_called);
  EXPECT_FALSE(unregister_called);
  EXPECT_FALSE(get_registration_called);

  test_background_sync_manager_->Continue();
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(register_called);
  EXPECT_EQ(kExpectedInitialId, callback_registration_.id());
  EXPECT_EQ(BACKGROUND_SYNC_STATUS_OK, callback_status_);
  // Unregister should be blocked while storing to the backend.
  EXPECT_FALSE(unregister_called);
  EXPECT_FALSE(get_registration_called);

  test_background_sync_manager_->Continue();
  base::RunLoop().RunUntilIdle();
  // Unregister should be done and since GetRegistration doesn't require the
  // backend it should be done too.
  EXPECT_EQ(BACKGROUND_SYNC_STATUS_NOT_FOUND, callback_status_);
  EXPECT_TRUE(unregister_called);
  EXPECT_TRUE(get_registration_called);
}

TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorker) {
  EXPECT_TRUE(Register(sync_options_1_));
  UnregisterServiceWorker(sw_registration_id_1_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest,
       UnregisterServiceWorkerDuringSyncRegistration) {
  EXPECT_TRUE(Register(sync_options_1_));

  test_background_sync_manager_->set_delay_backend(true);
  bool callback_called = false;
  test_background_sync_manager_->Register(
      sw_registration_id_1_, sync_options_2_,
      base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                 base::Unretained(this), &callback_called));

  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(callback_called);
  UnregisterServiceWorker(sw_registration_id_1_);

  test_background_sync_manager_->Continue();
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(callback_called);
  EXPECT_EQ(BACKGROUND_SYNC_STATUS_STORAGE_ERROR, callback_status_);

  test_background_sync_manager_->set_delay_backend(false);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DeleteAndStartOverServiceWorkerContext) {
  EXPECT_TRUE(Register(sync_options_1_));
  helper_->context()->ScheduleDeleteAndStartOver();
  base::RunLoop().RunUntilIdle();
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterBrowserRestart) {
  EXPECT_TRUE(Register(sync_options_1_));
  test_background_sync_manager_->set_corrupt_backend(true);
  EXPECT_FALSE(Register(sync_options_2_));

  // The manager is now disabled and not accepting new requests until browser
  // restart or notification that the storage has been wiped.
  test_background_sync_manager_->set_corrupt_backend(false);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(Register(sync_options_2_));

  // Simulate restarting the browser by creating a new BackgroundSyncManager.
  SetupBackgroundSyncManager();
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterDeleteAndStartOver) {
  EXPECT_TRUE(Register(sync_options_1_));
  test_background_sync_manager_->set_corrupt_backend(true);
  EXPECT_FALSE(Register(sync_options_2_));

  // The manager is now disabled and not accepting new requests until browser
  // restart or notification that the storage has been wiped.
  test_background_sync_manager_->set_corrupt_backend(false);
  helper_->context()->ScheduleDeleteAndStartOver();
  base::RunLoop().RunUntilIdle();

  RegisterServiceWorkers();

  EXPECT_TRUE(Register(sync_options_2_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsId) {
  BackgroundSyncRegistration reg_1;
  BackgroundSyncRegistration reg_2;

  EXPECT_TRUE(reg_1.Equals(reg_2));
  reg_2.set_id(reg_1.id() + 1);
  EXPECT_TRUE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsTag) {
  BackgroundSyncRegistration reg_1;
  BackgroundSyncRegistration reg_2;
  EXPECT_TRUE(reg_1.Equals(reg_2));
  reg_2.options()->tag = "bar";
  EXPECT_FALSE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsPeriodicity) {
  BackgroundSyncRegistration reg_1;
  BackgroundSyncRegistration reg_2;
  EXPECT_TRUE(reg_1.Equals(reg_2));
  reg_1.options()->periodicity = SYNC_PERIODIC;
  reg_2.options()->periodicity = SYNC_ONE_SHOT;
  EXPECT_FALSE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsMinPeriod) {
  BackgroundSyncRegistration reg_1;
  BackgroundSyncRegistration reg_2;
  EXPECT_TRUE(reg_1.Equals(reg_2));
  reg_2.options()->min_period = reg_1.options()->min_period + 1;
  EXPECT_FALSE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsNetworkState) {
  BackgroundSyncRegistration reg_1;
  BackgroundSyncRegistration reg_2;
  EXPECT_TRUE(reg_1.Equals(reg_2));
  reg_1.options()->network_state = NETWORK_STATE_ANY;
  reg_2.options()->network_state = NETWORK_STATE_ONLINE;
  EXPECT_FALSE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, RegistrationEqualsPowerState) {
  BackgroundSyncRegistration reg_1;
  BackgroundSyncRegistration reg_2;
  EXPECT_TRUE(reg_1.Equals(reg_2));
  reg_1.options()->power_state = POWER_STATE_AUTO;
  reg_2.options()->power_state = POWER_STATE_AVOID_DRAINING;
  EXPECT_FALSE(reg_1.Equals(reg_2));
}

TEST_F(BackgroundSyncManagerTest, StoreAndRetrievePreservesValues) {
  BackgroundSyncRegistrationOptions options;
  // Set non-default values for each field.
  options.tag = "foo";
  EXPECT_NE(SYNC_PERIODIC, options.periodicity);
  options.periodicity = SYNC_PERIODIC;
  options.min_period += 1;
  EXPECT_NE(NETWORK_STATE_ANY, options.network_state);
  options.network_state = NETWORK_STATE_ANY;
  EXPECT_NE(POWER_STATE_AUTO, options.power_state);
  options.power_state = POWER_STATE_AUTO;

  // Store the registration.
  EXPECT_TRUE(Register(options));

  // Simulate restarting the sync manager, forcing the next read to come from
  // disk.
  SetupBackgroundSyncManager();

  EXPECT_TRUE(GetRegistration(options));
  EXPECT_TRUE(options.Equals(*callback_registration_.options()));
}

TEST_F(BackgroundSyncManagerTest, EmptyTagSupported) {
  sync_options_1_.tag = "a";
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(sync_options_1_.Equals(*callback_registration_.options()));
  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, OverlappingPeriodicAndOneShotTags) {
  // Registrations with the same tags but different periodicities should not
  // collide.
  sync_options_1_.tag = "";
  sync_options_2_.tag = "";
  sync_options_1_.periodicity = SYNC_PERIODIC;
  sync_options_2_.periodicity = SYNC_ONE_SHOT;

  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));

  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_EQ(SYNC_PERIODIC, callback_registration_.options()->periodicity);
  EXPECT_TRUE(GetRegistration(sync_options_2_));
  EXPECT_EQ(SYNC_ONE_SHOT, callback_registration_.options()->periodicity);

  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(GetRegistration(sync_options_2_));
  EXPECT_EQ(SYNC_ONE_SHOT, callback_registration_.options()->periodicity);

  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, OneShotFiresOnRegistration) {
  InitSyncEventTest();

  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

// TODO(jkarlin): Change this to a periodic test as one-shots can't be power
// dependent according to spec.
TEST_F(BackgroundSyncManagerTest, OneShotFiresOnPowerChange) {
  InitSyncEventTest();
  sync_options_1_.power_state = POWER_STATE_AVOID_DRAINING;

  SetOnBatteryPower(true);
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(0, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));

  SetOnBatteryPower(false);
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

// TODO(jkarlin): Change this to a periodic test as one-shots can't be power
// dependent according to spec.
TEST_F(BackgroundSyncManagerTest, MultipleOneShotsFireOnPowerChange) {
  InitSyncEventTest();
  sync_options_1_.power_state = POWER_STATE_AVOID_DRAINING;
  sync_options_2_.power_state = POWER_STATE_AVOID_DRAINING;

  SetOnBatteryPower(true);
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
  EXPECT_EQ(0, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(GetRegistration(sync_options_2_));

  SetOnBatteryPower(false);
  EXPECT_EQ(2, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, OneShotFiresOnNetworkChange) {
  InitSyncEventTest();

  SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(0, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));

  SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, MultipleOneShotsFireOnNetworkChange) {
  InitSyncEventTest();

  SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_TRUE(Register(sync_options_2_));
  EXPECT_EQ(0, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  EXPECT_TRUE(GetRegistration(sync_options_2_));

  SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);

  EXPECT_EQ(2, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(GetRegistration(sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, OneShotFiresOnManagerRestart) {
  InitSyncEventTest();

  // Initially the event won't run because there is no network.
  SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(0, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));

  // Simulate closing the browser.
  DeleteBackgroundSyncManager();

  // The next time the manager is started, the network is good.
  SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
  SetupBackgroundSyncManager();
  InitSyncEventTest();

  // The event should have fired.
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, FailedOneShotStillExists) {
  InitFailedSyncEventTest();

  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));

  // The failed one-shot should stay registered but not fire until the
  // ServiceWorker is reloaded with an active client. Therefore, changing the
  // network should not cause the event to run again.
  SetNetwork(net::NetworkChangeNotifier::CONNECTION_2G);
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, FailedOneShotReregisteredAndFires) {
  InitFailedSyncEventTest();

  // The initial sync event fails.
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));
  BackgroundSyncRegistration first_registration = callback_registration_;

  InitSyncEventTest();

  // Reregistering should cause the sync event to fire again, this time
  // succeeding.
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(first_registration.id(), callback_registration_.id());
  EXPECT_EQ(2, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, DelayOneShotMidSync) {
  InitDelayedSyncEventTest();

  RegisterAndVerifySyncEventDelayed(sync_options_1_);

  // Finish firing the event and verify that the registration is removed.
  sync_fired_callback_.Run(SERVICE_WORKER_OK);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, OverwriteRegistrationMidSync) {
  InitDelayedSyncEventTest();

  sync_options_1_.network_state = NETWORK_STATE_ANY;
  SetNetwork(net::NetworkChangeNotifier::CONNECTION_NONE);

  RegisterAndVerifySyncEventDelayed(sync_options_1_);

  // Don't delay the next sync.
  test_background_sync_manager_->set_one_shot_callback(
      base::Bind(OneShotSuccessfulCallback, &sync_events_called_));

  // Register a different sync event with the same tag, overwriting the first.
  sync_options_1_.network_state = NETWORK_STATE_ONLINE;
  EXPECT_TRUE(Register(sync_options_1_));

  // The new sync event won't run as the network requirements aren't met.
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));

  // Finish the first event, note that the second is still registered.
  sync_fired_callback_.Run(SERVICE_WORKER_OK);
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));

  // Change the network and the second should run.
  SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(2, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, ReregisterOneShotMidSync) {
  InitDelayedSyncEventTest();

  RegisterAndVerifySyncEventDelayed(sync_options_1_);

  // Register the same sync, but don't delay it. It shouldn't run as it's
  // already firing.
  test_background_sync_manager_->set_one_shot_callback(
      base::Bind(OneShotSuccessfulCallback, &sync_events_called_));
  EXPECT_TRUE(Register(sync_options_1_));
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_TRUE(GetRegistration(sync_options_1_));

  // Finish the original event, note that the second never runs.
  sync_fired_callback_.Run(SERVICE_WORKER_OK);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1, sync_events_called_);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, UnregisterOneShotMidSync) {
  InitDelayedSyncEventTest();

  RegisterAndVerifySyncEventDelayed(sync_options_1_);

  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));

  sync_fired_callback_.Run(SERVICE_WORKER_OK);
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, BadBackendMidSync) {
  InitDelayedSyncEventTest();

  RegisterAndVerifySyncEventDelayed(sync_options_1_);

  test_background_sync_manager_->set_corrupt_backend(true);
  sync_fired_callback_.Run(SERVICE_WORKER_OK);
  base::RunLoop().RunUntilIdle();

  // The backend should now be disabled because it couldn't unregister the
  // one-shot.
  EXPECT_FALSE(Register(sync_options_2_));
  EXPECT_FALSE(
      RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_2_));
}

TEST_F(BackgroundSyncManagerTest, UnregisterServiceWorkerMidSync) {
  InitDelayedSyncEventTest();

  RegisterAndVerifySyncEventDelayed(sync_options_1_);
  UnregisterServiceWorker(sw_registration_id_1_);

  sync_fired_callback_.Run(SERVICE_WORKER_OK);

  // The backend isn't disabled, but the first service worker registration is
  // gone.
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_FALSE(Register(sync_options_1_));
  EXPECT_TRUE(
      RegisterWithServiceWorkerId(sw_registration_id_2_, sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, KillManagerMidSync) {
  InitDelayedSyncEventTest();

  RegisterAndVerifySyncEventDelayed(sync_options_1_);

  // Create a new manager which should fire the sync again on init.
  SetupBackgroundSyncManager();
  InitSyncEventTest();
  EXPECT_FALSE(GetRegistration(sync_options_1_));
  EXPECT_EQ(2, sync_events_called_);
}

TEST_F(BackgroundSyncManagerTest, RegisterFailsWithoutWindow) {
  RemoveWindowClients();
  EXPECT_FALSE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, RegisterExistingFailsWithoutWindow) {
  EXPECT_TRUE(Register(sync_options_1_));
  RemoveWindowClients();
  EXPECT_FALSE(Register(sync_options_1_));
}

TEST_F(BackgroundSyncManagerTest, UnregisterSucceedsWithoutWindow) {
  EXPECT_TRUE(Register(sync_options_1_));
  RemoveWindowClients();
  EXPECT_TRUE(Unregister(callback_registration_));
  EXPECT_FALSE(GetRegistration(sync_options_1_));
}

}  // namespace content