1 // Copyright 2015 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.
5 #include "components/proximity_auth/remote_device_life_cycle_impl.h"
7 #include "base/callback.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/test/test_simple_task_runner.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "components/proximity_auth/authenticator.h"
12 #include "components/proximity_auth/client.h"
13 #include "components/proximity_auth/connection.h"
14 #include "components/proximity_auth/connection_finder.h"
15 #include "components/proximity_auth/secure_context.h"
16 #include "components/proximity_auth/wire_message.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
22 using testing::NiceMock
;
23 using testing::Return
;
24 using testing::StrictMock
;
26 namespace proximity_auth
{
30 // Attributes of the remote device under test.
31 const char kRemoteDeviceName
[] = "remote device";
32 const char kRemoteDevicePublicKey
[] = "public key";
33 const char kRemoteDeviceBluetoothAddress
[] = "AA:BB:CC:DD:EE:FF";
34 const char kRemoteDevicePSK
[] = "remote device psk";
36 class StubConnection
: public Connection
{
38 StubConnection() : Connection(RemoteDevice()) {
39 SetStatus(Connection::Status::CONNECTED
);
42 ~StubConnection() override
{}
45 void Connect() override
{ NOTREACHED(); }
47 void Disconnect() override
{ SetStatus(Connection::Status::DISCONNECTED
); }
49 void SendMessageImpl(scoped_ptr
<WireMessage
> message
) override
{
54 DISALLOW_COPY_AND_ASSIGN(StubConnection
);
57 class StubSecureContext
: public SecureContext
{
59 StubSecureContext() {}
60 ~StubSecureContext() override
{}
62 void Decode(const std::string
& encoded_message
,
63 const MessageCallback
& callback
) override
{
67 void Encode(const std::string
& message
,
68 const MessageCallback
& callback
) override
{
72 ProtocolVersion
GetProtocolVersion() const override
{
74 return SecureContext::PROTOCOL_VERSION_THREE_ONE
;
78 DISALLOW_COPY_AND_ASSIGN(StubSecureContext
);
81 class FakeConnectionFinder
: public ConnectionFinder
{
83 FakeConnectionFinder() : connection_(nullptr) {}
84 ~FakeConnectionFinder() override
{}
86 void OnConnectionFound() {
87 ASSERT_FALSE(connection_callback_
.is_null());
88 scoped_ptr
<StubConnection
> scoped_connection_(new StubConnection());
89 connection_
= scoped_connection_
.get();
90 connection_callback_
.Run(scoped_connection_
.Pass());
93 StubConnection
* connection() { return connection_
; }
97 void Find(const ConnectionCallback
& connection_callback
) override
{
98 ASSERT_TRUE(connection_callback_
.is_null());
99 connection_callback_
= connection_callback
;
102 StubConnection
* connection_
;
104 ConnectionCallback connection_callback_
;
106 DISALLOW_COPY_AND_ASSIGN(FakeConnectionFinder
);
109 class FakeAuthenticator
: public Authenticator
{
111 FakeAuthenticator() {}
112 ~FakeAuthenticator() override
{}
114 void OnAuthenticationResult(Authenticator::Result result
) {
115 ASSERT_FALSE(callback_
.is_null());
116 scoped_ptr
<SecureContext
> secure_context
;
117 if (result
== Authenticator::Result::SUCCESS
)
118 secure_context
.reset(new StubSecureContext());
119 callback_
.Run(result
, secure_context
.Pass());
124 void Authenticate(const AuthenticationCallback
& callback
) override
{
125 ASSERT_TRUE(callback_
.is_null());
126 callback_
= callback
;
129 AuthenticationCallback callback_
;
131 DISALLOW_COPY_AND_ASSIGN(FakeAuthenticator
);
134 // Subclass of RemoteDeviceLifeCycleImpl to make it testable.
135 class TestableRemoteDeviceLifeCycleImpl
: public RemoteDeviceLifeCycleImpl
{
137 TestableRemoteDeviceLifeCycleImpl()
138 : RemoteDeviceLifeCycleImpl(RemoteDevice(kRemoteDeviceName
,
139 kRemoteDevicePublicKey
,
140 kRemoteDeviceBluetoothAddress
,
144 ~TestableRemoteDeviceLifeCycleImpl() override
{}
146 FakeConnectionFinder
* connection_finder() { return connection_finder_
; }
147 FakeAuthenticator
* authenticator() { return authenticator_
; }
150 scoped_ptr
<ConnectionFinder
> CreateConnectionFinder() override
{
151 scoped_ptr
<FakeConnectionFinder
> scoped_connection_finder(
152 new FakeConnectionFinder());
153 connection_finder_
= scoped_connection_finder
.get();
154 return scoped_connection_finder
.Pass();
157 scoped_ptr
<Authenticator
> CreateAuthenticator() override
{
158 scoped_ptr
<FakeAuthenticator
> scoped_authenticator(new FakeAuthenticator());
159 authenticator_
= scoped_authenticator
.get();
160 return scoped_authenticator
.Pass();
163 FakeConnectionFinder
* connection_finder_
;
164 FakeAuthenticator
* authenticator_
;
166 DISALLOW_COPY_AND_ASSIGN(TestableRemoteDeviceLifeCycleImpl
);
171 class ProximityAuthRemoteDeviceLifeCycleImplTest
172 : public testing::Test
,
173 public RemoteDeviceLifeCycle::Observer
{
175 ProximityAuthRemoteDeviceLifeCycleImplTest()
176 : task_runner_(new base::TestSimpleTaskRunner()),
177 thread_task_runner_handle_(task_runner_
) {}
179 ~ProximityAuthRemoteDeviceLifeCycleImplTest() override
{
180 life_cycle_
.RemoveObserver(this);
183 void StartLifeCycle() {
184 EXPECT_EQ(RemoteDeviceLifeCycle::State::STOPPED
, life_cycle_
.GetState());
185 life_cycle_
.AddObserver(this);
187 EXPECT_CALL(*this, OnLifeCycleStateChanged(
188 RemoteDeviceLifeCycle::State::STOPPED
,
189 RemoteDeviceLifeCycle::State::FINDING_CONNECTION
));
191 task_runner_
->RunUntilIdle();
192 Mock::VerifyAndClearExpectations(this);
194 EXPECT_EQ(RemoteDeviceLifeCycle::State::FINDING_CONNECTION
,
195 life_cycle_
.GetState());
198 StubConnection
* OnConnectionFound() {
199 EXPECT_EQ(RemoteDeviceLifeCycle::State::FINDING_CONNECTION
,
200 life_cycle_
.GetState());
202 EXPECT_CALL(*this, OnLifeCycleStateChanged(
203 RemoteDeviceLifeCycle::State::FINDING_CONNECTION
,
204 RemoteDeviceLifeCycle::State::AUTHENTICATING
));
205 life_cycle_
.connection_finder()->OnConnectionFound();
206 task_runner_
->RunUntilIdle();
207 Mock::VerifyAndClearExpectations(this);
209 EXPECT_EQ(RemoteDeviceLifeCycle::State::AUTHENTICATING
,
210 life_cycle_
.GetState());
211 return life_cycle_
.connection_finder()->connection();
214 void Authenticate(Authenticator::Result result
) {
215 EXPECT_EQ(RemoteDeviceLifeCycle::State::AUTHENTICATING
,
216 life_cycle_
.GetState());
218 RemoteDeviceLifeCycle::State expected_state
=
219 (result
== Authenticator::Result::SUCCESS
)
220 ? RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED
221 : RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED
;
223 EXPECT_CALL(*this, OnLifeCycleStateChanged(
224 RemoteDeviceLifeCycle::State::AUTHENTICATING
,
226 life_cycle_
.authenticator()->OnAuthenticationResult(result
);
228 if (result
== Authenticator::Result::SUCCESS
)
229 task_runner_
->RunUntilIdle();
231 EXPECT_EQ(expected_state
, life_cycle_
.GetState());
232 Mock::VerifyAndClearExpectations(this);
235 MOCK_METHOD2(OnLifeCycleStateChanged
,
236 void(RemoteDeviceLifeCycle::State old_state
,
237 RemoteDeviceLifeCycle::State new_state
));
239 TestableRemoteDeviceLifeCycleImpl life_cycle_
;
240 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
241 base::ThreadTaskRunnerHandle thread_task_runner_handle_
;
244 DISALLOW_COPY_AND_ASSIGN(ProximityAuthRemoteDeviceLifeCycleImplTest
);
247 TEST_F(ProximityAuthRemoteDeviceLifeCycleImplTest
, AuthenticateAndDisconnect
) {
249 for (size_t i
= 0; i
< 3; ++i
) {
250 Connection
* connection
= OnConnectionFound();
251 Authenticate(Authenticator::Result::SUCCESS
);
252 EXPECT_TRUE(life_cycle_
.GetClient());
255 OnLifeCycleStateChanged(
256 RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED
,
257 RemoteDeviceLifeCycle::State::FINDING_CONNECTION
));
258 connection
->Disconnect();
259 Mock::VerifyAndClearExpectations(this);
263 TEST_F(ProximityAuthRemoteDeviceLifeCycleImplTest
, AuthenticationFails
) {
264 // Simulate an authentication failure after connecting to the device.
267 Authenticate(Authenticator::Result::FAILURE
);
268 EXPECT_FALSE(life_cycle_
.GetClient());
270 // After a delay, the life cycle should return to FINDING_CONNECTION.
271 EXPECT_CALL(*this, OnLifeCycleStateChanged(
272 RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED
,
273 RemoteDeviceLifeCycle::State::FINDING_CONNECTION
));
274 task_runner_
->RunUntilIdle();
275 EXPECT_EQ(RemoteDeviceLifeCycle::State::FINDING_CONNECTION
,
276 life_cycle_
.GetState());
278 // Try failing with the DISCONNECTED state instead.
280 Authenticate(Authenticator::Result::DISCONNECTED
);
281 EXPECT_FALSE(life_cycle_
.GetClient());
283 // Check we're back in FINDING_CONNECTION state again.
284 EXPECT_CALL(*this, OnLifeCycleStateChanged(
285 RemoteDeviceLifeCycle::State::AUTHENTICATION_FAILED
,
286 RemoteDeviceLifeCycle::State::FINDING_CONNECTION
));
287 task_runner_
->RunUntilIdle();
288 EXPECT_EQ(RemoteDeviceLifeCycle::State::FINDING_CONNECTION
,
289 life_cycle_
.GetState());
292 TEST_F(ProximityAuthRemoteDeviceLifeCycleImplTest
,
293 AuthenticationFailsThenSucceeds
) {
294 // Authentication fails on first pass.
297 Authenticate(Authenticator::Result::FAILURE
);
298 EXPECT_FALSE(life_cycle_
.GetClient());
299 EXPECT_CALL(*this, OnLifeCycleStateChanged(_
, _
));
300 task_runner_
->RunUntilIdle();
302 // Authentication succeeds on second pass.
303 Connection
* connection
= OnConnectionFound();
304 Authenticate(Authenticator::Result::SUCCESS
);
305 EXPECT_TRUE(life_cycle_
.GetClient());
306 EXPECT_CALL(*this, OnLifeCycleStateChanged(_
, _
));
307 connection
->Disconnect();
310 } // namespace proximity_auth