1 // Copyright 2014 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/copresence/rpc/rpc_handler.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/message_loop/message_loop.h"
15 #include "components/audio_modem/public/modem.h"
16 #include "components/audio_modem/test/stub_whispernet_client.h"
17 #include "components/copresence/copresence_state_impl.h"
18 #include "components/copresence/handlers/directive_handler.h"
19 #include "components/copresence/proto/data.pb.h"
20 #include "components/copresence/proto/enums.pb.h"
21 #include "components/copresence/proto/rpcs.pb.h"
22 #include "components/copresence/test/fake_directive_handler.h"
23 #include "net/http/http_status_code.h"
24 #include "testing/gmock/include/gmock/gmock.h"
26 using google::protobuf::MessageLite
;
27 using google::protobuf::RepeatedPtrField
;
29 using testing::ElementsAre
;
30 using testing::Property
;
31 using testing::SizeIs
;
33 using audio_modem::AudioToken
;
34 using audio_modem::WhispernetClient
;
36 namespace copresence
{
40 const char kChromeVersion
[] = "Chrome Version String";
43 const RepeatedPtrField
<SubscribedMessage
>& /* messages */) {}
47 class RpcHandlerTest
: public testing::Test
, public CopresenceDelegate
{
50 : whispernet_client_(new audio_modem::StubWhispernetClient
),
51 // TODO(ckehoe): Use a FakeCopresenceState here
52 // and test that it gets called correctly.
53 state_(new CopresenceStateImpl
),
58 base::Bind(&IgnoreMessages
),
59 base::Bind(&RpcHandlerTest::CaptureHttpPost
,
60 base::Unretained(this))),
63 // CopresenceDelegate implementation
65 void HandleMessages(const std::string
& /* app_id */,
66 const std::string
& subscription_id
,
67 const std::vector
<Message
>& messages
) override
{
71 void HandleStatusUpdate(CopresenceStatus
/* status */) override
{
75 net::URLRequestContextGetter
* GetRequestContext() const override
{
79 const std::string
GetPlatformVersionString() const override
{
80 return kChromeVersion
;
83 const std::string
GetAPIKey(const std::string
& app_id
) const override
{
84 return app_id
+ " API Key";
87 WhispernetClient
* GetWhispernetClient() override
{
88 return whispernet_client_
.get();
91 // TODO(ckehoe): Add GCM tests.
92 gcm::GCMDriver
* GetGCMDriver() override
{
96 const std::string
GetDeviceId(bool authenticated
) override
{
97 return device_id_by_auth_state_
[authenticated
];
100 void SaveDeviceId(bool authenticated
, const std::string
& device_id
) override
{
101 device_id_by_auth_state_
[authenticated
] = device_id
;
106 // Send test input to RpcHandler
108 void RegisterDevice(bool authenticated
) {
109 rpc_handler_
.RegisterDevice(authenticated
);
112 void SendRegisterResponse(bool authenticated
,
113 const std::string
& device_id
) {
114 RegisterDeviceResponse response
;
115 response
.set_registered_device_id(device_id
);
116 response
.mutable_header()->mutable_status()->set_code(OK
);
118 std::string serialized_response
;
119 response
.SerializeToString(&serialized_response
);
120 rpc_handler_
.RegisterResponseHandler(
121 authenticated
, false, nullptr, net::HTTP_OK
, serialized_response
);
124 void SendReport(scoped_ptr
<ReportRequest
> request
,
125 const std::string
& app_id
,
126 const std::string
& auth_token
) {
127 rpc_handler_
.SendReportRequest(
128 request
.Pass(), app_id
, auth_token
, StatusCallback());
131 void SendReportResponse(int status_code
,
132 scoped_ptr
<ReportResponse
> response
) {
133 response
->mutable_header()->mutable_status()->set_code(OK
);
135 std::string serialized_response
;
136 response
->SerializeToString(&serialized_response
);
137 rpc_handler_
.ReportResponseHandler(
138 base::Bind(&RpcHandlerTest::CaptureStatus
, base::Unretained(this)),
141 serialized_response
);
144 // Read and modify RpcHandler state
146 void SetAuthToken(const std::string
& auth_token
) {
147 rpc_handler_
.auth_token_
= auth_token
;
150 const ScopedVector
<RpcHandler::PendingRequest
>& request_queue() const {
151 return rpc_handler_
.pending_requests_queue_
;
154 void AddInvalidToken(const std::string
& token
) {
155 rpc_handler_
.invalid_audio_token_cache_
.Add(token
, true);
158 bool TokenIsInvalid(const std::string
& token
) {
159 return rpc_handler_
.invalid_audio_token_cache_
.HasKey(token
);
162 // For rpc_handler_.invalid_audio_token_cache_
163 base::MessageLoop message_loop_
;
165 scoped_ptr
<WhispernetClient
> whispernet_client_
;
166 FakeDirectiveHandler directive_handler_
;
167 scoped_ptr
<CopresenceStateImpl
> state_
;
168 RpcHandler rpc_handler_
;
170 std::map
<bool, std::string
> device_id_by_auth_state_
;
172 CopresenceStatus status_
;
173 std::string rpc_name_
;
174 std::string api_key_
;
175 std::string auth_token_
;
176 ScopedVector
<MessageLite
> request_protos_
;
179 void CaptureHttpPost(
180 net::URLRequestContextGetter
* url_context_getter
,
181 const std::string
& rpc_name
,
182 const std::string
& api_key
,
183 const std::string
& auth_token
,
184 scoped_ptr
<MessageLite
> request_proto
,
185 const RpcHandler::PostCleanupCallback
& response_callback
) {
186 rpc_name_
= rpc_name
;
188 auth_token_
= auth_token
;
189 request_protos_
.push_back(request_proto
.release());
192 void CaptureStatus(CopresenceStatus status
) {
197 TEST_F(RpcHandlerTest
, RegisterDevice
) {
198 RegisterDevice(false);
199 EXPECT_THAT(request_protos_
, SizeIs(1));
200 const RegisterDeviceRequest
* registration
=
201 static_cast<RegisterDeviceRequest
*>(request_protos_
[0]);
202 EXPECT_EQ(CHROME
, registration
->device_identifiers().registrant().type());
204 SetAuthToken("Register auth");
205 RegisterDevice(true);
206 EXPECT_THAT(request_protos_
, SizeIs(2));
207 registration
= static_cast<RegisterDeviceRequest
*>(request_protos_
[1]);
208 EXPECT_FALSE(registration
->has_device_identifiers());
211 TEST_F(RpcHandlerTest
, RequestQueuing
) {
213 ReportRequest
* report
= new ReportRequest
;
214 report
->mutable_manage_messages_request()->add_id_to_unpublish("unpublish");
215 SendReport(make_scoped_ptr(report
), "Q App ID", "Q Auth Token");
216 EXPECT_THAT(request_queue(), SizeIs(1));
217 EXPECT_TRUE(request_queue()[0]->authenticated
);
219 // Check for registration request.
220 EXPECT_THAT(request_protos_
, SizeIs(1));
221 const RegisterDeviceRequest
* registration
=
222 static_cast<RegisterDeviceRequest
*>(request_protos_
[0]);
223 EXPECT_FALSE(registration
->device_identifiers().has_registrant());
224 EXPECT_EQ("Q Auth Token", auth_token_
);
226 // Send a second report.
227 report
= new ReportRequest
;
228 report
->mutable_manage_subscriptions_request()->add_id_to_unsubscribe(
230 SendReport(make_scoped_ptr(report
), "Q App ID", "Q Auth Token");
231 EXPECT_THAT(request_protos_
, SizeIs(1));
232 EXPECT_THAT(request_queue(), SizeIs(2));
233 EXPECT_TRUE(request_queue()[1]->authenticated
);
235 // Send an anonymous report.
236 report
= new ReportRequest
;
237 report
->mutable_update_signals_request()->add_token_observation()
238 ->set_token_id("Q Audio Token");
239 SendReport(make_scoped_ptr(report
), "Q App ID", "");
240 EXPECT_THAT(request_queue(), SizeIs(3));
241 EXPECT_FALSE(request_queue()[2]->authenticated
);
243 // Check for another registration request.
244 EXPECT_THAT(request_protos_
, SizeIs(2));
245 registration
= static_cast<RegisterDeviceRequest
*>(request_protos_
[1]);
246 EXPECT_TRUE(registration
->device_identifiers().has_registrant());
247 EXPECT_EQ("", auth_token_
);
249 // Respond to the first registration.
250 SendRegisterResponse(true, "Q Auth Device ID");
251 EXPECT_EQ("Q Auth Device ID", device_id_by_auth_state_
[true]);
253 // Check that queued reports are sent.
254 EXPECT_THAT(request_protos_
, SizeIs(4));
255 EXPECT_THAT(request_queue(), SizeIs(1));
256 EXPECT_THAT(directive_handler_
.removed_directives(),
257 ElementsAre("unpublish", "unsubscribe"));
258 report
= static_cast<ReportRequest
*>(request_protos_
[2]);
259 EXPECT_EQ("unpublish", report
->manage_messages_request().id_to_unpublish(0));
260 report
= static_cast<ReportRequest
*>(request_protos_
[3]);
261 EXPECT_EQ("unsubscribe",
262 report
->manage_subscriptions_request().id_to_unsubscribe(0));
264 // Respond to the second registration.
265 SendRegisterResponse(false, "Q Anonymous Device ID");
266 EXPECT_EQ("Q Anonymous Device ID", device_id_by_auth_state_
[false]);
268 // Check for last report.
269 EXPECT_THAT(request_protos_
, SizeIs(5));
270 EXPECT_TRUE(request_queue().empty());
271 report
= static_cast<ReportRequest
*>(request_protos_
[4]);
272 EXPECT_EQ("Q Audio Token",
273 report
->update_signals_request().token_observation(0).token_id());
276 TEST_F(RpcHandlerTest
, CreateRequestHeader
) {
277 device_id_by_auth_state_
[true] = "CreateRequestHeader Device ID";
278 SendReport(make_scoped_ptr(new ReportRequest
),
279 "CreateRequestHeader App",
280 "CreateRequestHeader Auth Token");
282 EXPECT_EQ(RpcHandler::kReportRequestRpcName
, rpc_name_
);
283 EXPECT_EQ("CreateRequestHeader App API Key", api_key_
);
284 EXPECT_EQ("CreateRequestHeader Auth Token", auth_token_
);
285 const ReportRequest
* report
= static_cast<ReportRequest
*>(request_protos_
[0]);
286 EXPECT_EQ(kChromeVersion
,
287 report
->header().framework_version().version_name());
288 EXPECT_EQ("CreateRequestHeader App",
289 report
->header().client_version().client());
290 EXPECT_EQ("CreateRequestHeader Device ID",
291 report
->header().registered_device_id());
292 EXPECT_EQ(CHROME_PLATFORM_TYPE
,
293 report
->header().device_fingerprint().type());
296 TEST_F(RpcHandlerTest
, ReportTokens
) {
297 std::vector
<AudioToken
> test_tokens
;
298 test_tokens
.push_back(AudioToken("token 1", false));
299 test_tokens
.push_back(AudioToken("token 2", false));
300 test_tokens
.push_back(AudioToken("token 3", true));
301 AddInvalidToken("token 2");
303 device_id_by_auth_state_
[false] = "ReportTokens Anonymous Device";
304 device_id_by_auth_state_
[true] = "ReportTokens Auth Device";
305 SetAuthToken("ReportTokens Auth");
307 rpc_handler_
.ReportTokens(test_tokens
);
308 EXPECT_EQ(RpcHandler::kReportRequestRpcName
, rpc_name_
);
309 EXPECT_EQ(" API Key", api_key_
);
310 EXPECT_THAT(request_protos_
, SizeIs(2));
311 const ReportRequest
* report
= static_cast<ReportRequest
*>(request_protos_
[0]);
312 RepeatedPtrField
<TokenObservation
> tokens_sent
=
313 report
->update_signals_request().token_observation();
314 EXPECT_THAT(tokens_sent
, ElementsAre(
315 Property(&TokenObservation::token_id
, "token 1"),
316 Property(&TokenObservation::token_id
, "token 3"),
317 Property(&TokenObservation::token_id
, "current audible"),
318 Property(&TokenObservation::token_id
, "current inaudible")));
321 TEST_F(RpcHandlerTest
, ReportResponseHandler
) {
322 // Fail on HTTP status != 200.
323 scoped_ptr
<ReportResponse
> response(new ReportResponse
);
325 SendReportResponse(net::HTTP_BAD_REQUEST
, response
.Pass());
326 EXPECT_EQ(FAIL
, status_
);
328 // Construct a test ReportResponse.
329 response
.reset(new ReportResponse
);
330 response
->mutable_header()->mutable_status()->set_code(OK
);
331 UpdateSignalsResponse
* update_response
=
332 response
->mutable_update_signals_response();
333 update_response
->set_status(util::error::OK
);
334 Token
* invalid_token
= update_response
->add_token();
335 invalid_token
->set_id("bad token");
336 invalid_token
->set_status(INVALID
);
337 update_response
->add_directive()->set_subscription_id("Subscription 1");
338 update_response
->add_directive()->set_subscription_id("Subscription 2");
342 SendReportResponse(net::HTTP_OK
, response
.Pass());
343 EXPECT_EQ(SUCCESS
, status_
);
344 EXPECT_TRUE(TokenIsInvalid("bad token"));
345 EXPECT_THAT(directive_handler_
.added_directives(),
346 ElementsAre("Subscription 1", "Subscription 2"));
349 } // namespace copresence