// 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/notifications/notification_database.h"

#include <stddef.h>
#include <stdint.h>

#include "base/files/scoped_temp_dir.h"
#include "base/guid.h"
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/notification_database_data.h"
#include "content/public/common/platform_notification_data.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
#include "url/gurl.h"

namespace content {

const int kExampleServiceWorkerRegistrationId = 42;

const struct {
  const char* origin;
  const char* tag;
  int64_t service_worker_registration_id;
} kExampleNotificationData[] = {
    {"https://example.com", "" /* tag */, 0},
    {"https://example.com", "" /* tag */, kExampleServiceWorkerRegistrationId},
    {"https://example.com", "" /* tag */, kExampleServiceWorkerRegistrationId},
    {"https://example.com", "" /* tag */,
     kExampleServiceWorkerRegistrationId + 1},
    {"https://chrome.com", "" /* tag */, 0},
    {"https://chrome.com", "" /* tag */, 0},
    {"https://chrome.com", "" /* tag */, kExampleServiceWorkerRegistrationId},
    {"https://chrome.com", "foo" /* tag */, 0}};

class NotificationDatabaseTest : public ::testing::Test {
 protected:
  // Creates a new NotificationDatabase instance in memory.
  NotificationDatabase* CreateDatabaseInMemory() {
    return new NotificationDatabase(base::FilePath());
  }

  // Creates a new NotificationDatabase instance in |path|.
  NotificationDatabase* CreateDatabaseOnFileSystem(const base::FilePath& path) {
    return new NotificationDatabase(path);
  }

  // Creates a new notification for |service_worker_registration_id| belonging
  // to |origin| and writes it to the database. The written notification id
  // will be stored in |notification_id|.
  void CreateAndWriteNotification(NotificationDatabase* database,
                                  const GURL& origin,
                                  const std::string& tag,
                                  int64_t service_worker_registration_id,
                                  std::string* notification_id) {
    DCHECK(notification_id);

    NotificationDatabaseData database_data;
    database_data.notification_id = GenerateNotificationId();
    database_data.origin = origin;
    database_data.service_worker_registration_id =
        service_worker_registration_id;
    database_data.notification_data.tag = tag;

    ASSERT_EQ(NotificationDatabase::STATUS_OK,
              database->WriteNotificationData(origin, database_data));

    *notification_id = database_data.notification_id;
  }

  // Populates |database| with a series of example notifications that differ in
  // their origin and Service Worker registration id.
  void PopulateDatabaseWithExampleData(NotificationDatabase* database) {
    std::string notification_id;
    for (size_t i = 0; i < arraysize(kExampleNotificationData); ++i) {
      ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification(
          database, GURL(kExampleNotificationData[i].origin),
          kExampleNotificationData[i].tag,
          kExampleNotificationData[i].service_worker_registration_id,
          &notification_id));
    }
  }

  // Returns if |database| has been opened.
  bool IsDatabaseOpen(NotificationDatabase* database) {
    return database->IsOpen();
  }

  // Returns if |database| is an in-memory only database.
  bool IsInMemoryDatabase(NotificationDatabase* database) {
    return database->IsInMemoryDatabase();
  }

  // Writes a LevelDB key-value pair directly to the LevelDB backing the
  // notification database in |database|.
  void WriteLevelDBKeyValuePair(NotificationDatabase* database,
                                const std::string& key,
                                const std::string& value) {
    leveldb::Status status =
        database->GetDBForTesting()->Put(leveldb::WriteOptions(), key, value);
    ASSERT_TRUE(status.ok());
  }

  // Generates a random notification ID. The format of the ID is opaque.
  std::string GenerateNotificationId() { return base::GenerateGUID(); }
};

TEST_F(NotificationDatabaseTest, OpenCloseMemory) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());

  // Should return false because the database does not exist in memory.
  EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
            database->Open(false /* create_if_missing */));

  // Should return true, indicating that the database could be created.
  EXPECT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  EXPECT_TRUE(IsDatabaseOpen(database.get()));
  EXPECT_TRUE(IsInMemoryDatabase(database.get()));

  // Verify that in-memory databases do not persist when being re-created.
  database.reset(CreateDatabaseInMemory());

  EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
            database->Open(false /* create_if_missing */));
}

TEST_F(NotificationDatabaseTest, OpenCloseFileSystem) {
  base::ScopedTempDir database_dir;
  ASSERT_TRUE(database_dir.CreateUniqueTempDir());

  std::unique_ptr<NotificationDatabase> database(
      CreateDatabaseOnFileSystem(database_dir.GetPath()));

  // Should return false because the database does not exist on the file system.
  EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
            database->Open(false /* create_if_missing */));

  // Should return true, indicating that the database could be created.
  EXPECT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  EXPECT_TRUE(IsDatabaseOpen(database.get()));
  EXPECT_FALSE(IsInMemoryDatabase(database.get()));

  // Close the database, and re-open it without attempting to create it because
  // the files on the file system should still exist as expected.
  database.reset(CreateDatabaseOnFileSystem(database_dir.GetPath()));
  EXPECT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(false /* create_if_missing */));
}

TEST_F(NotificationDatabaseTest, DestroyDatabase) {
  base::ScopedTempDir database_dir;
  ASSERT_TRUE(database_dir.CreateUniqueTempDir());

  std::unique_ptr<NotificationDatabase> database(
      CreateDatabaseOnFileSystem(database_dir.GetPath()));

  EXPECT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));
  EXPECT_TRUE(IsDatabaseOpen(database.get()));

  // Destroy the database. This will immediately close it as well.
  ASSERT_EQ(NotificationDatabase::STATUS_OK, database->Destroy());
  EXPECT_FALSE(IsDatabaseOpen(database.get()));

  // Try to re-open the database (but not re-create it). This should fail as
  // the files associated with the database should have been blown away.
  database.reset(CreateDatabaseOnFileSystem(database_dir.GetPath()));
  EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
            database->Open(false /* create_if_missing */));
}

TEST_F(NotificationDatabaseTest, NotificationIdIncrements) {
  base::ScopedTempDir database_dir;
  ASSERT_TRUE(database_dir.CreateUniqueTempDir());

  std::unique_ptr<NotificationDatabase> database(
      CreateDatabaseOnFileSystem(database_dir.GetPath()));

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  EXPECT_EQ(database->GetNextPersistentNotificationId(), 1);
  EXPECT_EQ(database->GetNextPersistentNotificationId(), 2);
  EXPECT_EQ(database->GetNextPersistentNotificationId(), 3);

  GURL origin("https://example.com");

  std::string notification_id;
  ASSERT_NO_FATAL_FAILURE(
      CreateAndWriteNotification(database.get(), origin, "" /* tag */,
                                 0 /* sw_registration_id */, &notification_id));

  database.reset(CreateDatabaseOnFileSystem(database_dir.GetPath()));
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(false /* create_if_missing */));

  // Verify that the next persistent notification id was stored in the database,
  // and continues where we expect it to be, even after closing and opening it.
  EXPECT_EQ(database->GetNextPersistentNotificationId(), 4);
}

TEST_F(NotificationDatabaseTest, NotificationIdIncrementsStorage) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  GURL origin("https://example.com");

  NotificationDatabaseData database_data, read_database_data;
  database_data.notification_id = GenerateNotificationId();

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->WriteNotificationData(origin, database_data));

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadNotificationData(database_data.notification_id,
                                           origin, &read_database_data));

  EXPECT_EQ(database_data.notification_id, read_database_data.notification_id);
}

TEST_F(NotificationDatabaseTest, NotificationIdCorruption) {
  base::ScopedTempDir database_dir;
  ASSERT_TRUE(database_dir.CreateUniqueTempDir());

  std::unique_ptr<NotificationDatabase> database(
      CreateDatabaseOnFileSystem(database_dir.GetPath()));

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  GURL origin("https://example.com");

  NotificationDatabaseData database_data;
  database_data.notification_id = GenerateNotificationId();

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->WriteNotificationData(origin, database_data));

  // Deliberately write an invalid value as the next notification id. When
  // re-opening the database, the Open() method should realize that an invalid
  // value is being read, and mark the database as corrupted.
  ASSERT_NO_FATAL_FAILURE(
      WriteLevelDBKeyValuePair(database.get(), "NEXT_NOTIFICATION_ID", "-42"));

  database.reset(CreateDatabaseOnFileSystem(database_dir.GetPath()));
  EXPECT_EQ(NotificationDatabase::STATUS_ERROR_CORRUPTED,
            database->Open(false /* create_if_missing */));
}

TEST_F(NotificationDatabaseTest, ReadInvalidNotificationData) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  NotificationDatabaseData database_data;

  // Reading the notification data for a notification that does not exist should
  // return the ERROR_NOT_FOUND status code.
  EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
            database->ReadNotificationData("bad-id", GURL("https://chrome.com"),
                                           &database_data));
}

TEST_F(NotificationDatabaseTest, ReadNotificationDataDifferentOrigin) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  GURL origin("https://example.com");

  NotificationDatabaseData database_data, read_database_data;
  database_data.notification_id = GenerateNotificationId();
  database_data.notification_data.title = base::UTF8ToUTF16("My Notification");

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->WriteNotificationData(origin, database_data));

  // Reading the notification from the database when given a different origin
  // should return the ERROR_NOT_FOUND status code.
  EXPECT_EQ(NotificationDatabase::STATUS_ERROR_NOT_FOUND,
            database->ReadNotificationData(database_data.notification_id,
                                           GURL("https://chrome.com"),
                                           &read_database_data));

  // However, reading the notification from the database with the same origin
  // should return STATUS_OK and the associated notification data.
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadNotificationData(database_data.notification_id,
                                           origin, &read_database_data));

  EXPECT_EQ(database_data.notification_data.title,
            read_database_data.notification_data.title);
}

TEST_F(NotificationDatabaseTest, ReadNotificationDataReflection) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  GURL origin("https://example.com");

  PlatformNotificationData notification_data;
  notification_data.title = base::UTF8ToUTF16("My Notification");
  notification_data.direction =
      PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
  notification_data.lang = "nl-NL";
  notification_data.body = base::UTF8ToUTF16("Hello, world!");
  notification_data.tag = "replace id";
  notification_data.icon = GURL("https://example.com/icon.png");
  notification_data.silent = true;

  NotificationDatabaseData database_data;
  database_data.notification_id = GenerateNotificationId();
  database_data.origin = origin;
  database_data.service_worker_registration_id = 42;
  database_data.notification_data = notification_data;

  // Write the constructed notification to the database, and then immediately
  // read it back from the database again as well.
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->WriteNotificationData(origin, database_data));

  NotificationDatabaseData read_database_data;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadNotificationData(database_data.notification_id,
                                           origin, &read_database_data));

  // Verify that all members retrieved from the database are exactly the same
  // as the ones that were written to it. This tests the serialization behavior.

  EXPECT_EQ(database_data.notification_id, read_database_data.notification_id);

  EXPECT_EQ(database_data.origin, read_database_data.origin);
  EXPECT_EQ(database_data.service_worker_registration_id,
            read_database_data.service_worker_registration_id);

  const PlatformNotificationData& read_notification_data =
      read_database_data.notification_data;

  EXPECT_EQ(notification_data.title, read_notification_data.title);
  EXPECT_EQ(notification_data.direction, read_notification_data.direction);
  EXPECT_EQ(notification_data.lang, read_notification_data.lang);
  EXPECT_EQ(notification_data.body, read_notification_data.body);
  EXPECT_EQ(notification_data.tag, read_notification_data.tag);
  EXPECT_EQ(notification_data.icon, read_notification_data.icon);
  EXPECT_EQ(notification_data.silent, read_notification_data.silent);
}

TEST_F(NotificationDatabaseTest, ReadWriteMultipleNotificationData) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  GURL origin("https://example.com");

  std::vector<std::string> notification_ids;
  std::string notification_id;

  // Write ten notifications to the database, each with a unique title and
  // notification id (it is the responsibility of the user to increment this).
  for (int i = 1; i <= 10; ++i) {
    ASSERT_NO_FATAL_FAILURE(CreateAndWriteNotification(
        database.get(), origin, "" /* tag */, i /* sw_registration_id */,
        &notification_id));

    EXPECT_FALSE(notification_id.empty());

    notification_ids.push_back(notification_id);
  }

  NotificationDatabaseData database_data;

  int64_t service_worker_registration_id = 1;

  // Read the ten notifications from the database, and verify that the titles
  // of each of them matches with how they were created.
  for (const std::string& notification_id : notification_ids) {
    ASSERT_EQ(NotificationDatabase::STATUS_OK,
              database->ReadNotificationData(notification_id, origin,
                                             &database_data));

    EXPECT_EQ(service_worker_registration_id++,
              database_data.service_worker_registration_id);
  }
}

TEST_F(NotificationDatabaseTest, DeleteInvalidNotificationData) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  // Deleting non-existing notifications is not considered to be a failure.
  ASSERT_EQ(
      NotificationDatabase::STATUS_OK,
      database->DeleteNotificationData("bad-id", GURL("https://chrome.com")));
}

TEST_F(NotificationDatabaseTest, DeleteNotificationDataSameOrigin) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  const std::string notification_id = GenerateNotificationId();

  NotificationDatabaseData database_data;
  database_data.notification_id = notification_id;

  GURL origin("https://example.com");

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->WriteNotificationData(origin, database_data));

  // Reading a notification after writing one should succeed.
  EXPECT_EQ(
      NotificationDatabase::STATUS_OK,
      database->ReadNotificationData(notification_id, origin, &database_data));

  // Delete the notification which was just written to the database, and verify
  // that reading it again will fail.
  EXPECT_EQ(NotificationDatabase::STATUS_OK,
            database->DeleteNotificationData(notification_id, origin));
  EXPECT_EQ(
      NotificationDatabase::STATUS_ERROR_NOT_FOUND,
      database->ReadNotificationData(notification_id, origin, &database_data));
}

TEST_F(NotificationDatabaseTest, DeleteNotificationDataDifferentOrigin) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  const std::string notification_id = GenerateNotificationId();

  NotificationDatabaseData database_data;
  database_data.notification_id = notification_id;

  GURL origin("https://example.com");

  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->WriteNotificationData(origin, database_data));

  // Attempting to delete the notification with a different origin, but with the
  // same |notification_id|, should not return an error (the notification could
  // not be found, but that's not considered a failure). However, it should not
  // remove the notification either.
  EXPECT_EQ(NotificationDatabase::STATUS_OK,
            database->DeleteNotificationData(notification_id,
                                             GURL("https://chrome.com")));

  EXPECT_EQ(
      NotificationDatabase::STATUS_OK,
      database->ReadNotificationData(notification_id, origin, &database_data));
}

TEST_F(NotificationDatabaseTest, ReadAllNotificationData) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));

  std::vector<NotificationDatabaseData> notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationData(&notifications));

  EXPECT_EQ(arraysize(kExampleNotificationData), notifications.size());
}

TEST_F(NotificationDatabaseTest, ReadAllNotificationDataEmpty) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  std::vector<NotificationDatabaseData> notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationData(&notifications));

  EXPECT_EQ(0u, notifications.size());
}

TEST_F(NotificationDatabaseTest, ReadAllNotificationDataForOrigin) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));

  GURL origin("https://example.com");

  std::vector<NotificationDatabaseData> notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationDataForOrigin(origin, &notifications));

  EXPECT_EQ(4u, notifications.size());
}

TEST_F(NotificationDatabaseTest,
       ReadAllNotificationDataForServiceWorkerRegistration) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));

  GURL origin("https://example.com:443");

  std::vector<NotificationDatabaseData> notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationDataForServiceWorkerRegistration(
                origin, kExampleServiceWorkerRegistrationId, &notifications));

  EXPECT_EQ(2u, notifications.size());
}

TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOrigin) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));

  GURL origin("https://example.com:443");

  std::set<std::string> deleted_notification_ids;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->DeleteAllNotificationDataForOrigin(
                origin, "" /* tag */, &deleted_notification_ids));

  EXPECT_EQ(4u, deleted_notification_ids.size());

  std::vector<NotificationDatabaseData> notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationDataForOrigin(origin, &notifications));

  EXPECT_EQ(0u, notifications.size());
}

TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOriginWithTag) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));

  GURL origin("https://chrome.com");

  std::vector<NotificationDatabaseData> notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationDataForOrigin(origin, &notifications));

  const std::string& tag = "foo";

  size_t notifications_with_tag = 0;
  size_t notifications_without_tag = 0;

  for (const auto& database_data : notifications) {
    if (database_data.notification_data.tag == tag)
      ++notifications_with_tag;
    else
      ++notifications_without_tag;
  }

  ASSERT_GT(notifications_with_tag, 0u);
  ASSERT_GT(notifications_without_tag, 0u);

  std::set<std::string> deleted_notification_ids;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->DeleteAllNotificationDataForOrigin(
                origin, "foo" /* tag */, &deleted_notification_ids));

  EXPECT_EQ(notifications_with_tag, deleted_notification_ids.size());

  std::vector<NotificationDatabaseData> updated_notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationDataForOrigin(origin,
                                                       &updated_notifications));

  EXPECT_EQ(notifications_without_tag, updated_notifications.size());

  size_t updated_notifications_with_tag = 0;
  size_t updated_notifications_without_tag = 0;

  for (const auto& database_data : updated_notifications) {
    if (database_data.notification_data.tag == tag)
      ++updated_notifications_with_tag;
    else
      ++updated_notifications_without_tag;
  }

  EXPECT_EQ(0u, updated_notifications_with_tag);
  EXPECT_EQ(notifications_without_tag, updated_notifications_without_tag);
}

TEST_F(NotificationDatabaseTest, DeleteAllNotificationDataForOriginEmpty) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  GURL origin("https://example.com");

  std::set<std::string> deleted_notification_ids;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->DeleteAllNotificationDataForOrigin(
                origin, "" /* tag */, &deleted_notification_ids));

  EXPECT_EQ(0u, deleted_notification_ids.size());
}

TEST_F(NotificationDatabaseTest,
       DeleteAllNotificationDataForServiceWorkerRegistration) {
  std::unique_ptr<NotificationDatabase> database(CreateDatabaseInMemory());
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->Open(true /* create_if_missing */));

  ASSERT_NO_FATAL_FAILURE(PopulateDatabaseWithExampleData(database.get()));

  GURL origin("https://example.com:443");
  std::set<std::string> deleted_notification_ids;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->DeleteAllNotificationDataForServiceWorkerRegistration(
                origin, kExampleServiceWorkerRegistrationId,
                &deleted_notification_ids));

  EXPECT_EQ(2u, deleted_notification_ids.size());

  std::vector<NotificationDatabaseData> notifications;
  ASSERT_EQ(NotificationDatabase::STATUS_OK,
            database->ReadAllNotificationDataForServiceWorkerRegistration(
                origin, kExampleServiceWorkerRegistrationId, &notifications));

  EXPECT_EQ(0u, notifications.size());
}

}  // namespace content
