/content/browser/content_index/content_index_database_unittest.cc
C++ | 538 lines | 420 code | 94 blank | 24 comment | 5 complexity | e7d4cbe9591d94efe40c4b6d18ac9bc3 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
- // Copyright 2019 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/content_index/content_index_database.h"
- #include <string>
- #include "base/run_loop.h"
- #include "base/test/bind.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "content/browser/service_worker/embedded_worker_test_helper.h"
- #include "content/public/browser/content_index_provider.h"
- #include "content/public/test/browser_task_environment.h"
- #include "content/public/test/test_browser_context.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/blink/public/common/storage_key/storage_key.h"
- #include "third_party/blink/public/mojom/service_worker/service_worker_registration_options.mojom.h"
- #include "third_party/skia/include/core/SkBitmap.h"
- #include "url/origin.h"
- namespace content {
- namespace {
- using ::testing::_;
- class MockContentIndexProvider : public ContentIndexProvider {
- public:
- MOCK_METHOD1(GetIconSizes,
- std::vector<gfx::Size>(blink::mojom::ContentCategory));
- MOCK_METHOD1(OnContentAdded, void(ContentIndexEntry entry));
- MOCK_METHOD3(OnContentDeleted,
- void(int64_t service_Worker_registration_id,
- const url::Origin& origin,
- const std::string& description_id));
- };
- class ContentIndexTestBrowserContext : public TestBrowserContext {
- public:
- ContentIndexTestBrowserContext()
- : delegate_(std::make_unique<MockContentIndexProvider>()) {}
- ~ContentIndexTestBrowserContext() override = default;
- MockContentIndexProvider* GetContentIndexProvider() override {
- return delegate_.get();
- }
- private:
- std::unique_ptr<MockContentIndexProvider> delegate_;
- };
- void DidRegisterServiceWorker(int64_t* out_service_worker_registration_id,
- base::OnceClosure quit_closure,
- blink::ServiceWorkerStatusCode status,
- const std::string& status_message,
- int64_t service_worker_registration_id) {
- DCHECK(out_service_worker_registration_id);
- EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status) << status_message;
- *out_service_worker_registration_id = service_worker_registration_id;
- std::move(quit_closure).Run();
- }
- void DidFindServiceWorkerRegistration(
- scoped_refptr<ServiceWorkerRegistration>* out_service_worker_registration,
- base::OnceClosure quit_closure,
- blink::ServiceWorkerStatusCode status,
- scoped_refptr<ServiceWorkerRegistration> service_worker_registration) {
- DCHECK(out_service_worker_registration);
- EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status)
- << blink::ServiceWorkerStatusToString(status);
- *out_service_worker_registration = service_worker_registration;
- std::move(quit_closure).Run();
- }
- void DatabaseErrorCallback(base::OnceClosure quit_closure,
- blink::mojom::ContentIndexError* out_error,
- blink::mojom::ContentIndexError error) {
- *out_error = error;
- std::move(quit_closure).Run();
- }
- void GetDescriptionsCallback(
- base::OnceClosure quit_closure,
- blink::mojom::ContentIndexError* out_error,
- std::vector<blink::mojom::ContentDescriptionPtr>* out_descriptions,
- blink::mojom::ContentIndexError error,
- std::vector<blink::mojom::ContentDescriptionPtr> descriptions) {
- if (out_error)
- *out_error = error;
- DCHECK(out_descriptions);
- *out_descriptions = std::move(descriptions);
- std::move(quit_closure).Run();
- }
- std::vector<SkBitmap> CreateTestIcons() {
- std::vector<SkBitmap> icons(2);
- icons[0].allocN32Pixels(42, 42);
- icons[1].allocN32Pixels(24, 24);
- return icons;
- }
- } // namespace
- class ContentIndexDatabaseTest : public ::testing::Test {
- public:
- ContentIndexDatabaseTest()
- : task_environment_(BrowserTaskEnvironment::IO_MAINLOOP),
- embedded_worker_test_helper_(base::FilePath() /* in memory */) {}
- ContentIndexDatabaseTest(const ContentIndexDatabaseTest&) = delete;
- ContentIndexDatabaseTest& operator=(const ContentIndexDatabaseTest&) = delete;
- ~ContentIndexDatabaseTest() override = default;
- void SetUp() override {
- // Register Service Worker.
- service_worker_registration_id_ = RegisterServiceWorker(origin_);
- ASSERT_NE(service_worker_registration_id_,
- blink::mojom::kInvalidServiceWorkerRegistrationId);
- database_ = std::make_unique<ContentIndexDatabase>(
- &browser_context_, embedded_worker_test_helper_.context_wrapper());
- }
- blink::mojom::ContentDescriptionPtr CreateDescription(const std::string& id) {
- auto icon_definition = blink::mojom::ContentIconDefinition::New();
- icon_definition->src = "https://example.com/image.png";
- icon_definition->type = "image/png";
- std::vector<blink::mojom::ContentIconDefinitionPtr> icons;
- icons.push_back(std::move(icon_definition));
- return blink::mojom::ContentDescription::New(
- id, "title", "description", blink::mojom::ContentCategory::HOME_PAGE,
- std::move(icons), "https://example.com");
- }
- blink::mojom::ContentIndexError AddEntry(
- blink::mojom::ContentDescriptionPtr description,
- std::vector<SkBitmap> icons = CreateTestIcons()) {
- base::RunLoop run_loop;
- blink::mojom::ContentIndexError error;
- database_->AddEntry(
- service_worker_registration_id_, origin_,
- /* is_top_level_context= */ true, std::move(description),
- std::move(icons), launch_url(),
- base::BindOnce(&DatabaseErrorCallback, run_loop.QuitClosure(), &error));
- run_loop.Run();
- return error;
- }
- blink::mojom::ContentIndexError DeleteEntry(const std::string& id) {
- base::RunLoop run_loop;
- blink::mojom::ContentIndexError error;
- database_->DeleteEntry(
- service_worker_registration_id_, origin_, id,
- base::BindOnce(&DatabaseErrorCallback, run_loop.QuitClosure(), &error));
- run_loop.Run();
- return error;
- }
- std::vector<blink::mojom::ContentDescriptionPtr> GetDescriptions(
- blink::mojom::ContentIndexError* out_error = nullptr) {
- base::RunLoop run_loop;
- std::vector<blink::mojom::ContentDescriptionPtr> descriptions;
- database_->GetDescriptions(
- service_worker_registration_id_, origin_,
- base::BindOnce(&GetDescriptionsCallback, run_loop.QuitClosure(),
- out_error, &descriptions));
- run_loop.Run();
- return descriptions;
- }
- std::vector<SkBitmap> GetIcons(const std::string& id) {
- base::RunLoop run_loop;
- std::vector<SkBitmap> out_icons;
- database_->GetIcons(
- service_worker_registration_id_, id,
- base::BindLambdaForTesting([&](std::vector<SkBitmap> icons) {
- out_icons = std::move(icons);
- run_loop.Quit();
- }));
- run_loop.Run();
- return out_icons;
- }
- std::vector<ContentIndexEntry> GetAllEntries() {
- base::RunLoop run_loop;
- std::vector<ContentIndexEntry> out_entries;
- database_->GetAllEntries(
- base::BindLambdaForTesting([&](blink::mojom::ContentIndexError error,
- std::vector<ContentIndexEntry> entries) {
- ASSERT_EQ(error, blink::mojom::ContentIndexError::NONE);
- out_entries = std::move(entries);
- run_loop.Quit();
- }));
- run_loop.Run();
- return out_entries;
- }
- std::unique_ptr<ContentIndexEntry> GetEntry(
- const std::string& description_id) {
- base::RunLoop run_loop;
- std::unique_ptr<ContentIndexEntry> out_entry;
- database_->GetEntry(service_worker_registration_id_, description_id,
- base::BindLambdaForTesting(
- [&](absl::optional<ContentIndexEntry> entry) {
- if (entry)
- out_entry = std::make_unique<ContentIndexEntry>(
- std::move(*entry));
- run_loop.Quit();
- }));
- run_loop.Run();
- return out_entry;
- }
- MockContentIndexProvider* provider() {
- return browser_context_.GetContentIndexProvider();
- }
- int64_t service_worker_registration_id() {
- return service_worker_registration_id_;
- }
- void set_service_worker_registration_id(
- int64_t service_worker_registration_id) {
- service_worker_registration_id_ = service_worker_registration_id;
- }
- ContentIndexDatabase* database() { return database_.get(); }
- BrowserTaskEnvironment& task_environment() { return task_environment_; }
- const url::Origin& origin() { return origin_; }
- GURL launch_url() { return origin_.GetURL(); }
- int64_t RegisterServiceWorker(const url::Origin& origin) {
- GURL script_url(origin.GetURL().spec() + "sw.js");
- int64_t service_worker_registration_id =
- blink::mojom::kInvalidServiceWorkerRegistrationId;
- {
- blink::mojom::ServiceWorkerRegistrationOptions options;
- options.scope = origin.GetURL();
- blink::StorageKey key(origin);
- base::RunLoop run_loop;
- embedded_worker_test_helper_.context()->RegisterServiceWorker(
- script_url, key, options,
- blink::mojom::FetchClientSettingsObject::New(),
- base::BindOnce(&DidRegisterServiceWorker,
- &service_worker_registration_id,
- run_loop.QuitClosure()),
- /*requesting_frame_id=*/GlobalRenderFrameHostId());
- run_loop.Run();
- }
- if (service_worker_registration_id ==
- blink::mojom::kInvalidServiceWorkerRegistrationId) {
- ADD_FAILURE() << "Could not obtain a valid Service Worker registration";
- return blink::mojom::kInvalidServiceWorkerRegistrationId;
- }
- {
- base::RunLoop run_loop;
- embedded_worker_test_helper_.context()->registry()->FindRegistrationForId(
- service_worker_registration_id, blink::StorageKey(origin),
- base::BindOnce(&DidFindServiceWorkerRegistration,
- &service_worker_registration_,
- run_loop.QuitClosure()));
- run_loop.Run();
- }
- // Wait for the worker to be activated.
- base::RunLoop().RunUntilIdle();
- if (!service_worker_registration_) {
- ADD_FAILURE() << "Could not find the new Service Worker registration.";
- return blink::mojom::kInvalidServiceWorkerRegistrationId;
- }
- return service_worker_registration_id;
- }
- private:
- BrowserTaskEnvironment task_environment_; // Must be first member.
- ContentIndexTestBrowserContext browser_context_;
- url::Origin origin_ = url::Origin::Create(GURL("https://example.com"));
- int64_t service_worker_registration_id_ =
- blink::mojom::kInvalidServiceWorkerRegistrationId;
- EmbeddedWorkerTestHelper embedded_worker_test_helper_;
- scoped_refptr<ServiceWorkerRegistration> service_worker_registration_;
- std::unique_ptr<ContentIndexDatabase> database_;
- };
- TEST_F(ContentIndexDatabaseTest, DatabaseOperations) {
- // Initially database will be empty.
- {
- blink::mojom::ContentIndexError error;
- auto descriptions = GetDescriptions(&error);
- EXPECT_TRUE(descriptions.empty());
- EXPECT_EQ(error, blink::mojom::ContentIndexError::NONE);
- }
- // Insert entries and expect to find them.
- EXPECT_EQ(AddEntry(CreateDescription("id1")),
- blink::mojom::ContentIndexError::NONE);
- EXPECT_EQ(AddEntry(CreateDescription("id2")),
- blink::mojom::ContentIndexError::NONE);
- EXPECT_EQ(GetDescriptions().size(), 2u);
- // Remove an entry.
- EXPECT_EQ(DeleteEntry("id2"), blink::mojom::ContentIndexError::NONE);
- // Inspect the last remaining element.
- auto descriptions = GetDescriptions();
- ASSERT_EQ(descriptions.size(), 1u);
- auto expected_description = CreateDescription("id1");
- EXPECT_TRUE(descriptions[0]->Equals(*expected_description));
- }
- TEST_F(ContentIndexDatabaseTest, DatabaseOperationsBadSWID) {
- url::Origin other_origin = url::Origin::Create(GURL("https://other.com"));
- int64_t other_service_worker_registration_id =
- RegisterServiceWorker(other_origin);
- ASSERT_NE(other_service_worker_registration_id,
- blink::mojom::kInvalidServiceWorkerRegistrationId);
- set_service_worker_registration_id(other_service_worker_registration_id);
- blink::mojom::ContentIndexError error;
- auto descriptions = GetDescriptions(&error);
- EXPECT_TRUE(descriptions.empty());
- EXPECT_EQ(error, blink::mojom::ContentIndexError::STORAGE_ERROR);
- EXPECT_EQ(AddEntry(CreateDescription("id1")),
- blink::mojom::ContentIndexError::STORAGE_ERROR);
- EXPECT_EQ(DeleteEntry("id2"), blink::mojom::ContentIndexError::STORAGE_ERROR);
- }
- TEST_F(ContentIndexDatabaseTest, AddDuplicateIdWillOverwrite) {
- auto description1 = CreateDescription("id");
- description1->title = "title1";
- auto description2 = CreateDescription("id");
- description2->title = "title2";
- EXPECT_EQ(AddEntry(std::move(description1)),
- blink::mojom::ContentIndexError::NONE);
- EXPECT_EQ(AddEntry(std::move(description2)),
- blink::mojom::ContentIndexError::NONE);
- auto descriptions = GetDescriptions();
- ASSERT_EQ(descriptions.size(), 1u);
- EXPECT_EQ(descriptions[0]->id, "id");
- EXPECT_EQ(descriptions[0]->title, "title2");
- }
- TEST_F(ContentIndexDatabaseTest, DeleteNonExistentEntry) {
- auto descriptions = GetDescriptions();
- EXPECT_TRUE(descriptions.empty());
- EXPECT_EQ(DeleteEntry("id"), blink::mojom::ContentIndexError::NONE);
- }
- TEST_F(ContentIndexDatabaseTest, ProviderUpdated) {
- {
- std::unique_ptr<ContentIndexEntry> out_entry;
- EXPECT_CALL(*provider(), OnContentAdded(_))
- .WillOnce(testing::Invoke([&](auto entry) {
- out_entry = std::make_unique<ContentIndexEntry>(std::move(entry));
- }));
- EXPECT_EQ(AddEntry(CreateDescription("id")),
- blink::mojom::ContentIndexError::NONE);
- // Wait for the provider to receive the OnContentAdded event.
- task_environment().RunUntilIdle();
- ASSERT_TRUE(out_entry);
- ASSERT_TRUE(out_entry->description);
- EXPECT_EQ(out_entry->service_worker_registration_id,
- service_worker_registration_id());
- EXPECT_EQ(out_entry->description->id, "id");
- EXPECT_EQ(out_entry->launch_url, launch_url());
- EXPECT_FALSE(out_entry->registration_time.is_null());
- }
- {
- EXPECT_CALL(*provider(), OnContentDeleted(service_worker_registration_id(),
- origin(), "id"));
- EXPECT_EQ(DeleteEntry("id"), blink::mojom::ContentIndexError::NONE);
- task_environment().RunUntilIdle();
- }
- }
- TEST_F(ContentIndexDatabaseTest, IconLifetimeTiedToEntry) {
- // Initially we don't have an icon.
- EXPECT_TRUE(GetIcons("id").empty());
- EXPECT_EQ(AddEntry(CreateDescription("id")),
- blink::mojom::ContentIndexError::NONE);
- auto icons = GetIcons("id");
- ASSERT_EQ(icons.size(), 2u);
- if (icons[0].width() > icons[1].width())
- std::swap(icons[0], icons[1]);
- EXPECT_FALSE(icons[0].isNull());
- EXPECT_FALSE(icons[0].drawsNothing());
- EXPECT_EQ(icons[0].width(), 24);
- EXPECT_EQ(icons[0].height(), 24);
- EXPECT_FALSE(icons[1].isNull());
- EXPECT_FALSE(icons[1].drawsNothing());
- EXPECT_EQ(icons[1].width(), 42);
- EXPECT_EQ(icons[1].height(), 42);
- EXPECT_EQ(DeleteEntry("id"), blink::mojom::ContentIndexError::NONE);
- EXPECT_TRUE(GetIcons("id").empty());
- }
- TEST_F(ContentIndexDatabaseTest, NoIconsAreSupported) {
- // Initially we don't have an icon.
- EXPECT_TRUE(GetIcons("id").empty());
- // Create an entry with no icons.
- EXPECT_EQ(AddEntry(CreateDescription("id"), /* icons= */ {}),
- blink::mojom::ContentIndexError::NONE);
- // No icons should be found.
- EXPECT_TRUE(GetIcons("id").empty());
- }
- TEST_F(ContentIndexDatabaseTest, GetEntries) {
- // Initially there are no entries.
- EXPECT_FALSE(GetEntry("any-id"));
- EXPECT_TRUE(GetAllEntries().empty());
- std::unique_ptr<ContentIndexEntry> added_entry;
- {
- EXPECT_CALL(*provider(), OnContentAdded(_))
- .WillOnce(testing::Invoke([&](auto entry) {
- added_entry = std::make_unique<ContentIndexEntry>(std::move(entry));
- }));
- EXPECT_EQ(AddEntry(CreateDescription("id")),
- blink::mojom::ContentIndexError::NONE);
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(added_entry);
- }
- // Check the notified entries match the queried entries.
- {
- auto entry = GetEntry("id");
- ASSERT_TRUE(entry);
- EXPECT_TRUE(entry->description->Equals(*added_entry->description));
- auto entries = GetAllEntries();
- ASSERT_EQ(entries.size(), 1u);
- EXPECT_TRUE(entries[0].description->Equals(*added_entry->description));
- }
- // Add one more entry.
- {
- EXPECT_CALL(*provider(), OnContentAdded(_));
- EXPECT_EQ(AddEntry(CreateDescription("id-2")),
- blink::mojom::ContentIndexError::NONE);
- auto entries = GetAllEntries();
- EXPECT_EQ(entries.size(), 2u);
- }
- }
- TEST_F(ContentIndexDatabaseTest, BlockedOriginsCannotRegisterContent) {
- // Initially adding is fine.
- EXPECT_EQ(AddEntry(CreateDescription("id1")),
- blink::mojom::ContentIndexError::NONE);
- // Two delete events were dispatched.
- database()->BlockOrigin(origin());
- database()->BlockOrigin(origin());
- // Content can't be registered while the origin is blocked.
- EXPECT_EQ(AddEntry(CreateDescription("id2")),
- blink::mojom::ContentIndexError::STORAGE_ERROR);
- // First event dispatch completed.
- database()->UnblockOrigin(origin());
- // Content still can't be registered.
- EXPECT_EQ(AddEntry(CreateDescription("id3")),
- blink::mojom::ContentIndexError::STORAGE_ERROR);
- // Last event dispatch completed.
- database()->UnblockOrigin(origin());
- // Registering is OK now.
- EXPECT_EQ(AddEntry(CreateDescription("id4")),
- blink::mojom::ContentIndexError::NONE);
- }
- TEST_F(ContentIndexDatabaseTest, UmaRecorded) {
- base::HistogramTester histogram_tester;
- EXPECT_EQ(AddEntry(CreateDescription("id")),
- blink::mojom::ContentIndexError::NONE);
- histogram_tester.ExpectBucketCount("ContentIndex.Database.Add",
- blink::ServiceWorkerStatusCode::kOk, 1);
- EXPECT_FALSE(GetIcons("id").empty());
- histogram_tester.ExpectBucketCount("ContentIndex.Database.GetIcon",
- blink::ServiceWorkerStatusCode::kOk, 1);
- EXPECT_EQ(GetAllEntries().size(), 1u);
- histogram_tester.ExpectBucketCount("ContentIndex.Database.GetAllEntries",
- blink::ServiceWorkerStatusCode::kOk, 1);
- EXPECT_EQ(GetDescriptions().size(), 1u);
- histogram_tester.ExpectBucketCount("ContentIndex.Database.GetDescriptions",
- blink::ServiceWorkerStatusCode::kOk, 1);
- EXPECT_TRUE(GetEntry("id"));
- histogram_tester.ExpectBucketCount("ContentIndex.Database.GetEntry",
- blink::ServiceWorkerStatusCode::kOk, 1);
- EXPECT_EQ(DeleteEntry("id"), blink::mojom::ContentIndexError::NONE);
- histogram_tester.ExpectBucketCount("ContentIndex.Database.Delete",
- blink::ServiceWorkerStatusCode::kOk, 1);
- database()->BlockOrigin(origin());
- AddEntry(CreateDescription("id"));
- histogram_tester.ExpectBucketCount("ContentIndex.RegistrationBlocked",
- blink::mojom::ContentCategory::HOME_PAGE,
- 1);
- }
- } // namespace content