blob: ca4713ccaa29031bbdcad23abc0afc7259a37fef [file] [log] [blame]
// Copyright 2014 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 "chrome/browser/notifications/sync_notifier/synced_notification_app_info_service.h"
#include "chrome/browser/notifications/sync_notifier/sync_notifier_test_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/test/base/testing_pref_service_syncable.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "sync/api/fake_sync_change_processor.h"
#include "sync/api/sync_change.h"
#include "sync/api/sync_change_processor.h"
#include "sync/api/sync_error_factory.h"
#include "sync/api/sync_error_factory_mock.h"
#include "sync/protocol/sync.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
using sync_pb::EntitySpecifics;
using syncer::SyncData;
using syncer::SyncChange;
using syncer::SyncChangeList;
using syncer::SyncDataList;
using syncer::SYNCED_NOTIFICATION_APP_INFO;
using notifier::SyncedNotificationAppInfo;
using notifier::SyncedNotificationAppInfoService;
using sync_pb::SyncedNotificationAppInfoSpecifics;
namespace notifier {
// Extract app_info id from syncer::SyncData.
std::string GetAppInfoId(const SyncData& sync_data) {
SyncedNotificationAppInfoSpecifics specifics =
sync_data.GetSpecifics().synced_notification_app_info();
// TODO(petewil): It would be better if we had a designated unique identifier
// instead of relying on the display name to be unique.
return specifics.synced_notification_app_info(0).settings_display_name();
}
// Dummy SyncChangeProcessor used to help review what SyncChanges are pushed
// back up to Sync.
class TestChangeProcessor : public syncer::SyncChangeProcessor {
public:
TestChangeProcessor() {}
virtual ~TestChangeProcessor() {}
// Store a copy of all the changes passed in so we can examine them later.
virtual syncer::SyncError ProcessSyncChanges(
const tracked_objects::Location& from_here,
const SyncChangeList& change_list) OVERRIDE {
change_map_.clear();
for (SyncChangeList::const_iterator iter = change_list.begin();
iter != change_list.end();
++iter) {
// Put the data into the change tracking map.
change_map_[GetAppInfoId(iter->sync_data())] = *iter;
}
return syncer::SyncError();
}
virtual syncer::SyncDataList GetAllSyncData(syncer::ModelType type)
const OVERRIDE {
return syncer::SyncDataList();
}
size_t change_list_size() { return change_map_.size(); }
bool ContainsId(const std::string& id) {
return change_map_.find(id) != change_map_.end();
}
SyncChange GetChangeById(const std::string& id) {
EXPECT_TRUE(ContainsId(id));
return change_map_[id];
}
private:
// Track the changes received in ProcessSyncChanges.
std::map<std::string, SyncChange> change_map_;
DISALLOW_COPY_AND_ASSIGN(TestChangeProcessor);
};
class SyncedNotificationAppInfoServiceTest : public testing::Test {
public:
SyncedNotificationAppInfoServiceTest()
: sync_processor_(new TestChangeProcessor),
sync_processor_delegate_(
new syncer::FakeSyncChangeProcessor()) {}
virtual ~SyncedNotificationAppInfoServiceTest() {}
// Overrides from testing::Test.
virtual void SetUp() { profile_.reset(new TestingProfile()); }
// Introduce some sample test data into the system.
void AddTestingAppInfosToList(
SyncedNotificationAppInfoService* app_info_service) {
// Create the app_info struct, setting the settings display name.
// The sending_service_infos_ list will take ownership of this pointer.
SyncedNotificationAppInfo* test_item1 = new SyncedNotificationAppInfo(
NULL, kSendingService1Name, app_info_service);
// Add some App IDs.
test_item1->AddAppId(kAppId1);
test_item1->AddAppId(kAppId2);
// Set this icon GURL.
test_item1->SetSettingsURLs(GURL(kTestIconUrl), GURL());
// Add to the list.
app_info_service->sending_service_infos_.push_back(test_item1);
// Add a second test item for another service.
SyncedNotificationAppInfo* test_item2 = new SyncedNotificationAppInfo(
NULL, kSendingService2Name, app_info_service);
// Add some App IDs.
test_item2->AddAppId(kAppId4);
test_item2->AddAppId(kAppId5);
// Set thi icon GURL.
test_item2->SetSettingsURLs(GURL(kTestIconUrl), GURL());
// Add to the list.
app_info_service->sending_service_infos_.push_back(test_item2);
}
// Put some representative test data into the AppInfo protobuf.
static void FillProtobufWithTestData1(
sync_pb::SyncedNotificationAppInfo& protobuf) {
protobuf.add_app_id(std::string(kAppId1));
protobuf.add_app_id(std::string(kAppId2));
protobuf.set_settings_display_name(kSendingService1Name);
protobuf.set_info_url(kTestInfoUrl);
protobuf.mutable_icon()->set_url(kTestIconUrl);
}
static void FillProtobufWithTestData2(
sync_pb::SyncedNotificationAppInfo& protobuf) {
protobuf.add_app_id(std::string(kAppId3));
protobuf.set_settings_display_name(kSendingService1Name);
protobuf.mutable_icon()->set_url(kTestIconUrl);
}
// Helper to create syncer::SyncChange.
static SyncChange CreateSyncChange(SyncChange::SyncChangeType type,
const std::string& settings_display_name,
const std::string& info_url,
const std::string& icon_url,
const std::string& app_id1,
const std::string& app_id2) {
return SyncChange(
FROM_HERE,
type,
CreateSyncData(
settings_display_name, info_url, icon_url, app_id1, app_id2));
}
// Build a SyncData object to look like what Sync would deliver.
static SyncData CreateSyncData(const std::string& settings_display_name,
const std::string& info_url,
const std::string& icon_url,
const std::string& app_id1,
const std::string& app_id2) {
// CreateLocalData makes a copy of this, so it can safely live on the stack.
EntitySpecifics entity_specifics;
EXPECT_FALSE(app_id1.empty());
sync_pb::SyncedNotificationAppInfoSpecifics* specifics =
entity_specifics.mutable_synced_notification_app_info();
// Add a synced_notification_app_info object.
specifics->add_synced_notification_app_info();
sync_pb::SyncedNotificationAppInfo* app_info =
specifics->mutable_synced_notification_app_info(0);
// Add the key, the settings display name.
app_info->set_settings_display_name(settings_display_name);
// Add the welcome notification info URL.
app_info->set_info_url(info_url);
// Add the icon URL.
app_info->mutable_icon()->set_url(icon_url);
// Add the app IDs.
app_info->add_app_id(app_id1);
// Only add the second if it is non-empty
if (!app_id2.empty()) {
app_info->add_app_id(app_id2);
}
// Create the sync data.
SyncData sync_data =
SyncData::CreateLocalData("syncer::SYNCED_NOTIFICATION_APP_INFO",
"SyncedNotificationAppInfoServiceUnitTest",
entity_specifics);
return sync_data;
}
TestChangeProcessor* processor() {
return static_cast<TestChangeProcessor*>(sync_processor_.get());
}
scoped_ptr<syncer::SyncChangeProcessor> PassProcessor() {
return sync_processor_delegate_.Pass();
}
protected:
scoped_ptr<TestingProfile> profile_;
private:
scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
scoped_ptr<syncer::SyncChangeProcessor> sync_processor_delegate_;
DISALLOW_COPY_AND_ASSIGN(SyncedNotificationAppInfoServiceTest);
};
// Null data case - we have no data, and sync has no data when we start up.
TEST_F(SyncedNotificationAppInfoServiceTest, MergeDataAndStartSyncingTest) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
app_info_service.MergeDataAndStartSyncing(
SYNCED_NOTIFICATION_APP_INFO,
SyncDataList(), // Empty.
PassProcessor(),
scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
EXPECT_EQ(static_cast<size_t>(0),
app_info_service.sending_service_infos_size());
}
// Process sync changes when there is no local data.
TEST_F(SyncedNotificationAppInfoServiceTest, ProcessSyncChangesEmptyModel) {
// We initially have no data.
SyncedNotificationAppInfoService app_info_service(profile_.get());
app_info_service.set_avoid_bitmap_fetching_for_test(true);
// Set up an ADD.
SyncChangeList changes;
changes.push_back(CreateSyncChange(SyncChange::ACTION_ADD,
kSendingService1Name,
kTestInfoUrl,
kTestIconUrl,
kAppId1,
kAppId2));
// Process the changes we built.
app_info_service.ProcessSyncChanges(FROM_HERE, changes);
// Verify sync change made it to the SyncedNotificationAppInfo list.
SyncedNotificationAppInfo* app_info1 =
app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService1Name);
EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), app_info1);
EXPECT_TRUE(app_info1->HasAppId(kAppId1));
EXPECT_TRUE(app_info1->HasAppId(kAppId2));
EXPECT_FALSE(app_info1->HasAppId(kAppId3));
EXPECT_EQ(app_info1->settings_icon_url(), GURL(kTestIconUrl));
}
// Process sync changes when there is local data.
TEST_F(SyncedNotificationAppInfoServiceTest, ProcessSyncChangesNonEmptyModel) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
app_info_service.set_avoid_bitmap_fetching_for_test(true);
// Create some local fake data. We rely on the specific ids set up here.
AddTestingAppInfosToList(&app_info_service);
// Set up an UPDATE.
SyncChangeList changes;
changes.push_back(CreateSyncChange(SyncChange::ACTION_UPDATE,
kSendingService1Name,
kTestInfoUrl,
kTestIconUrl,
kAppId1,
kAppId3));
// Simulate incoming changed sync data at runtime.
app_info_service.ProcessSyncChanges(FROM_HERE, changes);
// We should find that the first item now has a different set of app ids.
SyncedNotificationAppInfo* app_info1 =
app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService1Name);
EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), app_info1);
EXPECT_TRUE(app_info1->HasAppId(kAppId1));
EXPECT_FALSE(app_info1->HasAppId(kAppId2));
EXPECT_TRUE(app_info1->HasAppId(kAppId3));
EXPECT_EQ(app_info1->settings_icon_url(), GURL(kTestIconUrl));
}
// Test ProcessIncomingAppInfoProtobuf with an add.
TEST_F(SyncedNotificationAppInfoServiceTest,
ProcessIncomingAppInfoProtobufAddTest) {
// Get an app info service object.
SyncedNotificationAppInfoService app_info_service(profile_.get());
app_info_service.set_avoid_bitmap_fetching_for_test(true);
// Get an app info protobuf.
sync_pb::SyncedNotificationAppInfo protobuf;
FillProtobufWithTestData1(protobuf);
// Call the function we are testing.
app_info_service.ProcessIncomingAppInfoProtobuf(protobuf);
// Ensure that we now have an app_info in our list, and it looks like we
// expect.
notifier::SyncedNotificationAppInfo* found_app_info;
found_app_info = app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService1Name);
EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
found_app_info);
EXPECT_TRUE(found_app_info->HasAppId(kAppId1));
EXPECT_TRUE(found_app_info->HasAppId(kAppId2));
}
// Test ProcessIncomingAppInfoProtobuf with an update
TEST_F(SyncedNotificationAppInfoServiceTest,
ProcessIncomingAppInfoProtobufUpdateTest) {
// Get an app info service object.
SyncedNotificationAppInfoService app_info_service(profile_.get());
app_info_service.set_avoid_bitmap_fetching_for_test(true);
// Make an app info with the same display name as the first one in the test
// data.
sync_pb::SyncedNotificationAppInfo protobuf1;
FillProtobufWithTestData1(protobuf1);
app_info_service.ProcessIncomingAppInfoProtobuf(protobuf1);
// Ensure that we now have an app_info in our list, and it looks like we
// expect.
notifier::SyncedNotificationAppInfo* found_app_info1;
found_app_info1 = app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService1Name);
EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
found_app_info1);
EXPECT_TRUE(found_app_info1->HasAppId(kAppId1));
EXPECT_TRUE(found_app_info1->HasAppId(kAppId2));
// Make an update to the protobuf that has already been sent.
app_info_service.FreeSyncedNotificationAppInfoByName(kSendingService1Name);
// Change appid1 to appid3
sync_pb::SyncedNotificationAppInfo protobuf2;
FillProtobufWithTestData2(protobuf2);
app_info_service.ProcessIncomingAppInfoProtobuf(protobuf2);
// Ensure we have the same named app info as before, but it has the new
// contents.
notifier::SyncedNotificationAppInfo* found_app_info2;
found_app_info2 = app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService1Name);
EXPECT_NE(static_cast<notifier::SyncedNotificationAppInfo*>(NULL),
found_app_info2);
EXPECT_FALSE(found_app_info2->HasAppId(kAppId1));
EXPECT_TRUE(found_app_info2->HasAppId(kAppId3));
}
// Test our function that creates a synced notification from a protobuf.
TEST_F(SyncedNotificationAppInfoServiceTest,
CreateSyncedNotificationAppInfoFromProtobufTest) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
// Build a protobuf and fill it with data.
sync_pb::SyncedNotificationAppInfo protobuf;
FillProtobufWithTestData1(protobuf);
scoped_ptr<SyncedNotificationAppInfo> app_info;
app_info =
app_info_service.CreateSyncedNotificationAppInfoFromProtobuf(protobuf);
// Ensure the app info class has the fields we expect.
EXPECT_EQ(std::string(kSendingService1Name),
app_info->settings_display_name());
EXPECT_EQ(GURL(kTestInfoUrl), app_info->welcome_link_url());
EXPECT_TRUE(app_info->HasAppId(kAppId1));
EXPECT_TRUE(app_info->HasAppId(kAppId2));
EXPECT_EQ(GURL(std::string(kTestIconUrl)), app_info->settings_icon_url());
}
// Test our find by sending service name function.
TEST_F(SyncedNotificationAppInfoServiceTest,
FindSyncedNotificationAppInfoByNameTest) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
AddTestingAppInfosToList(&app_info_service);
SyncedNotificationAppInfo* found;
found = app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService1Name);
EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), found);
EXPECT_EQ(std::string(kSendingService1Name), found->settings_display_name());
found = app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService3Name);
EXPECT_EQ(NULL, found);
}
// Test our find by AppId function.
TEST_F(SyncedNotificationAppInfoServiceTest,
FindSyncedNotificationAppInfoByAppIdTest) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
AddTestingAppInfosToList(&app_info_service);
SyncedNotificationAppInfo* found;
found = app_info_service.FindSyncedNotificationAppInfoByAppId(kAppId1);
EXPECT_NE(static_cast<SyncedNotificationAppInfo*>(NULL), found);
EXPECT_EQ(std::string(kSendingService1Name), found->settings_display_name());
found = app_info_service.FindSyncedNotificationAppInfoByName(kAppId5);
EXPECT_EQ(NULL, found);
}
// Test our find sending service name by app id function.
TEST_F(SyncedNotificationAppInfoServiceTest,
FindSendingServiceNameFromAppIdTest) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
AddTestingAppInfosToList(&app_info_service);
std::string found_name;
found_name = app_info_service.FindSendingServiceNameFromAppId(kAppId1);
EXPECT_EQ(std::string(kSendingService1Name), found_name);
found_name = app_info_service.FindSendingServiceNameFromAppId(kAppId6);
EXPECT_TRUE(found_name.empty());
}
// Test our delete function.
TEST_F(SyncedNotificationAppInfoServiceTest,
FreeSyncedNotificationAppInfoByNameTest) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
AddTestingAppInfosToList(&app_info_service);
SyncedNotificationAppInfo* found;
app_info_service.FreeSyncedNotificationAppInfoByName(kSendingService1Name);
found = app_info_service.FindSyncedNotificationAppInfoByName(
kSendingService1Name);
EXPECT_EQ(NULL, found);
}
TEST_F(SyncedNotificationAppInfoServiceTest,
GetAllSendingServiceSettingsDataTest) {
SyncedNotificationAppInfoService app_info_service(profile_.get());
AddTestingAppInfosToList(&app_info_service);
std::vector<SyncedNotificationSendingServiceSettingsData> data;
data = app_info_service.GetAllSendingServiceSettingsData();
EXPECT_EQ(static_cast<unsigned int>(2), data.size());
EXPECT_EQ(kSendingService1Name, data[0].settings_display_name);
EXPECT_EQ(kSendingService2Name, data[1].settings_display_name);
}
} // namespace notifier