1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chromeos/services/secure_channel/public/cpp/client/client_channel_impl.h"
6 
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/memory/scoped_refptr.h"
11 #include "base/no_destructor.h"
12 #include "base/optional.h"
13 #include "base/run_loop.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/test/null_task_runner.h"
16 #include "base/test/task_environment.h"
17 #include "base/test/test_simple_task_runner.h"
18 #include "chromeos/components/multidevice/remote_device_test_util.h"
19 #include "chromeos/services/secure_channel/fake_channel.h"
20 #include "chromeos/services/secure_channel/fake_secure_channel.h"
21 #include "chromeos/services/secure_channel/public/cpp/client/client_channel_impl.h"
22 #include "chromeos/services/secure_channel/public/cpp/client/connection_attempt.h"
23 #include "chromeos/services/secure_channel/public/cpp/client/connection_attempt_impl.h"
24 #include "chromeos/services/secure_channel/public/cpp/client/fake_client_channel_observer.h"
25 #include "chromeos/services/secure_channel/public/cpp/client/fake_connection_attempt.h"
26 #include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h"
27 #include "chromeos/services/secure_channel/secure_channel_impl.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 
30 namespace chromeos {
31 
32 namespace secure_channel {
33 
34 class SecureChannelClientChannelImplTest : public testing::Test {
35  protected:
36   SecureChannelClientChannelImplTest() = default;
37 
38   // testing::Test:
SetUp()39   void SetUp() override {
40     fake_channel_ = std::make_unique<FakeChannel>();
41 
42     client_channel_ = ClientChannelImpl::Factory::Create(
43         fake_channel_->GenerateRemote(),
44         message_receiver_remote_.BindNewPipeAndPassReceiver());
45 
46     fake_observer_ = std::make_unique<FakeClientChannelObserver>();
47     client_channel_->AddObserver(fake_observer_.get());
48   }
49 
TearDown()50   void TearDown() override {
51     client_channel_->RemoveObserver(fake_observer_.get());
52   }
53 
CallGetConnectionMetadata()54   mojom::ConnectionMetadataPtr CallGetConnectionMetadata() {
55     EXPECT_FALSE(connection_metadata_);
56 
57     base::RunLoop run_loop;
58     EXPECT_TRUE(client_channel_->GetConnectionMetadata(base::BindOnce(
59         &SecureChannelClientChannelImplTest::OnGetConnectionMetadata,
60         base::Unretained(this), run_loop.QuitClosure())));
61     run_loop.Run();
62 
63     return std::move(connection_metadata_);
64   }
65 
CallSendMessage(const std::string & message)66   int CallSendMessage(const std::string& message) {
67     static int message_counter = 0;
68     int counter_for_this_message = message_counter++;
69     bool success = client_channel_->SendMessage(
70         message,
71         base::BindOnce(&SecureChannelClientChannelImplTest::OnMessageSent,
72                        base::Unretained(this), counter_for_this_message));
73     EXPECT_TRUE(success);
74     SendPendingMojoMessages();
75     return counter_for_this_message;
76   }
77 
CallSendMessageCallback(base::OnceClosure callback)78   void CallSendMessageCallback(base::OnceClosure callback) {
79     base::RunLoop run_loop;
80     message_sent_callback_ = run_loop.QuitClosure();
81     std::move(callback).Run();
82     run_loop.Run();
83   }
84 
VerifyChannelDisconnected()85   void VerifyChannelDisconnected() {
86     EXPECT_TRUE(client_channel_->is_disconnected());
87     EXPECT_TRUE(fake_observer_->is_disconnected());
88 
89     // Ensure that these methods do not work once the ClientChannel is
90     // disconnected.
91     EXPECT_FALSE(client_channel_->GetConnectionMetadata(base::NullCallback()));
92     EXPECT_FALSE(client_channel_->SendMessage("message", base::NullCallback()));
93   }
94 
SendPendingMojoMessages()95   void SendPendingMojoMessages() {
96     static_cast<ClientChannelImpl*>(client_channel_.get())->FlushForTesting();
97   }
98 
99   base::test::TaskEnvironment task_environment_;
100 
101   std::unique_ptr<FakeChannel> fake_channel_;
102   mojo::Remote<mojom::MessageReceiver> message_receiver_remote_;
103   std::unique_ptr<FakeClientChannelObserver> fake_observer_;
104 
105   mojom::ConnectionMetadataPtr connection_metadata_;
106   base::OnceClosure message_sent_callback_;
107   std::set<int> message_counters_received_;
108 
109   std::unique_ptr<ClientChannel> client_channel_;
110 
111  private:
OnGetConnectionMetadata(base::OnceClosure callback,mojom::ConnectionMetadataPtr connection_metadata)112   void OnGetConnectionMetadata(
113       base::OnceClosure callback,
114       mojom::ConnectionMetadataPtr connection_metadata) {
115     connection_metadata_ = std::move(connection_metadata);
116     std::move(callback).Run();
117   }
118 
OnMessageSent(int message_counter)119   void OnMessageSent(int message_counter) {
120     message_counters_received_.insert(message_counter);
121     std::move(message_sent_callback_).Run();
122   }
123 
124   DISALLOW_COPY_AND_ASSIGN(SecureChannelClientChannelImplTest);
125 };
126 
TEST_F(SecureChannelClientChannelImplTest,TestGetConnectionMetadata)127 TEST_F(SecureChannelClientChannelImplTest, TestGetConnectionMetadata) {
128   std::vector<mojom::ConnectionCreationDetail> creation_details{
129       mojom::ConnectionCreationDetail::
130           REMOTE_DEVICE_USED_BACKGROUND_BLE_ADVERTISING};
131 
132   mojom::ConnectionMetadataPtr metadata = mojom::ConnectionMetadata::New(
133       creation_details,
134       mojom::BluetoothConnectionMetadata::New(-24 /* current_rssi */),
135       "channel_binding_data");
136   fake_channel_->set_connection_metadata_for_next_call(std::move(metadata));
137 
138   metadata = CallGetConnectionMetadata();
139   EXPECT_EQ(creation_details, metadata->creation_details);
140   EXPECT_EQ(-24, metadata->bluetooth_connection_metadata->current_rssi);
141 }
142 
TEST_F(SecureChannelClientChannelImplTest,TestSendMessage)143 TEST_F(SecureChannelClientChannelImplTest, TestSendMessage) {
144   int message_1_counter = CallSendMessage("payload1");
145   int message_2_counter = CallSendMessage("payload2");
146 
147   std::vector<std::pair<std::string, mojom::Channel::SendMessageCallback>>&
148       sent_messages = fake_channel_->sent_messages();
149 
150   EXPECT_EQ(2u, sent_messages.size());
151   EXPECT_EQ("payload1", sent_messages[0].first);
152   EXPECT_EQ("payload2", sent_messages[1].first);
153 
154   CallSendMessageCallback(std::move(sent_messages[0].second));
155   CallSendMessageCallback(std::move(sent_messages[1].second));
156 
157   EXPECT_TRUE(base::Contains(message_counters_received_, message_1_counter));
158   EXPECT_TRUE(base::Contains(message_counters_received_, message_2_counter));
159 }
160 
TEST_F(SecureChannelClientChannelImplTest,TestReceiveMessage)161 TEST_F(SecureChannelClientChannelImplTest, TestReceiveMessage) {
162   message_receiver_remote_->OnMessageReceived("payload");
163   message_receiver_remote_.FlushForTesting();
164 
165   EXPECT_EQ(1u, fake_observer_->received_messages().size());
166   EXPECT_EQ("payload", fake_observer_->received_messages()[0]);
167 }
168 
TEST_F(SecureChannelClientChannelImplTest,TestDisconnectRemotely)169 TEST_F(SecureChannelClientChannelImplTest, TestDisconnectRemotely) {
170   fake_channel_->DisconnectGeneratedRemote();
171 
172   SendPendingMojoMessages();
173 
174   VerifyChannelDisconnected();
175 }
176 
177 }  // namespace secure_channel
178 
179 }  // namespace chromeos
180