| // Copyright 2020 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/phonehub/connection_scheduler_impl.h" |
| |
| #include <memory> |
| |
| #include "base/macros.h" |
| #include "base/test/task_environment.h" |
| #include "base/time/time.h" |
| #include "chromeos/components/phonehub/connection_manager.h" |
| #include "chromeos/components/phonehub/fake_connection_manager.h" |
| #include "chromeos/components/phonehub/fake_feature_status_provider.h" |
| #include "chromeos/components/phonehub/feature_status.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace chromeos { |
| namespace phonehub { |
| |
| class ConnectionSchedulerImplTest : public testing::Test { |
| protected: |
| ConnectionSchedulerImplTest() = default; |
| ConnectionSchedulerImplTest(const ConnectionSchedulerImplTest&) = delete; |
| ConnectionSchedulerImplTest& operator=(const ConnectionSchedulerImplTest&) = |
| delete; |
| ~ConnectionSchedulerImplTest() override = default; |
| |
| void SetUp() override { |
| fake_connection_manager_ = std::make_unique<FakeConnectionManager>(); |
| fake_feature_status_provider_ = |
| std::make_unique<FakeFeatureStatusProvider>(); |
| } |
| |
| void CreateConnectionScheduler() { |
| connection_scheduler_ = std::make_unique<ConnectionSchedulerImpl>( |
| fake_connection_manager_.get(), fake_feature_status_provider_.get()); |
| } |
| |
| base::TimeDelta GetCurrentBackoffDelay() { |
| return connection_scheduler_->GetCurrentBackoffDelayTimeForTesting(); |
| } |
| |
| int GetBackoffFailureCount() { |
| return connection_scheduler_->GetBackoffFailureCountForTesting(); |
| } |
| |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| std::unique_ptr<FakeConnectionManager> fake_connection_manager_; |
| std::unique_ptr<FakeFeatureStatusProvider> fake_feature_status_provider_; |
| std::unique_ptr<ConnectionSchedulerImpl> connection_scheduler_; |
| }; |
| |
| TEST_F(ConnectionSchedulerImplTest, SuccesssfullyAttemptConnection) { |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| CreateConnectionScheduler(); |
| |
| connection_scheduler_->ScheduleConnectionNow(); |
| // Verify that the ConnectionManager has attempted to connect. |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| |
| // Simulate state changes with AttemptConnection(). |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledAndConnecting); |
| fake_feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected); |
| // Verify only 1 call to AttemptConnection() was ever made. |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| // Verify that we did not attempt a backoff retry. |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| } |
| |
| TEST_F(ConnectionSchedulerImplTest, FeatureDisabledDoesNotEstablishConnection) { |
| fake_feature_status_provider_->SetStatus(FeatureStatus::kDisabled); |
| CreateConnectionScheduler(); |
| |
| connection_scheduler_->ScheduleConnectionNow(); |
| // Verify that the ConnectionManager did not attempt connection. |
| EXPECT_EQ(0u, fake_connection_manager_->num_attempt_connection_calls()); |
| // Verify that we did not attempt a backoff retry. |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| } |
| |
| TEST_F(ConnectionSchedulerImplTest, BackoffRetryWithUpdatedConnection) { |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| CreateConnectionScheduler(); |
| |
| connection_scheduler_->ScheduleConnectionNow(); |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| // Simulate state changes with AttemptConnection(). |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledAndConnecting); |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| EXPECT_EQ(1, GetBackoffFailureCount()); |
| |
| // Move forward time to the next backoff retry with disconnected status. |
| task_environment_.FastForwardBy(GetCurrentBackoffDelay()); |
| EXPECT_EQ(2u, fake_connection_manager_->num_attempt_connection_calls()); |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledAndConnecting); |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| EXPECT_EQ(2, GetBackoffFailureCount()); |
| |
| // Move forward time to the next backoff retry, this time with connected |
| // status. |
| task_environment_.FastForwardBy(GetCurrentBackoffDelay()); |
| EXPECT_EQ(3u, fake_connection_manager_->num_attempt_connection_calls()); |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledAndConnecting); |
| fake_feature_status_provider_->SetStatus(FeatureStatus::kEnabledAndConnected); |
| // Expected no more backoff failures since connection is now established. |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| |
| // Fast forward time and confirm no other retries have been made. |
| task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(100)); |
| EXPECT_EQ(3u, fake_connection_manager_->num_attempt_connection_calls()); |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| EXPECT_EQ(FeatureStatus::kEnabledAndConnected, |
| fake_feature_status_provider_->GetStatus()); |
| } |
| |
| TEST_F(ConnectionSchedulerImplTest, BackoffRetryWithUpdatedFeatures) { |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| CreateConnectionScheduler(); |
| |
| connection_scheduler_->ScheduleConnectionNow(); |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| // Simulate state changes with AttemptConnection(). |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledAndConnecting); |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| EXPECT_EQ(1, GetBackoffFailureCount()); |
| |
| // Simulate the feature status switched to disabled. |
| fake_feature_status_provider_->SetStatus(FeatureStatus::kDisabled); |
| // Expect the backoff to reset and never attempt to kickoff another |
| // connection. |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| // Expect that connection has been disconnected. |
| EXPECT_EQ(1u, fake_connection_manager_->num_disconnect_calls()); |
| |
| // Fast forward time and confirm no other retries have been made. |
| task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(100)); |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| |
| // Simulate the feature re-enabled and the connection kickoff should start. |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| // The next ScheduleConnection() was not caused by a previous failure, expect |
| // backoff failure count to not increase. |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| |
| // Move forward in time and confirm backoff attempted another retry. |
| task_environment_.FastForwardBy(GetCurrentBackoffDelay()); |
| EXPECT_EQ(2u, fake_connection_manager_->num_attempt_connection_calls()); |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledAndConnecting); |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| // The next ScheduleConnection() was caused by a previous failure, expect 1 |
| // failure count. |
| EXPECT_EQ(1, GetBackoffFailureCount()); |
| } |
| |
| TEST_F(ConnectionSchedulerImplTest, ScheduleConnectionSuspended) { |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| CreateConnectionScheduler(); |
| |
| // Simulate screen locked and expect no scheduled connections. |
| fake_feature_status_provider_->SetStatus(FeatureStatus::kLockOrSuspended); |
| // Expect no scheduled connections on screen lock. |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| EXPECT_EQ(0u, fake_connection_manager_->num_attempt_connection_calls()); |
| EXPECT_EQ(1u, fake_connection_manager_->num_disconnect_calls()); |
| |
| // Simulate screen unlocked and expect a scheduled connection. |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| } |
| |
| TEST_F(ConnectionSchedulerImplTest, HostsNotEligible) { |
| // Simulate no eligible hosts available. Expect no scheduled connections. |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kNotEligibleForFeature); |
| CreateConnectionScheduler(); |
| |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| EXPECT_EQ(0u, fake_connection_manager_->num_attempt_connection_calls()); |
| |
| fake_feature_status_provider_->SetStatus( |
| FeatureStatus::kEnabledButDisconnected); |
| // Flip to have eligble hosts available. Expect a scheduled connection. |
| EXPECT_EQ(0, GetBackoffFailureCount()); |
| EXPECT_EQ(1u, fake_connection_manager_->num_attempt_connection_calls()); |
| } |
| |
| } // namespace phonehub |
| } // namespace chromeos |