diff options
author | quiche <quiche@chromium.org> | 2015-01-26 12:12:55 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-01-26 20:14:09 +0000 |
commit | c96b5d5783a331aeea09e91e87f2f3678909c37f (patch) | |
tree | b5d357f112d770ce91c98f7e367a1290c1e481e2 /components/wifi_sync | |
parent | c324546cf857bae485efb9a2d80eec6d50d18ed5 (diff) | |
download | chromium_src-c96b5d5783a331aeea09e91e87f2f3678909c37f.zip chromium_src-c96b5d5783a331aeea09e91e87f2f3678909c37f.tar.gz chromium_src-c96b5d5783a331aeea09e91e87f2f3678909c37f.tar.bz2 |
wifi_sync: implement ACTION_ADD in WifiCredentialSyncableService
Implement support for adding networks. Specifically:
1) When an ACTION_ADD change is received from sync, apply that
change to the platform's network configruation.
2) Provide a method that upper layers can call, to add a network
to Chrome Sync.
BUG=chromium:431435
TEST=components_unittests --gtest_filter="Wifi*"
Review URL: https://codereview.chromium.org/836303004
Cr-Commit-Position: refs/heads/master@{#313109}
Diffstat (limited to 'components/wifi_sync')
-rw-r--r-- | components/wifi_sync/BUILD.gn | 2 | ||||
-rw-r--r-- | components/wifi_sync/DEPS | 2 | ||||
-rw-r--r-- | components/wifi_sync/wifi_credential_syncable_service.cc | 169 | ||||
-rw-r--r-- | components/wifi_sync/wifi_credential_syncable_service.h | 29 | ||||
-rw-r--r-- | components/wifi_sync/wifi_credential_syncable_service_factory.cc | 35 | ||||
-rw-r--r-- | components/wifi_sync/wifi_credential_syncable_service_unittest.cc | 286 |
6 files changed, 518 insertions, 5 deletions
diff --git a/components/wifi_sync/BUILD.gn b/components/wifi_sync/BUILD.gn index 324bc8a..0344428 100644 --- a/components/wifi_sync/BUILD.gn +++ b/components/wifi_sync/BUILD.gn @@ -33,11 +33,13 @@ source_set("unit_tests") { deps = [ ":wifi_sync", "//sync", + "//testing/gmock", "//testing/gtest", ] sources = [ "wifi_config_delegate_chromeos_unittest.cc", + "wifi_credential_syncable_service_unittest.cc", "wifi_credential_unittest.cc", "wifi_security_class_chromeos_unittest.cc", "wifi_security_class_unittest.cc", diff --git a/components/wifi_sync/DEPS b/components/wifi_sync/DEPS index c9d0bc0..441abe4 100644 --- a/components/wifi_sync/DEPS +++ b/components/wifi_sync/DEPS @@ -1,10 +1,12 @@ include_rules = [ "+chromeos/dbus", + "+chromeos/login", "+chromeos/network", "+components/keyed_service/content", "+components/keyed_service/core", "+components/onc", "+sync/api", + "+sync/internal_api/public/attachments", "+sync/protocol", "+third_party/cros_system_api/dbus/service_constants.h", ] diff --git a/components/wifi_sync/wifi_credential_syncable_service.cc b/components/wifi_sync/wifi_credential_syncable_service.cc index a78b92a..e402301 100644 --- a/components/wifi_sync/wifi_credential_syncable_service.cc +++ b/components/wifi_sync/wifi_credential_syncable_service.cc @@ -4,18 +4,111 @@ #include "components/wifi_sync/wifi_credential_syncable_service.h" +#include <stdint.h> +#include <vector> + #include "base/logging.h" +#include "components/wifi_sync/wifi_credential.h" +#include "components/wifi_sync/wifi_security_class.h" #include "sync/api/sync_change.h" +#include "sync/api/sync_data.h" #include "sync/api/sync_error.h" #include "sync/api/sync_error_factory.h" #include "sync/api/sync_merge_result.h" +#include "sync/protocol/sync.pb.h" namespace wifi_sync { +namespace { + +struct RawCredentialData { + std::vector<uint8_t> ssid; + WifiSecurityClass security_class; + std::string passphrase; +}; + +void BuildSpecifics(const WifiCredential& credential, + sync_pb::EntitySpecifics* out_buffer) { + DCHECK(out_buffer); + sync_pb::WifiCredentialSpecifics* credential_specifics = + out_buffer->mutable_wifi_credential(); + DCHECK(credential_specifics); + credential_specifics->set_ssid(credential.ssid().data(), + credential.ssid().size()); + credential_specifics->set_security_class( + WifiSecurityClassToSyncSecurityClass(credential.security_class())); + if (WifiSecurityClassSupportsPassphrases(credential.security_class())) { + credential_specifics->set_passphrase(credential.passphrase().data(), + credential.passphrase().size()); + } +} + +bool ParseSpecifics(const sync_pb::EntitySpecifics& specifics, + RawCredentialData* raw_credential) { + DCHECK(raw_credential); + if (!specifics.has_wifi_credential()) { + LOG(ERROR) << "Specifics with missing wifi_credential; skipping"; + return false; + } + + const sync_pb::WifiCredentialSpecifics& credential_specifics = + specifics.wifi_credential(); + if (!credential_specifics.has_ssid()) { + LOG(ERROR) << "Specifics with missing SSID; skipping"; + return false; + } + if (!credential_specifics.has_security_class()) { + LOG(ERROR) << "Specifics with missing security class; skipping"; + return false; + } + + const WifiSecurityClass security_class = + WifiSecurityClassFromSyncSecurityClass( + credential_specifics.security_class()); + if (WifiSecurityClassSupportsPassphrases(security_class) && + !credential_specifics.has_passphrase()) { + LOG(ERROR) << "Specifics for security class " + << credential_specifics.security_class() + << " is missing passphrase; skipping"; + return false; + } + + raw_credential->ssid.assign(credential_specifics.ssid().begin(), + credential_specifics.ssid().end()); + raw_credential->security_class = security_class; + raw_credential->passphrase = credential_specifics.passphrase(); + return true; +} + +// TODO(quiche): Separate SyncData validation from parsing of +// WifiCredentialSpecifics. +bool ParseSyncData(const syncer::SyncData& sync_data, + RawCredentialData* raw_credential) { + DCHECK(raw_credential); + if (!sync_data.IsValid()) { + LOG(WARNING) << "Invalid SyncData; skipping item"; + return false; + } + + if (sync_data.GetDataType() != syncer::WIFI_CREDENTIALS) { + LOG(WARNING) << "Unexpected SyncData of type " + << syncer::ModelTypeToString(sync_data.GetDataType()) + << "; skipping item"; + return false; + } + + return ParseSpecifics(sync_data.GetSpecifics(), raw_credential); +} + +} // namespace + const syncer::ModelType WifiCredentialSyncableService::kModelType = syncer::WIFI_CREDENTIALS; -WifiCredentialSyncableService::WifiCredentialSyncableService() { +WifiCredentialSyncableService::WifiCredentialSyncableService( + scoped_ptr<WifiConfigDelegate> network_config_delegate) + : network_config_delegate_(network_config_delegate.Pass()) { + DCHECK(network_config_delegate_); } WifiCredentialSyncableService::~WifiCredentialSyncableService() { @@ -32,7 +125,7 @@ syncer::SyncMergeResult WifiCredentialSyncableService::MergeDataAndStartSyncing( sync_processor_ = sync_processor.Pass(); - // TODO(quiche): Update local WiFi configuration. + // TODO(quiche): Update local WiFi configuration from |initial_sync_data|. // TODO(quiche): Notify upper layers that sync is ready. NOTIMPLEMENTED(); @@ -54,8 +147,78 @@ syncer::SyncDataList WifiCredentialSyncableService::GetAllSyncData( syncer::SyncError WifiCredentialSyncableService::ProcessSyncChanges( const tracked_objects::Location& /* caller_location */, const syncer::SyncChangeList& change_list) { - NOTIMPLEMENTED(); + if (!sync_processor_.get()) { + return syncer::SyncError( + FROM_HERE, syncer::SyncError::UNREADY_ERROR, + "ProcessSyncChanges called before MergeDataAndStartSyncing", + kModelType); + } + + for (const syncer::SyncChange& sync_change : change_list) { + DCHECK(sync_change.IsValid()); + RawCredentialData raw_credential; + if (!ParseSyncData(sync_change.sync_data(), &raw_credential)) { + LOG(WARNING) << "Failed to parse item; skipping " + << syncer::SyncChange::ChangeTypeToString( + sync_change.change_type()); + continue; + } + + scoped_ptr<WifiCredential> credential; + switch (sync_change.change_type()) { + case syncer::SyncChange::ACTION_ADD: + credential = WifiCredential::Create(raw_credential.ssid, + raw_credential.security_class, + raw_credential.passphrase); + if (!credential) + LOG(WARNING) << "Failed to create credential; skipping"; + else + network_config_delegate_->AddToLocalNetworks(*credential); + break; + case syncer::SyncChange::ACTION_UPDATE: + // TODO(quiche): Implement update, and add appropriate tests. + NOTIMPLEMENTED(); + break; + case syncer::SyncChange::ACTION_DELETE: + // TODO(quiche): Implement delete, and add appropriate tests. + NOTIMPLEMENTED(); + break; + default: + return syncer::SyncError( + FROM_HERE, syncer::SyncError::DATATYPE_ERROR, + "ProcessSyncChanges given invalid SyncChangeType", kModelType); + } + } + return syncer::SyncError(); } +bool WifiCredentialSyncableService::AddToSyncedNetworks( + const std::string& item_id, + const WifiCredential& credential) { + if (!sync_processor_.get()) { + // Callers must queue updates until MergeDataAndStartSyncing has + // been called on this SyncableService. + LOG(WARNING) << "WifiCredentials syncable service is not started."; + return false; + } + + // TODO(quiche): Handle case where network already exists. + syncer::SyncChangeList change_list; + syncer::SyncError sync_error; + sync_pb::EntitySpecifics wifi_credential_specifics; + BuildSpecifics(credential, &wifi_credential_specifics); + change_list.push_back( + syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, + syncer::SyncData::CreateLocalData( + item_id, item_id, wifi_credential_specifics))); + sync_error = sync_processor_->ProcessSyncChanges(FROM_HERE, change_list); + if (sync_error.IsSet()) { + LOG(ERROR) << sync_error.ToString(); + return false; + } + + return true; +} + } // namespace wifi_sync diff --git a/components/wifi_sync/wifi_credential_syncable_service.h b/components/wifi_sync/wifi_credential_syncable_service.h index fbd82f4..d0868e8 100644 --- a/components/wifi_sync/wifi_credential_syncable_service.h +++ b/components/wifi_sync/wifi_credential_syncable_service.h @@ -5,13 +5,17 @@ #ifndef COMPONENTS_WIFI_SYNC_WIFI_CREDENTIAL_SYNCABLE_SERVICE_H_ #define COMPONENTS_WIFI_SYNC_WIFI_CREDENTIAL_SYNCABLE_SERVICE_H_ +#include <string> + #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "components/keyed_service/core/keyed_service.h" +#include "components/wifi_sync/wifi_config_delegate.h" #include "sync/api/sync_change_processor.h" #include "sync/api/syncable_service.h" namespace wifi_sync { +class WifiCredential; // KeyedService that synchronizes WiFi credentials between local settings, // and Chrome Sync. @@ -19,10 +23,19 @@ namespace wifi_sync { // This service does not necessarily own the storage for WiFi // credentials. In particular, on ChromeOS, WiFi credential storage is // managed by the ChromeOS connection manager ("Shill"). +// +// On ChromeOS, this class should only be instantiated +// for the primary user profile, as that is the only profile for +// which a Shill profile is loaded. class WifiCredentialSyncableService : public syncer::SyncableService, public KeyedService { public: - WifiCredentialSyncableService(); + // Constructs a syncable service. Changes from Chrome Sync will be + // applied locally by |network_config_delegate|. Local changes will + // be propagated to Chrome Sync using the |sync_processor| provided + // in the call to MergeDataAndStartSyncing. + explicit WifiCredentialSyncableService( + scoped_ptr<WifiConfigDelegate> network_config_delegate); ~WifiCredentialSyncableService() override; // syncer::SyncableService implementation. @@ -37,11 +50,25 @@ class WifiCredentialSyncableService const tracked_objects::Location& caller_location, const syncer::SyncChangeList& change_list) override; + // Adds a WiFiCredential to Chrome Sync. |item_id| is a persistent + // identifier which can be used to later remove the credential. It + // is an error to add a network that already exists. It is also an + // error to call this method before MergeDataAndStartSyncing(), or + // after StopSyncing(). + // + // TODO(quiche): Allow changing a credential, by addding it again. + // crbug.com/431436 + bool AddToSyncedNetworks(const std::string& item_id, + const WifiCredential& credential); + private: // The syncer::ModelType that this SyncableService processes and // generates updates for. static const syncer::ModelType kModelType; + // The object we use to change local network configuration. + const scoped_ptr<WifiConfigDelegate> network_config_delegate_; + // Our SyncChangeProcessor instance. Used to push changes into // Chrome Sync. scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; diff --git a/components/wifi_sync/wifi_credential_syncable_service_factory.cc b/components/wifi_sync/wifi_credential_syncable_service_factory.cc index dbc2fec..cf3b460 100644 --- a/components/wifi_sync/wifi_credential_syncable_service_factory.cc +++ b/components/wifi_sync/wifi_credential_syncable_service_factory.cc @@ -4,11 +4,44 @@ #include "components/wifi_sync/wifi_credential_syncable_service_factory.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/wifi_sync/wifi_credential_syncable_service.h" +#if defined(OS_CHROMEOS) +#include "chromeos/login/login_state.h" +#include "chromeos/network/network_handler.h" +#include "components/wifi_sync/wifi_config_delegate_chromeos.h" +#endif + namespace wifi_sync { +namespace { + +scoped_ptr<WifiConfigDelegate> BuildConfigDelegate( + content::BrowserContext* context) { +#if defined(OS_CHROMEOS) + const chromeos::LoginState* login_state = chromeos::LoginState::Get(); + DCHECK(login_state->IsUserLoggedIn()); + DCHECK(!login_state->primary_user_hash().empty()); + // TODO(quiche): Verify that |context| is the primary user's context. + + // Note: NetworkHandler is a singleton that is managed by + // ChromeBrowserMainPartsChromeos, and destroyed after all + // KeyedService instances are destroyed. + chromeos::NetworkHandler* network_handler = chromeos::NetworkHandler::Get(); + return make_scoped_ptr(new WifiConfigDelegateChromeOs( + login_state->primary_user_hash(), + network_handler->managed_network_configuration_handler())); +#else + NOTREACHED(); + return nullptr; +#endif +} + +} // namespace + // static WifiCredentialSyncableService* WifiCredentialSyncableServiceFactory::GetForBrowserContext( @@ -38,7 +71,7 @@ KeyedService* WifiCredentialSyncableServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { // TODO(quiche): Figure out if this behaves properly for multi-profile. // crbug.com/430681. - return new WifiCredentialSyncableService(); + return new WifiCredentialSyncableService(BuildConfigDelegate(context)); } } // namespace wifi_sync diff --git a/components/wifi_sync/wifi_credential_syncable_service_unittest.cc b/components/wifi_sync/wifi_credential_syncable_service_unittest.cc new file mode 100644 index 0000000..d5de955 --- /dev/null +++ b/components/wifi_sync/wifi_credential_syncable_service_unittest.cc @@ -0,0 +1,286 @@ +// 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 "components/wifi_sync/wifi_credential_syncable_service.h" + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "base/tracked_objects.h" +#include "components/wifi_sync/wifi_config_delegate.h" +#include "components/wifi_sync/wifi_credential.h" +#include "components/wifi_sync/wifi_security_class.h" +#include "sync/api/attachments/attachment_id.h" +#include "sync/api/fake_sync_change_processor.h" +#include "sync/api/sync_change.h" +#include "sync/api/sync_data.h" +#include "sync/api/sync_error.h" +#include "sync/api/sync_error_factory_mock.h" +#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h" +#include "sync/protocol/sync.pb.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace wifi_sync { + +using syncer::FakeSyncChangeProcessor; +using syncer::SyncErrorFactoryMock; + +namespace { + +const char kSsidNonUtf8[] = "\xc0"; + +// Fake implementation of WifiConfigDelegate, which provides the +// ability to check how many times a WifiConfigDelegate method has +// been called. +class FakeWifiConfigDelegate : public WifiConfigDelegate { + public: + FakeWifiConfigDelegate() : add_count_(0) {} + ~FakeWifiConfigDelegate() override {} + + // WifiConfigDelegate implementation. + void AddToLocalNetworks(const WifiCredential& network_credential) override { + ++add_count_; + } + + // Returns the number of times the AddToLocalNetworks method has + // been called. + unsigned int add_count() const { return add_count_; } + + private: + // The number of times AddToLocalNetworks has been called on this fake. + unsigned int add_count_; + + DISALLOW_COPY_AND_ASSIGN(FakeWifiConfigDelegate); +}; + +// Unit tests for WifiCredentialSyncableService. +class WifiCredentialSyncableServiceTest : public testing::Test { + protected: + WifiCredentialSyncableServiceTest() + : config_delegate_(new FakeWifiConfigDelegate()), + change_processor_(nullptr) { + syncable_service_.reset( + new WifiCredentialSyncableService(make_scoped_ptr(config_delegate_))); + } + + // Wrappers for methods in WifiCredentialSyncableService. + syncer::SyncError ProcessSyncChanges( + const syncer::SyncChangeList& change_list) { + return syncable_service_->ProcessSyncChanges(FROM_HERE, change_list); + } + bool AddToSyncedNetworks(const std::string& item_id, + const WifiCredential& credential) { + return syncable_service_->AddToSyncedNetworks(item_id, credential); + } + + // Returns the number of change requests received by + // |change_processor_|. + int change_processor_changes_size() { + CHECK(change_processor_); + return change_processor_->changes().size(); + } + + // Returns the number of times AddToLocalNetworks has been called on + // |config_delegate_|. + unsigned int config_delegate_add_count() { + return config_delegate_->add_count(); + } + + // Returns a new WifiCredential constructed from the given parameters. + WifiCredential MakeCredential(const std::string& ssid, + WifiSecurityClass security_class, + const std::string& passphrase) { + scoped_ptr<WifiCredential> credential = WifiCredential::Create( + WifiCredential::MakeSsidBytesForTest(ssid), security_class, passphrase); + CHECK(credential); + return *credential; + } + + // Returns a new EntitySpecifics protobuf, with the + // wifi_credential_specifics fields populated with the given + // parameters. + sync_pb::EntitySpecifics MakeWifiCredentialSpecifics( + const std::string& ssid, + sync_pb::WifiCredentialSpecifics_SecurityClass security_class, + const std::string* passphrase) { + const std::vector<uint8_t> ssid_bytes(ssid.begin(), ssid.end()); + sync_pb::EntitySpecifics sync_entity_specifics; + sync_pb::WifiCredentialSpecifics* wifi_credential_specifics = + sync_entity_specifics.mutable_wifi_credential(); + CHECK(wifi_credential_specifics); + wifi_credential_specifics->set_ssid(ssid_bytes.data(), ssid_bytes.size()); + wifi_credential_specifics->set_security_class(security_class); + if (passphrase) { + wifi_credential_specifics->set_passphrase(passphrase->data(), + passphrase->size()); + } + return sync_entity_specifics; + } + + syncer::SyncChange MakeActionAdd( + int sync_item_id, + const std::string& ssid, + sync_pb::WifiCredentialSpecifics_SecurityClass security_class, + const std::string* passphrase) { + return syncer::SyncChange( + FROM_HERE, syncer::SyncChange::ACTION_ADD, + syncer::SyncData::CreateRemoteData( + sync_item_id, + MakeWifiCredentialSpecifics(ssid, security_class, passphrase), + base::Time(), syncer::AttachmentIdList(), + syncer::AttachmentServiceProxyForTest::Create())); + } + + void StartSyncing() { + scoped_ptr<FakeSyncChangeProcessor> change_processor( + new FakeSyncChangeProcessor()); + change_processor_ = change_processor.get(); + syncable_service_->MergeDataAndStartSyncing( + syncer::WIFI_CREDENTIALS, syncer::SyncDataList(), + change_processor.Pass(), make_scoped_ptr(new SyncErrorFactoryMock())); + } + + private: + scoped_ptr<WifiCredentialSyncableService> syncable_service_; + FakeWifiConfigDelegate* config_delegate_; // Owned by |syncable_service_| + FakeSyncChangeProcessor* change_processor_; // Owned by |syncable_service_| + + DISALLOW_COPY_AND_ASSIGN(WifiCredentialSyncableServiceTest); +}; + +} // namespace + +TEST_F(WifiCredentialSyncableServiceTest, ProcessSyncChangesNotStarted) { + syncer::SyncError sync_error(ProcessSyncChanges(syncer::SyncChangeList())); + ASSERT_TRUE(sync_error.IsSet()); + EXPECT_EQ(syncer::SyncError::UNREADY_ERROR, sync_error.error_type()); + EXPECT_EQ(0U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesActionAddSecurityClassInvalid) { + syncer::SyncChangeList changes; + const int sync_item_id = 1; + changes.push_back(MakeActionAdd( + sync_item_id, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_INVALID, nullptr)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); // Bad items are ignored. + EXPECT_EQ(0U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesActionAddSecurityClassNoneSuccess) { + syncer::SyncChangeList changes; + const int sync_item_id = 1; + changes.push_back(MakeActionAdd( + sync_item_id, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_NONE, nullptr)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); + EXPECT_EQ(1U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesActionAddSecurityClassWepMissingPassphrase) { + syncer::SyncChangeList changes; + const int sync_item_id = 1; + changes.push_back(MakeActionAdd( + sync_item_id, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_WEP, nullptr)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); // Bad items are ignored. + EXPECT_EQ(0U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesActionAddSecurityClassWepSuccess) { + syncer::SyncChangeList changes; + const int sync_item_id = 1; + const std::string passphrase("abcde"); + changes.push_back(MakeActionAdd( + sync_item_id, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_WEP, &passphrase)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); + EXPECT_EQ(1U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesActionAddSecurityClassPskMissingPassphrase) { + syncer::SyncChangeList changes; + const int sync_item_id = 1; + changes.push_back(MakeActionAdd( + sync_item_id, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_PSK, nullptr)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); // Bad items are ignored. + EXPECT_EQ(0U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesActionAddSecurityClassPskSuccess) { + syncer::SyncChangeList changes; + const int sync_item_id = 1; + const std::string passphrase("psk-passphrase"); + changes.push_back(MakeActionAdd( + sync_item_id, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_PSK, &passphrase)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); + EXPECT_EQ(1U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesContinuesAfterSecurityClassInvalid) { + syncer::SyncChangeList changes; + changes.push_back(MakeActionAdd( + 1 /* sync item id */, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_INVALID, nullptr)); + changes.push_back(MakeActionAdd( + 2 /* sync item id */, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_NONE, nullptr)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); // Bad items are ignored. + EXPECT_EQ(1U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, + ProcessSyncChangesContinuesAfterMissingPassphrase) { + syncer::SyncChangeList changes; + changes.push_back(MakeActionAdd( + 1 /* sync item id */, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_WEP, nullptr)); + changes.push_back(MakeActionAdd( + 2 /* sync item id */, kSsidNonUtf8, + sync_pb::WifiCredentialSpecifics::SECURITY_CLASS_NONE, nullptr)); + StartSyncing(); + syncer::SyncError sync_error = ProcessSyncChanges(changes); + EXPECT_FALSE(sync_error.IsSet()); // Bad items are ignored. + EXPECT_EQ(1U, config_delegate_add_count()); +} + +TEST_F(WifiCredentialSyncableServiceTest, AddToSyncedNetworksNotStarted) { + EXPECT_FALSE(AddToSyncedNetworks( + "fake-item-id", MakeCredential(kSsidNonUtf8, SECURITY_CLASS_NONE, ""))); +} + +TEST_F(WifiCredentialSyncableServiceTest, AddToSyncedNetworksSuccess) { + StartSyncing(); + EXPECT_TRUE(AddToSyncedNetworks( + "fake-item-id", MakeCredential(kSsidNonUtf8, SECURITY_CLASS_NONE, ""))); + EXPECT_EQ(1, change_processor_changes_size()); +} + +} // namespace wifi_sync |