| // Copyright 2016 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/disconnect_tethering_operation.h" |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/time/time.h" |
| #include "base/timer/mock_timer.h" |
| #include "chromeos/components/multidevice/remote_device_test_util.h" |
| #include "chromeos/components/tether/message_wrapper.h" |
| #include "chromeos/components/tether/proto/tether.pb.h" |
| #include "chromeos/components/tether/test_timer_factory.h" |
| #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h" |
| #include "chromeos/services/secure_channel/public/cpp/client/fake_client_channel.h" |
| #include "chromeos/services/secure_channel/public/cpp/client/fake_connection_attempt.h" |
| #include "chromeos/services/secure_channel/public/cpp/client/fake_secure_channel_client.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace chromeos { |
| |
| namespace tether { |
| |
| namespace { |
| |
| constexpr base::TimeDelta kDisconnectTetheringRequestTime = |
| base::TimeDelta::FromSeconds(3); |
| |
| // Used to verify the DisonnectTetheringOperation notifies the observer when |
| // appropriate. |
| class MockOperationObserver : public DisconnectTetheringOperation::Observer { |
| public: |
| MockOperationObserver() = default; |
| ~MockOperationObserver() = default; |
| |
| MOCK_METHOD2(OnOperationFinished, void(const std::string&, bool)); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MockOperationObserver); |
| }; |
| |
| } // namespace |
| |
| class DisconnectTetheringOperationTest : public testing::Test { |
| protected: |
| DisconnectTetheringOperationTest() |
| : local_device_(multidevice::RemoteDeviceRefBuilder() |
| .SetPublicKey("local device") |
| .Build()), |
| remote_device_(multidevice::CreateRemoteDeviceRefListForTest(1)[0]) {} |
| |
| void SetUp() override { |
| fake_device_sync_client_ = |
| std::make_unique<device_sync::FakeDeviceSyncClient>(); |
| fake_device_sync_client_->set_local_device_metadata(local_device_); |
| fake_secure_channel_client_ = |
| std::make_unique<secure_channel::FakeSecureChannelClient>(); |
| |
| operation_ = ConstructOperation(); |
| operation_->Initialize(); |
| |
| ConnectAuthenticatedChannelForDevice(remote_device_); |
| } |
| |
| std::unique_ptr<DisconnectTetheringOperation> ConstructOperation() { |
| auto connection_attempt = |
| std::make_unique<secure_channel::FakeConnectionAttempt>(); |
| connection_attempt_ = connection_attempt.get(); |
| // remote_device_to_fake_connection_attempt_map_[remote_device_] = |
| // fake_connection_attempt.get(); |
| fake_secure_channel_client_->set_next_listen_connection_attempt( |
| remote_device_, local_device_, std::move(connection_attempt)); |
| |
| auto operation = base::WrapUnique(new DisconnectTetheringOperation( |
| remote_device_, fake_device_sync_client_.get(), |
| fake_secure_channel_client_.get())); |
| operation->AddObserver(&mock_observer_); |
| |
| // Prepare the disconnection timeout timer to be made for the remote device. |
| auto test_timer_factory = std::make_unique<TestTimerFactory>(); |
| test_timer_factory->set_device_id_for_next_timer( |
| remote_device_.GetDeviceId()); |
| operation->SetTimerFactoryForTest(std::move(test_timer_factory)); |
| |
| test_clock_.SetNow(base::Time::UnixEpoch()); |
| operation->SetClockForTest(&test_clock_); |
| |
| return operation; |
| } |
| |
| void ConnectAuthenticatedChannelForDevice( |
| multidevice::RemoteDeviceRef remote_device) { |
| auto fake_client_channel = |
| std::make_unique<secure_channel::FakeClientChannel>(); |
| connection_attempt_->NotifyConnection(std::move(fake_client_channel)); |
| } |
| |
| const multidevice::RemoteDeviceRef local_device_; |
| const multidevice::RemoteDeviceRef remote_device_; |
| |
| secure_channel::FakeConnectionAttempt* connection_attempt_; |
| std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_; |
| std::unique_ptr<secure_channel::FakeSecureChannelClient> |
| fake_secure_channel_client_; |
| |
| base::SimpleTestClock test_clock_; |
| MockOperationObserver mock_observer_; |
| base::HistogramTester histogram_tester_; |
| |
| std::unique_ptr<DisconnectTetheringOperation> operation_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(DisconnectTetheringOperationTest); |
| }; |
| |
| TEST_F(DisconnectTetheringOperationTest, TestSuccess) { |
| // Verify that the Observer is called with success and the correct parameters. |
| EXPECT_CALL(mock_observer_, OnOperationFinished(remote_device_.GetDeviceId(), |
| true /* successful */)); |
| |
| // Advance the clock in order to verify a non-zero request duration is |
| // recorded and verified (below). |
| test_clock_.Advance(kDisconnectTetheringRequestTime); |
| |
| // Execute the operation. |
| operation_->OnMessageSent(0 /* sequence_number */); |
| |
| // Verify the request duration metric is recorded. |
| histogram_tester_.ExpectTimeBucketCount( |
| "InstantTethering.Performance.DisconnectTetheringRequestDuration", |
| kDisconnectTetheringRequestTime, 1); |
| } |
| |
| TEST_F(DisconnectTetheringOperationTest, TestFailure) { |
| // Verify that the observer is called with failure and the correct parameters. |
| EXPECT_CALL(mock_observer_, OnOperationFinished(remote_device_.GetDeviceId(), |
| false /* successful */)); |
| |
| // Finalize the operation; no message has been sent so this represents a |
| // failure case. |
| operation_->UnregisterDevice(remote_device_); |
| |
| histogram_tester_.ExpectTotalCount( |
| "InstantTethering.Performance.DisconnectTetheringRequestDuration", 0); |
| } |
| |
| // Tests that the DisonnectTetheringRequest message is sent to the remote device |
| // once the communication channel is connected and authenticated. |
| TEST_F(DisconnectTetheringOperationTest, |
| DisconnectRequestSentOnceAuthenticated) { |
| std::unique_ptr<DisconnectTetheringOperation> operation = |
| ConstructOperation(); |
| operation->Initialize(); |
| |
| // Create the client channel for the remote device. |
| auto fake_client_channel = |
| std::make_unique<secure_channel::FakeClientChannel>(); |
| |
| // No requests as a result of creating the client channel. |
| auto& sent_messages = fake_client_channel->sent_messages(); |
| EXPECT_EQ(0u, sent_messages.size()); |
| |
| // Connect and authenticate the client channel. |
| connection_attempt_->NotifyConnection(std::move(fake_client_channel)); |
| |
| // Verify the DisconnectTetheringRequest message is sent. |
| auto message_wrapper = |
| std::make_unique<MessageWrapper>(DisconnectTetheringRequest()); |
| std::string expected_payload = message_wrapper->ToRawMessage(); |
| EXPECT_EQ(1u, sent_messages.size()); |
| EXPECT_EQ(expected_payload, sent_messages[0].first); |
| } |
| |
| } // namespace tether |
| |
| } // namespace chromeos |