blob: 43f44d98f4dd4696d3a580fc0392e8ea33821ed7 [file] [log] [blame]
// Copyright 2017 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 "chromeos/components/tether/gms_core_notifications_state_tracker_impl.h"
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "components/cryptauth/remote_device_ref.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace tether {
namespace {
const int kNumTestDevices = 3;
// Creates test devices which have the naming scheme of "testDevice0",
// "testDevice1", etc.
cryptauth::RemoteDeviceRefList CreateTestDevices() {
cryptauth::RemoteDeviceRefList test_devices =
cryptauth::CreateRemoteDeviceRefListForTest(kNumTestDevices);
for (size_t i = 0; i < kNumTestDevices; ++i) {
std::stringstream ss;
ss << "testDevice" << i;
test_devices.push_back(cryptauth::RemoteDeviceRefBuilder()
.SetName(std::string(ss.str()))
.Build());
}
return test_devices;
}
class TestObserver final : public GmsCoreNotificationsStateTracker::Observer {
public:
explicit TestObserver(GmsCoreNotificationsStateTrackerImpl* tracker)
: tracker_(tracker) {}
~TestObserver() = default;
uint32_t change_count() const { return change_count_; }
const std::vector<std::string>& names_from_last_update() {
return names_from_last_update_;
}
// GmsCoreNotificationsStateTracker::Observer:
void OnGmsCoreNotificationStateChanged() override {
names_from_last_update_ =
tracker_->GetGmsCoreNotificationsDisabledDeviceNames();
++change_count_;
}
private:
GmsCoreNotificationsStateTrackerImpl* tracker_;
uint32_t change_count_ = 0;
std::vector<std::string> names_from_last_update_;
DISALLOW_COPY_AND_ASSIGN(TestObserver);
};
} // namespace
class GmsCoreNotificationsStateTrackerImplTest : public testing::Test {
protected:
GmsCoreNotificationsStateTrackerImplTest()
: test_devices_(CreateTestDevices()) {}
void SetUp() override {
devices_to_send_.clear();
scanned_device_infos_.clear();
tracker_ = std::make_unique<GmsCoreNotificationsStateTrackerImpl>();
observer_ = std::make_unique<TestObserver>(tracker_.get());
tracker_->AddObserver(observer_.get());
}
void VerifyExpectedNames(const std::vector<std::string> expected_names,
size_t expected_change_count) {
EXPECT_EQ(expected_names, observer_->names_from_last_update());
EXPECT_EQ(expected_change_count, observer_->change_count());
}
void ReceiveTetherAvailabilityResponse(bool is_final_scan_result) {
tracker_->OnTetherAvailabilityResponse(
scanned_device_infos_, devices_to_send_, is_final_scan_result);
}
void AddScannedRemoteDevice(cryptauth::RemoteDeviceRef remote_device) {
scanned_device_infos_.emplace_back(remote_device, DeviceStatus(),
false /* setup_required */);
}
const cryptauth::RemoteDeviceRefList test_devices_;
std::vector<HostScannerOperation::ScannedDeviceInfo> scanned_device_infos_;
cryptauth::RemoteDeviceRefList devices_to_send_;
std::unique_ptr<GmsCoreNotificationsStateTrackerImpl> tracker_;
std::unique_ptr<TestObserver> observer_;
private:
DISALLOW_COPY_AND_ASSIGN(GmsCoreNotificationsStateTrackerImplTest);
};
TEST_F(GmsCoreNotificationsStateTrackerImplTest, TestTracking) {
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(std::vector<std::string>(),
0 /* expected_change_count */);
// Add two devices and verify that they are now tracked.
devices_to_send_.push_back(test_devices_[0]);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames({test_devices_[0].name()} /* expected_names */,
1 /* expected_change_count */);
devices_to_send_.push_back(test_devices_[1]);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), test_devices_[1].name()} /* expected_names */,
2 /* expected_change_count */);
// Receive another response with the same list; this should not result in an
// additional "state changed" event.
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), test_devices_[1].name()} /* expected_names */,
2 /* expected_change_count */);
// End the scan session.
ReceiveTetherAvailabilityResponse(true /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), test_devices_[1].name()} /* expected_names */,
2 /* expected_change_count */);
// Start a new session; since the previous session contains device 0 and
// device 1, these devices should remain at least until the scan session ends.
devices_to_send_.clear();
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), test_devices_[1].name()} /* expected_names */,
2 /* expected_change_count */);
// Add two devices (one new and one from a previous session).
devices_to_send_.push_back(test_devices_[0]);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), test_devices_[1].name()} /* expected_names */,
2 /* expected_change_count */);
devices_to_send_.push_back(test_devices_[2]);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames({test_devices_[0].name(), test_devices_[1].name(),
test_devices_[2].name()} /* expected_names */,
3 /* expected_change_count */);
// End the scan session; since "session2" was not present in this session, it
// should be removed.
ReceiveTetherAvailabilityResponse(true /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), test_devices_[2].name()} /* expected_names */,
4 /* expected_change_count */);
// Start another session (devices 0 and 2 should still be present).
devices_to_send_.clear();
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), test_devices_[2].name()} /* expected_names */,
4 /* expected_change_count */);
// Add device 0 as a potential tether host. This should cause it to be removed
// from the list without notifications, even though the scan session has not
// yet ended.
AddScannedRemoteDevice(test_devices_[0]);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames({test_devices_[2].name()} /* expected_names */,
5 /* expected_change_count */);
// Keep device 2 in the list; since it already existed from the previous scan
// session, no new event should have occurred.
devices_to_send_.push_back(test_devices_[2]);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames({test_devices_[2].name()} /* expected_names */,
5 /* expected_change_count */);
// End the scan session.
ReceiveTetherAvailabilityResponse(true /* is_final_scan_result */);
VerifyExpectedNames({test_devices_[2].name()} /* expected_names */,
5 /* expected_change_count */);
// Now, destroy |tracker_|; this should result in one more change event.
tracker_.reset();
VerifyExpectedNames({} /* expected_names */, 6 /* expected_change_count */);
}
TEST_F(GmsCoreNotificationsStateTrackerImplTest, TestTracking_SameName) {
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(std::vector<std::string>(),
0 /* expected_change_count */);
// Add device 0.
devices_to_send_.push_back(test_devices_[0]);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames({test_devices_[0].name()} /* expected_names */,
1 /* expected_change_count */);
// Make a copy of device 1, and change its name to be the same as device 0's
// while keeping its public key (and, thus, ID) the same.
cryptauth::RemoteDeviceRef device_1_copy =
cryptauth::RemoteDeviceRefBuilder()
.SetPublicKey(test_devices_[1].public_key())
.SetName(test_devices_[0].name())
.Build();
// Add the updated device 1. Both names should be sent in the event, even
// though they are the same name.
devices_to_send_.push_back(device_1_copy);
ReceiveTetherAvailabilityResponse(false /* is_final_scan_result */);
VerifyExpectedNames(
{test_devices_[0].name(), device_1_copy.name()} /* expected_names */,
2 /* expected_change_count */);
tracker_.reset();
VerifyExpectedNames({} /* expected_names */, 3 /* expected_change_count */);
}
} // namespace tether
} // namespace chromeos