summaryrefslogtreecommitdiffstats
path: root/components/wifi_sync
diff options
context:
space:
mode:
authorquiche <quiche@chromium.org>2015-01-26 12:12:55 -0800
committerCommit bot <commit-bot@chromium.org>2015-01-26 20:14:09 +0000
commitc96b5d5783a331aeea09e91e87f2f3678909c37f (patch)
treeb5d357f112d770ce91c98f7e367a1290c1e481e2 /components/wifi_sync
parentc324546cf857bae485efb9a2d80eec6d50d18ed5 (diff)
downloadchromium_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.gn2
-rw-r--r--components/wifi_sync/DEPS2
-rw-r--r--components/wifi_sync/wifi_credential_syncable_service.cc169
-rw-r--r--components/wifi_sync/wifi_credential_syncable_service.h29
-rw-r--r--components/wifi_sync/wifi_credential_syncable_service_factory.cc35
-rw-r--r--components/wifi_sync/wifi_credential_syncable_service_unittest.cc286
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