// 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_service_impl.h" #include #include #include "base/bind.h" #include "base/bind_helpers.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "content/browser/background_sync/background_sync_context_impl.h" #include "content/browser/background_sync/background_sync_network_observer.h" #include "content/browser/service_worker/embedded_worker_test_helper.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" #include "content/browser/storage_partition_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/background_sync_test_util.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" #include "mojo/public/cpp/bindings/interface_ptr.h" #include "net/base/network_change_notifier.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { namespace { const char kServiceWorkerPattern[] = "https://example.com/a"; const char kServiceWorkerScript[] = "https://example.com/a/script.js"; // Callbacks from SetUp methods void RegisterServiceWorkerCallback(bool* called, int64_t* store_registration_id, ServiceWorkerStatusCode status, const std::string& status_message, int64_t registration_id) { EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status); *called = true; *store_registration_id = registration_id; } void FindServiceWorkerRegistrationCallback( scoped_refptr* out_registration, ServiceWorkerStatusCode status, const scoped_refptr& registration) { EXPECT_EQ(SERVICE_WORKER_OK, status) << ServiceWorkerStatusToString(status); *out_registration = registration; } // Callbacks from BackgroundSyncServiceImpl methods void ErrorAndRegistrationCallback( bool* called, mojom::BackgroundSyncError* out_error, mojom::SyncRegistrationPtr* out_registration, mojom::BackgroundSyncError error, const mojom::SyncRegistrationPtr& registration) { *called = true; *out_error = error; *out_registration = registration.Clone(); } void ErrorAndRegistrationListCallback( bool* called, mojom::BackgroundSyncError* out_error, unsigned long* out_array_size, mojom::BackgroundSyncError error, mojo::Array registrations) { *called = true; *out_error = error; if (error == mojom::BackgroundSyncError::NONE) *out_array_size = registrations.size(); } } // namespace class BackgroundSyncServiceImplTest : public testing::Test { public: BackgroundSyncServiceImplTest() : thread_bundle_( new TestBrowserThreadBundle(TestBrowserThreadBundle::IO_MAINLOOP)), network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) { default_sync_registration_ = mojom::SyncRegistration::New(); } void SetUp() override { // Don't let the tests be confused by the real-world device connectivity background_sync_test_util::SetIgnoreNetworkChangeNotifier(true); CreateTestHelper(); CreateStoragePartition(); CreateBackgroundSyncContext(); CreateServiceWorkerRegistration(); CreateBackgroundSyncServiceImpl(); } void TearDown() override { // This must be explicitly destroyed here to ensure that destruction // of both the BackgroundSyncContext and the BackgroundSyncManager occurs on // the correct thread. background_sync_context_->Shutdown(); base::RunLoop().RunUntilIdle(); background_sync_context_ = nullptr; // Restore the network observer functionality for subsequent tests background_sync_test_util::SetIgnoreNetworkChangeNotifier(false); } // SetUp helper methods void CreateTestHelper() { embedded_worker_helper_.reset( new EmbeddedWorkerTestHelper(base::FilePath())); } void CreateStoragePartition() { // Creates a StoragePartition so that the BackgroundSyncManager can // use it to access the BrowserContext. storage_partition_impl_.reset(new StoragePartitionImpl( embedded_worker_helper_->browser_context(), base::FilePath(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); embedded_worker_helper_->context_wrapper()->set_storage_partition( storage_partition_impl_.get()); } void CreateBackgroundSyncContext() { background_sync_context_ = new BackgroundSyncContextImpl(); background_sync_context_->Init(embedded_worker_helper_->context_wrapper()); // Tests do not expect the sync event to fire immediately after // register (and cleanup up the sync registrations). Prevent the sync // event from firing by setting the network state to have no connection. // NOTE: The setup of the network connection must happen after the // BackgroundSyncManager has been setup, including any asynchronous // initialization. base::RunLoop().RunUntilIdle(); BackgroundSyncNetworkObserver* network_observer = background_sync_context_->background_sync_manager() ->GetNetworkObserverForTesting(); network_observer->NotifyManagerIfNetworkChangedForTesting( net::NetworkChangeNotifier::CONNECTION_NONE); base::RunLoop().RunUntilIdle(); } void CreateServiceWorkerRegistration() { bool called = false; embedded_worker_helper_->context()->RegisterServiceWorker( GURL(kServiceWorkerPattern), GURL(kServiceWorkerScript), NULL, base::Bind(&RegisterServiceWorkerCallback, &called, &sw_registration_id_)); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(called); embedded_worker_helper_->context_wrapper()->FindReadyRegistrationForId( sw_registration_id_, GURL(kServiceWorkerPattern).GetOrigin(), base::Bind(FindServiceWorkerRegistrationCallback, &sw_registration_)); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(sw_registration_); } void CreateBackgroundSyncServiceImpl() { // Create a dummy mojo channel so that the BackgroundSyncServiceImpl can be // instantiated mojo::InterfaceRequest service_request = mojo::GetProxy(&service_ptr_); // Create a new BackgroundSyncServiceImpl bound to the dummy channel background_sync_context_->CreateService(std::move(service_request)); base::RunLoop().RunUntilIdle(); service_impl_ = *background_sync_context_->services_.begin(); ASSERT_TRUE(service_impl_); } // Helpers for testing BackgroundSyncServiceImpl methods void Register( mojom::SyncRegistrationPtr sync, const mojom::BackgroundSyncService::RegisterCallback& callback) { service_impl_->Register(std::move(sync), sw_registration_id_, false /* requested_from_service_worker */, callback); base::RunLoop().RunUntilIdle(); } void GetRegistrations( const mojom::BackgroundSyncService::GetRegistrationsCallback& callback) { service_impl_->GetRegistrations(sw_registration_id_, callback); base::RunLoop().RunUntilIdle(); } scoped_ptr thread_bundle_; scoped_ptr network_change_notifier_; scoped_ptr embedded_worker_helper_; scoped_ptr storage_partition_impl_; scoped_refptr background_sync_context_; int64_t sw_registration_id_; scoped_refptr sw_registration_; mojom::BackgroundSyncServicePtr service_ptr_; BackgroundSyncServiceImpl* service_impl_; // Owned by background_sync_context_ mojom::SyncRegistrationPtr default_sync_registration_; }; // Tests TEST_F(BackgroundSyncServiceImplTest, Register) { bool called = false; mojom::BackgroundSyncError error; mojom::SyncRegistrationPtr reg; Register(default_sync_registration_.Clone(), base::Bind(&ErrorAndRegistrationCallback, &called, &error, ®)); EXPECT_TRUE(called); EXPECT_EQ(mojom::BackgroundSyncError::NONE, error); EXPECT_EQ("", reg->tag); } TEST_F(BackgroundSyncServiceImplTest, GetRegistrations) { bool called = false; mojom::BackgroundSyncError error; unsigned long array_size = 0UL; GetRegistrations(base::Bind(&ErrorAndRegistrationListCallback, &called, &error, &array_size)); EXPECT_TRUE(called); EXPECT_EQ(mojom::BackgroundSyncError::NONE, error); EXPECT_EQ(0UL, array_size); } TEST_F(BackgroundSyncServiceImplTest, GetRegistrationsWithRegisteredSync) { bool register_called = false; bool getregistrations_called = false; mojom::BackgroundSyncError register_error; mojom::BackgroundSyncError getregistrations_error; mojom::SyncRegistrationPtr register_reg; unsigned long array_size = 0UL; Register(default_sync_registration_.Clone(), base::Bind(&ErrorAndRegistrationCallback, ®ister_called, ®ister_error, ®ister_reg)); EXPECT_TRUE(register_called); EXPECT_EQ(mojom::BackgroundSyncError::NONE, register_error); GetRegistrations(base::Bind(&ErrorAndRegistrationListCallback, &getregistrations_called, &getregistrations_error, &array_size)); EXPECT_TRUE(getregistrations_called); EXPECT_EQ(mojom::BackgroundSyncError::NONE, getregistrations_error); EXPECT_EQ(1UL, array_size); } } // namespace content