Commit bff7ae96 authored by Jon Mann's avatar Jon Mann Committed by Commit Bot

Use the last connected timestamp when merging sync and local networks.

When Wi-Fi sync is first enabled and a list of synced networks
has to be merged with the local networks on a device, use the last
connected timestamp to decide which configuration should be used.

Bug: 966270
Change-Id: Id7688a0fdb9e7922cee8ffec0ef69b804436e3e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2093274Reviewed-by: default avatarJames Vecore <vecore@google.com>
Commit-Queue: Jon Mann <jonmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#750257}
parent b8bfdbf3
...@@ -17,7 +17,9 @@ NetworkIdentifier GeneratePskNetworkId(const std::string& ssid) { ...@@ -17,7 +17,9 @@ NetworkIdentifier GeneratePskNetworkId(const std::string& ssid) {
} }
sync_pb::WifiConfigurationSpecifics GenerateTestWifiSpecifics( sync_pb::WifiConfigurationSpecifics GenerateTestWifiSpecifics(
const NetworkIdentifier& id) { const NetworkIdentifier& id,
const std::string& passphrase = "passphrase",
double timestamp = 1) {
sync_pb::WifiConfigurationSpecifics specifics; sync_pb::WifiConfigurationSpecifics specifics;
specifics.set_hex_ssid(id.hex_ssid()); specifics.set_hex_ssid(id.hex_ssid());
...@@ -30,7 +32,8 @@ sync_pb::WifiConfigurationSpecifics GenerateTestWifiSpecifics( ...@@ -30,7 +32,8 @@ sync_pb::WifiConfigurationSpecifics GenerateTestWifiSpecifics(
} else { } else {
NOTREACHED(); NOTREACHED();
} }
specifics.set_passphrase("password"); specifics.set_passphrase(passphrase);
specifics.set_last_update_timestamp(timestamp);
specifics.set_automatically_connect( specifics.set_automatically_connect(
sync_pb::WifiConfigurationSpecifics::AUTOMATICALLY_CONNECT_ENABLED); sync_pb::WifiConfigurationSpecifics::AUTOMATICALLY_CONNECT_ENABLED);
specifics.set_is_preferred( specifics.set_is_preferred(
......
...@@ -19,7 +19,9 @@ NetworkIdentifier GeneratePskNetworkId(const std::string& ssid); ...@@ -19,7 +19,9 @@ NetworkIdentifier GeneratePskNetworkId(const std::string& ssid);
// Creates a proto with default values and sets the hex_ssid and security_type // Creates a proto with default values and sets the hex_ssid and security_type
// based on the input |id|. // based on the input |id|.
sync_pb::WifiConfigurationSpecifics GenerateTestWifiSpecifics( sync_pb::WifiConfigurationSpecifics GenerateTestWifiSpecifics(
const NetworkIdentifier& id); const NetworkIdentifier& id,
const std::string& passphrase = "passphrase",
double timestamp = 1);
} // namespace sync_wifi } // namespace sync_wifi
......
...@@ -76,20 +76,86 @@ base::Optional<syncer::ModelError> WifiConfigurationBridge::MergeSyncData( ...@@ -76,20 +76,86 @@ base::Optional<syncer::ModelError> WifiConfigurationBridge::MergeSyncData(
void WifiConfigurationBridge::OnGetAllSyncableNetworksResult( void WifiConfigurationBridge::OnGetAllSyncableNetworksResult(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList change_list, syncer::EntityChangeList change_list,
std::vector<sync_pb::WifiConfigurationSpecifics> list) { std::vector<sync_pb::WifiConfigurationSpecifics> local_network_list) {
NET_LOG(DEBUG) << list.size() << " local networks eligible for sync."; // To merge local and synced networks we add all local networks that don't
// exist in sync to the server and all synced networks that don't exist
// locally to Shill. For networks which exist on both lists, we compare the
// last connected timestamp and take the newer configuration.
NET_LOG(DEBUG) << local_network_list.size()
<< " local networks eligible for sync.";
base::flat_map<NetworkIdentifier, sync_pb::WifiConfigurationSpecifics>
sync_networks;
base::flat_map<NetworkIdentifier, sync_pb::WifiConfigurationSpecifics>
local_networks;
// Iterate through incoming changes from sync and populate the sync_networks
// map.
for (std::unique_ptr<syncer::EntityChange>& change : change_list) {
if (change->type() == syncer::EntityChange::ACTION_DELETE) {
// Don't delete any local networks during the initial merge when sync is
// first enabled.
continue;
}
for (sync_pb::WifiConfigurationSpecifics& proto : list) { const sync_pb::WifiConfigurationSpecifics& proto =
// TODO(jonmann) Don't override local configurations that are newer. change->data().specifics.wifi_configuration();
NetworkIdentifier id = NetworkIdentifier::FromProto(proto);
if (sync_networks.contains(id) &&
sync_networks[id].last_update_timestamp() >
proto.last_update_timestamp()) {
continue;
}
sync_networks[id] = proto;
}
// Iterate through local networks and add to sync where appropriate.
for (sync_pb::WifiConfigurationSpecifics& proto : local_network_list) {
NetworkIdentifier id = NetworkIdentifier::FromProto(proto);
if (sync_networks.contains(id) &&
sync_networks[id].last_update_timestamp() >
proto.last_update_timestamp()) {
continue;
}
local_networks[id] = proto;
std::unique_ptr<syncer::EntityData> entity_data = std::unique_ptr<syncer::EntityData> entity_data =
GenerateWifiEntityData(proto); GenerateWifiEntityData(proto);
std::string storage_key = GetStorageKey(*entity_data); std::string storage_key = GetStorageKey(*entity_data);
// Upload the local network configuration to sync. This could be a new
// configuration or an update to an existing one.
change_processor()->Put(storage_key, std::move(entity_data), change_processor()->Put(storage_key, std::move(entity_data),
metadata_change_list.get()); metadata_change_list.get());
entries_[storage_key] = proto; entries_[storage_key] = proto;
} }
ApplySyncChanges(std::move(metadata_change_list), std::move(change_list)); std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch =
store_->CreateWriteBatch();
// Iterate through synced networks and update local stack where appropriate.
for (auto& kv : sync_networks) {
NetworkIdentifier& id = kv.first;
sync_pb::WifiConfigurationSpecifics& proto = kv.second;
if (local_networks.contains(id) &&
local_networks[id].last_update_timestamp() >
proto.last_update_timestamp()) {
continue;
}
// Update the local network stack to have the synced network configuration.
synced_network_updater_->AddOrUpdateNetwork(proto);
// Save the proto to the sync data store to keep track of all synced
// networks on device. This gets loaded into |entries_| next time the
// bridge is initialized.
batch->WriteData(id.SerializeToString(), proto.SerializeAsString());
entries_[id.SerializeToString()] = proto;
}
// Mark the changes as processed.
batch->TakeMetadataChangesFrom(std::move(metadata_change_list));
Commit(std::move(batch));
} }
base::Optional<syncer::ModelError> WifiConfigurationBridge::ApplySyncChanges( base::Optional<syncer::ModelError> WifiConfigurationBridge::ApplySyncChanges(
......
...@@ -72,7 +72,7 @@ class WifiConfigurationBridge : public syncer::ModelTypeSyncBridge { ...@@ -72,7 +72,7 @@ class WifiConfigurationBridge : public syncer::ModelTypeSyncBridge {
void OnGetAllSyncableNetworksResult( void OnGetAllSyncableNetworksResult(
std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
syncer::EntityChangeList change_list, syncer::EntityChangeList change_list,
std::vector<sync_pb::WifiConfigurationSpecifics> list); std::vector<sync_pb::WifiConfigurationSpecifics> local_network_list);
// An in-memory list of the proto's that mirrors what is on the sync server. // An in-memory list of the proto's that mirrors what is on the sync server.
// This gets updated when changes are received from the server and after local // This gets updated when changes are received from the server and after local
......
...@@ -45,6 +45,7 @@ using testing::UnorderedElementsAre; ...@@ -45,6 +45,7 @@ using testing::UnorderedElementsAre;
const char kSsidMeow[] = "meow"; const char kSsidMeow[] = "meow";
const char kSsidWoof[] = "woof"; const char kSsidWoof[] = "woof";
const char kSsidHonk[] = "honk";
syncer::EntityData GenerateWifiEntityData( syncer::EntityData GenerateWifiEntityData(
const sync_pb::WifiConfigurationSpecifics& data) { const sync_pb::WifiConfigurationSpecifics& data) {
...@@ -55,13 +56,17 @@ syncer::EntityData GenerateWifiEntityData( ...@@ -55,13 +56,17 @@ syncer::EntityData GenerateWifiEntityData(
return entity_data; return entity_data;
} }
bool ProtoVectorContainsId( bool VectorContainsProto(
const std::vector<sync_pb::WifiConfigurationSpecifics>& protos, const std::vector<sync_pb::WifiConfigurationSpecifics>& protos,
NetworkIdentifier id) { const sync_pb::WifiConfigurationSpecifics& proto) {
return std::find_if( return std::find_if(
protos.begin(), protos.end(), protos.begin(), protos.end(),
[&id](const sync_pb::WifiConfigurationSpecifics& specifics) { [&proto](const sync_pb::WifiConfigurationSpecifics& specifics) {
return NetworkIdentifier::FromProto(specifics) == id; return NetworkIdentifier::FromProto(specifics) ==
NetworkIdentifier::FromProto(proto) &&
specifics.last_update_timestamp() ==
proto.last_update_timestamp() &&
specifics.passphrase() == proto.passphrase();
}) != protos.end(); }) != protos.end();
} }
...@@ -164,6 +169,8 @@ class WifiConfigurationBridgeTest : public testing::Test { ...@@ -164,6 +169,8 @@ class WifiConfigurationBridgeTest : public testing::Test {
const NetworkIdentifier& meow_network_id() const { return meow_network_id_; } const NetworkIdentifier& meow_network_id() const { return meow_network_id_; }
const NetworkIdentifier& honk_network_id() const { return honk_network_id_; }
private: private:
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
...@@ -181,21 +188,25 @@ class WifiConfigurationBridgeTest : public testing::Test { ...@@ -181,21 +188,25 @@ class WifiConfigurationBridgeTest : public testing::Test {
const NetworkIdentifier meow_network_id_ = GeneratePskNetworkId(kSsidMeow); const NetworkIdentifier meow_network_id_ = GeneratePskNetworkId(kSsidMeow);
const NetworkIdentifier honk_network_id_ = GeneratePskNetworkId(kSsidHonk);
DISALLOW_COPY_AND_ASSIGN(WifiConfigurationBridgeTest); DISALLOW_COPY_AND_ASSIGN(WifiConfigurationBridgeTest);
}; };
TEST_F(WifiConfigurationBridgeTest, InitWithTwoNetworksFromServer) { TEST_F(WifiConfigurationBridgeTest, InitWithTwoNetworksFromServer) {
syncer::EntityChangeList remote_input; syncer::EntityChangeList remote_input;
WifiConfigurationSpecifics entry1 = WifiConfigurationSpecifics meow_network =
GenerateTestWifiSpecifics(meow_network_id()); GenerateTestWifiSpecifics(meow_network_id());
WifiConfigurationSpecifics entry2 = WifiConfigurationSpecifics woof_network =
GenerateTestWifiSpecifics(woof_network_id()); GenerateTestWifiSpecifics(woof_network_id());
remote_input.push_back(syncer::EntityChange::CreateAdd( remote_input.push_back(
meow_network_id().SerializeToString(), GenerateWifiEntityData(entry1))); syncer::EntityChange::CreateAdd(meow_network_id().SerializeToString(),
remote_input.push_back(syncer::EntityChange::CreateAdd( GenerateWifiEntityData(meow_network)));
woof_network_id().SerializeToString(), GenerateWifiEntityData(entry2))); remote_input.push_back(
syncer::EntityChange::CreateAdd(woof_network_id().SerializeToString(),
GenerateWifiEntityData(woof_network)));
bridge()->MergeSyncData( bridge()->MergeSyncData(
std::make_unique<syncer::InMemoryMetadataChangeList>(), std::make_unique<syncer::InMemoryMetadataChangeList>(),
...@@ -209,19 +220,19 @@ TEST_F(WifiConfigurationBridgeTest, InitWithTwoNetworksFromServer) { ...@@ -209,19 +220,19 @@ TEST_F(WifiConfigurationBridgeTest, InitWithTwoNetworksFromServer) {
const std::vector<sync_pb::WifiConfigurationSpecifics>& networks = const std::vector<sync_pb::WifiConfigurationSpecifics>& networks =
synced_network_updater()->add_or_update_calls(); synced_network_updater()->add_or_update_calls();
EXPECT_EQ(2u, networks.size()); EXPECT_EQ(2u, networks.size());
EXPECT_TRUE(ProtoVectorContainsId(networks, meow_network_id())); EXPECT_TRUE(VectorContainsProto(networks, meow_network));
EXPECT_TRUE(ProtoVectorContainsId(networks, woof_network_id())); EXPECT_TRUE(VectorContainsProto(networks, woof_network));
} }
TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesAddTwoSpecifics) { TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesAddTwoSpecifics) {
const WifiConfigurationSpecifics specifics1 = const WifiConfigurationSpecifics meow_network =
GenerateTestWifiSpecifics(meow_network_id()); GenerateTestWifiSpecifics(meow_network_id());
const WifiConfigurationSpecifics specifics2 = const WifiConfigurationSpecifics woof_network =
GenerateTestWifiSpecifics(woof_network_id()); GenerateTestWifiSpecifics(woof_network_id());
base::Optional<syncer::ModelError> error = base::Optional<syncer::ModelError> error = bridge()->ApplySyncChanges(
bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(), bridge()->CreateMetadataChangeList(),
CreateEntityAddList({specifics1, specifics2})); CreateEntityAddList({meow_network, woof_network}));
EXPECT_FALSE(error); EXPECT_FALSE(error);
std::vector<NetworkIdentifier> ids = bridge()->GetAllIdsForTesting(); std::vector<NetworkIdentifier> ids = bridge()->GetAllIdsForTesting();
EXPECT_EQ(2u, ids.size()); EXPECT_EQ(2u, ids.size());
...@@ -231,8 +242,8 @@ TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesAddTwoSpecifics) { ...@@ -231,8 +242,8 @@ TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesAddTwoSpecifics) {
const std::vector<sync_pb::WifiConfigurationSpecifics>& networks = const std::vector<sync_pb::WifiConfigurationSpecifics>& networks =
synced_network_updater()->add_or_update_calls(); synced_network_updater()->add_or_update_calls();
EXPECT_EQ(2u, networks.size()); EXPECT_EQ(2u, networks.size());
EXPECT_TRUE(ProtoVectorContainsId(networks, meow_network_id())); EXPECT_TRUE(VectorContainsProto(networks, woof_network));
EXPECT_TRUE(ProtoVectorContainsId(networks, woof_network_id())); EXPECT_TRUE(VectorContainsProto(networks, meow_network));
} }
TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneAdd) { TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneAdd) {
...@@ -254,7 +265,7 @@ TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneAdd) { ...@@ -254,7 +265,7 @@ TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneAdd) {
const std::vector<sync_pb::WifiConfigurationSpecifics>& networks = const std::vector<sync_pb::WifiConfigurationSpecifics>& networks =
synced_network_updater()->add_or_update_calls(); synced_network_updater()->add_or_update_calls();
EXPECT_EQ(1u, networks.size()); EXPECT_EQ(1u, networks.size());
EXPECT_TRUE(ProtoVectorContainsId(networks, meow_network_id())); EXPECT_TRUE(VectorContainsProto(networks, entry));
} }
TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneDeletion) { TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneDeletion) {
...@@ -276,7 +287,7 @@ TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneDeletion) { ...@@ -276,7 +287,7 @@ TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneDeletion) {
const std::vector<sync_pb::WifiConfigurationSpecifics>& networks = const std::vector<sync_pb::WifiConfigurationSpecifics>& networks =
synced_network_updater()->add_or_update_calls(); synced_network_updater()->add_or_update_calls();
EXPECT_EQ(1u, networks.size()); EXPECT_EQ(1u, networks.size());
EXPECT_TRUE(ProtoVectorContainsId(networks, meow_network_id())); EXPECT_TRUE(VectorContainsProto(networks, entry));
syncer::EntityChangeList delete_changes; syncer::EntityChangeList delete_changes;
delete_changes.push_back( delete_changes.push_back(
...@@ -296,16 +307,31 @@ TEST_F(WifiConfigurationBridgeTest, MergeSyncData) { ...@@ -296,16 +307,31 @@ TEST_F(WifiConfigurationBridgeTest, MergeSyncData) {
auto metadata_change_list = auto metadata_change_list =
std::make_unique<syncer::InMemoryMetadataChangeList>(); std::make_unique<syncer::InMemoryMetadataChangeList>();
syncer::EntityChangeList entity_data; syncer::EntityChangeList entity_data;
const char kSyncPsk[] = "sync_psk";
WifiConfigurationSpecifics meow_network = const char kLocalPsk[] = "local_psk";
GenerateTestWifiSpecifics(meow_network_id());
WifiConfigurationSpecifics meow_sync =
GenerateTestWifiSpecifics(meow_network_id(), kSyncPsk, /*timestamp=*/100);
WifiConfigurationSpecifics woof_sync =
GenerateTestWifiSpecifics(woof_network_id(), kSyncPsk, /*timestamp=*/100);
WifiConfigurationSpecifics honk_sync =
GenerateTestWifiSpecifics(honk_network_id(), kSyncPsk, /*timestamp=*/100);
entity_data.push_back( entity_data.push_back(
syncer::EntityChange::CreateAdd(meow_network_id().SerializeToString(), syncer::EntityChange::CreateAdd(meow_network_id().SerializeToString(),
GenerateWifiEntityData(meow_network))); GenerateWifiEntityData(meow_sync)));
entity_data.push_back(
syncer::EntityChange::CreateAdd(woof_network_id().SerializeToString(),
GenerateWifiEntityData(woof_sync)));
entity_data.push_back(
syncer::EntityChange::CreateAdd(honk_network_id().SerializeToString(),
GenerateWifiEntityData(honk_sync)));
WifiConfigurationSpecifics woof_network = WifiConfigurationSpecifics woof_local =
GenerateTestWifiSpecifics(woof_network_id()); GenerateTestWifiSpecifics(woof_network_id(), kLocalPsk, /*timestamp=*/1);
local_network_collector()->AddNetwork(woof_network); WifiConfigurationSpecifics meow_local = GenerateTestWifiSpecifics(
meow_network_id(), kLocalPsk, /*timestamp=*/1000);
local_network_collector()->AddNetwork(woof_local);
local_network_collector()->AddNetwork(meow_local);
std::string storage_key; std::string storage_key;
EXPECT_CALL(*processor(), Put(_, _, _)) EXPECT_CALL(*processor(), Put(_, _, _))
...@@ -316,17 +342,21 @@ TEST_F(WifiConfigurationBridgeTest, MergeSyncData) { ...@@ -316,17 +342,21 @@ TEST_F(WifiConfigurationBridgeTest, MergeSyncData) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
// Verify local network was added to sync. // Verify local network was added to sync.
EXPECT_EQ(storage_key, woof_network_id().SerializeToString()); EXPECT_EQ(storage_key, meow_network_id().SerializeToString());
// Verify sync network was added to local stack. // Verify sync network was added to local stack.
const std::vector<sync_pb::WifiConfigurationSpecifics>& const std::vector<sync_pb::WifiConfigurationSpecifics>&
updated_local_networks = synced_network_updater()->add_or_update_calls(); updated_local_networks = synced_network_updater()->add_or_update_calls();
EXPECT_EQ(1u, updated_local_networks.size()); EXPECT_EQ(2u, updated_local_networks.size());
EXPECT_TRUE(ProtoVectorContainsId(updated_local_networks, meow_network_id())); EXPECT_TRUE(VectorContainsProto(updated_local_networks, woof_sync));
EXPECT_TRUE(VectorContainsProto(updated_local_networks, honk_sync));
std::vector<sync_pb::WifiConfigurationSpecifics> sync_networks = std::vector<sync_pb::WifiConfigurationSpecifics> sync_networks =
GetAllSyncedData(); GetAllSyncedData();
EXPECT_EQ(2u, sync_networks.size()); EXPECT_EQ(3u, sync_networks.size());
EXPECT_TRUE(VectorContainsProto(sync_networks, meow_local));
EXPECT_TRUE(VectorContainsProto(sync_networks, woof_sync));
EXPECT_TRUE(VectorContainsProto(sync_networks, honk_sync));
} }
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment