chromium/chromeos/ash/components/sync_wifi/pending_network_configuration_tracker_impl_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/sync_wifi/pending_network_configuration_tracker_impl.h"

#include <memory>
#include <optional>

#include "base/functional/bind.h"
#include "chromeos/ash/components/sync_wifi/test_data_generator.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"

namespace ash::sync_wifi {

namespace {

const char kFredSsid[] = "Fred";
const char kMangoSsid[] = "Mango";

const char kPendingNetworkConfigurationsPref[] =
    "sync_wifi.pending_network_configuration_updates";
const char kChangeGuidKey[] = "ChangeGuid";

}  // namespace

class PendingNetworkConfigurationTrackerImplTest : public testing::Test {
 public:
  PendingNetworkConfigurationTrackerImplTest() = default;

  PendingNetworkConfigurationTrackerImplTest(
      const PendingNetworkConfigurationTrackerImplTest&) = delete;
  PendingNetworkConfigurationTrackerImplTest& operator=(
      const PendingNetworkConfigurationTrackerImplTest&) = delete;

  void SetUp() override {
    test_pref_service_ =
        std::make_unique<sync_preferences::TestingPrefServiceSyncable>();

    PendingNetworkConfigurationTrackerImpl::RegisterProfilePrefs(
        test_pref_service_->registry());
    tracker_ = std::make_unique<PendingNetworkConfigurationTrackerImpl>(
        test_pref_service_.get());
  }

  PendingNetworkConfigurationTrackerImpl* tracker() { return tracker_.get(); }

  const base::Value::Dict* GetPref() const {
    return &test_pref_service_.get()
                ->GetUserPref(kPendingNetworkConfigurationsPref)
                ->GetDict();
  }

  bool DoesPrefContainPendingUpdate(const NetworkIdentifier& id,
                                    const std::string& update_guid) const {
    const base::Value::Dict* dict = GetPref()->FindDict(id.SerializeToString());
    if (!dict) {
      return false;
    }

    const std::string* found_guid = dict->FindString(kChangeGuidKey);
    return found_guid && *found_guid == update_guid;
  }

  void AssertTrackerHasMatchingUpdate(
      const std::string& update_guid,
      const NetworkIdentifier& id,
      int completed_attempts = 0,
      const std::optional<sync_pb::WifiConfigurationSpecifics> specifics =
          std::nullopt) {
    std::optional<PendingNetworkConfigurationUpdate> update =
        tracker()->GetPendingUpdate(update_guid, id);
    ASSERT_TRUE(update);
    ASSERT_EQ(id, update->id());
    ASSERT_EQ(completed_attempts, update->completed_attempts());
    std::string serialized_specifics_wants;
    std::string serialized_specifics_has;
    if (specifics)
      specifics->SerializeToString(&serialized_specifics_wants);
    if (update->specifics())
      update->specifics()->SerializeToString(&serialized_specifics_has);
    ASSERT_EQ(serialized_specifics_wants, serialized_specifics_has);
  }

  const NetworkIdentifier& fred_network_id() const { return fred_network_id_; }

  const NetworkIdentifier& mango_network_id() const {
    return mango_network_id_;
  }

 private:
  std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
      test_pref_service_;
  std::unique_ptr<PendingNetworkConfigurationTrackerImpl> tracker_;

  const NetworkIdentifier fred_network_id_ = GeneratePskNetworkId(kFredSsid);
  const NetworkIdentifier mango_network_id_ = GeneratePskNetworkId(kMangoSsid);
};

TEST_F(PendingNetworkConfigurationTrackerImplTest, TestMarkComplete) {
  std::string change_guid = tracker()->TrackPendingUpdate(
      fred_network_id(), /*specifics=*/std::nullopt);
  AssertTrackerHasMatchingUpdate(change_guid, fred_network_id());
  EXPECT_EQ(1u, GetPref()->size());
  EXPECT_TRUE(DoesPrefContainPendingUpdate(fred_network_id(), change_guid));
  tracker()->MarkComplete(change_guid, fred_network_id());
  EXPECT_FALSE(tracker()->GetPendingUpdate(change_guid, fred_network_id()));
  EXPECT_EQ(0u, GetPref()->size());
}

TEST_F(PendingNetworkConfigurationTrackerImplTest, TestTwoChangesSameNetwork) {
  std::string change_guid =
      tracker()->TrackPendingUpdate(fred_network_id(),
                                    /*specifics=*/std::nullopt);
  tracker()->IncrementCompletedAttempts(change_guid, fred_network_id());
  AssertTrackerHasMatchingUpdate(change_guid, fred_network_id(),
                                 /*completed_attempts=*/1);
  EXPECT_EQ(1u, GetPref()->size());
  EXPECT_EQ(1, tracker()
                   ->GetPendingUpdate(change_guid, fred_network_id())
                   ->completed_attempts());

  std::string second_change_guid =
      tracker()->TrackPendingUpdate(fred_network_id(),
                                    /*specifics=*/std::nullopt);
  EXPECT_FALSE(tracker()->GetPendingUpdate(change_guid, fred_network_id()));
  AssertTrackerHasMatchingUpdate(second_change_guid, fred_network_id());
  EXPECT_EQ(0, tracker()
                   ->GetPendingUpdate(second_change_guid, fred_network_id())
                   ->completed_attempts());
  EXPECT_EQ(1u, GetPref()->size());
}

TEST_F(PendingNetworkConfigurationTrackerImplTest,
       TestTwoChangesDifferentNetworks) {
  std::string change_guid =
      tracker()->TrackPendingUpdate(fred_network_id(),
                                    /*specifics=*/std::nullopt);
  AssertTrackerHasMatchingUpdate(change_guid, fred_network_id());
  EXPECT_TRUE(DoesPrefContainPendingUpdate(fred_network_id(), change_guid));
  EXPECT_EQ(1u, GetPref()->size());
  std::string second_change_guid =
      tracker()->TrackPendingUpdate(mango_network_id(),
                                    /*specifics=*/std::nullopt);
  AssertTrackerHasMatchingUpdate(change_guid, fred_network_id());
  AssertTrackerHasMatchingUpdate(second_change_guid, mango_network_id());
  EXPECT_TRUE(DoesPrefContainPendingUpdate(fred_network_id(), change_guid));
  EXPECT_TRUE(
      DoesPrefContainPendingUpdate(mango_network_id(), second_change_guid));
  EXPECT_EQ(2u, GetPref()->size());
}

TEST_F(PendingNetworkConfigurationTrackerImplTest, TestGetPendingUpdates) {
  std::string change_guid =
      tracker()->TrackPendingUpdate(fred_network_id(),
                                    /*specifics=*/std::nullopt);
  std::string second_change_guid =
      tracker()->TrackPendingUpdate(mango_network_id(),
                                    /*specifics=*/std::nullopt);
  std::vector<PendingNetworkConfigurationUpdate> list =
      tracker()->GetPendingUpdates();
  EXPECT_EQ(2u, list.size());
  EXPECT_EQ(change_guid, list[0].change_guid());
  EXPECT_EQ(fred_network_id(), list[0].id());
  EXPECT_EQ(second_change_guid, list[1].change_guid());
  EXPECT_EQ(mango_network_id(), list[1].id());

  tracker()->MarkComplete(change_guid, fred_network_id());
  list = tracker()->GetPendingUpdates();
  EXPECT_EQ(1u, list.size());
  EXPECT_EQ(second_change_guid, list[0].change_guid());
  EXPECT_EQ(mango_network_id(), list[0].id());
}

TEST_F(PendingNetworkConfigurationTrackerImplTest, TestGetPendingUpdate) {
  sync_pb::WifiConfigurationSpecifics specifics =
      GenerateTestWifiSpecifics(fred_network_id());
  std::string change_guid =
      tracker()->TrackPendingUpdate(fred_network_id(), specifics);

  AssertTrackerHasMatchingUpdate(change_guid, fred_network_id(),
                                 /*completed_attempts=*/0, specifics);
}

TEST_F(PendingNetworkConfigurationTrackerImplTest, TestRetryCounting) {
  std::string change_guid =
      tracker()->TrackPendingUpdate(fred_network_id(),
                                    /*specifics=*/std::nullopt);
  AssertTrackerHasMatchingUpdate(change_guid, fred_network_id());
  EXPECT_EQ(1u, GetPref()->size());
  EXPECT_EQ(0, tracker()
                   ->GetPendingUpdate(change_guid, fred_network_id())
                   ->completed_attempts());
  tracker()->IncrementCompletedAttempts(change_guid, fred_network_id());
  tracker()->IncrementCompletedAttempts(change_guid, fred_network_id());
  tracker()->IncrementCompletedAttempts(change_guid, fred_network_id());
  EXPECT_EQ(3, tracker()
                   ->GetPendingUpdate(change_guid, fred_network_id())
                   ->completed_attempts());
  tracker()->IncrementCompletedAttempts(change_guid, fred_network_id());
  tracker()->IncrementCompletedAttempts(change_guid, fred_network_id());
  EXPECT_EQ(5, tracker()
                   ->GetPendingUpdate(change_guid, fred_network_id())
                   ->completed_attempts());
}

}  // namespace ash::sync_wifi