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/message_loop/message_loop.h"
14 #include "components/copresence/handlers/directive_handler.h"
15 #include "components/copresence/proto/data.pb.h"
16 #include "components/copresence/proto/enums.pb.h"
17 #include "components/copresence/proto/rpcs.pb.h"
18 #include "net/http/http_status_code.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using google::protobuf::MessageLite
;
22 using google::protobuf::RepeatedPtrField
;
24 namespace copresence
{
28 const char kChromeVersion
[] = "Chrome Version String";
30 void AddMessageWithStrategy(ReportRequest
* report
,
31 BroadcastScanConfiguration strategy
) {
32 report
->mutable_manage_messages_request()->add_message_to_publish()
33 ->mutable_token_exchange_strategy()->set_broadcast_scan_configuration(
37 void AddSubscriptionWithStrategy(ReportRequest
* report
,
38 BroadcastScanConfiguration strategy
) {
39 report
->mutable_manage_subscriptions_request()->add_subscription()
40 ->mutable_token_exchange_strategy()->set_broadcast_scan_configuration(
44 void CreateSubscribedMessage(const std::vector
<std::string
>& subscription_ids
,
45 const std::string
& message_string
,
46 SubscribedMessage
* message_proto
) {
47 message_proto
->mutable_published_message()->set_payload(message_string
);
48 for (std::vector
<std::string
>::const_iterator subscription_id
=
49 subscription_ids
.begin();
50 subscription_id
!= subscription_ids
.end();
52 message_proto
->add_subscription_id(*subscription_id
);
56 // TODO(ckehoe): Make DirectiveHandler an interface.
57 class FakeDirectiveHandler
: public DirectiveHandler
{
59 FakeDirectiveHandler() {}
60 virtual ~FakeDirectiveHandler() {}
62 const std::vector
<Directive
>& added_directives() const {
63 return added_directives_
;
66 virtual void Initialize(
67 const AudioRecorder::DecodeSamplesCallback
& decode_cb
,
68 const AudioDirectiveHandler::EncodeTokenCallback
& encode_cb
) OVERRIDE
{}
70 virtual void AddDirective(const Directive
& directive
) OVERRIDE
{
71 added_directives_
.push_back(directive
);
74 virtual void RemoveDirectives(const std::string
& op_id
) OVERRIDE
{
75 // TODO(ckehoe): Add a parallel implementation when prod has one.
79 std::vector
<Directive
> added_directives_
;
81 DISALLOW_COPY_AND_ASSIGN(FakeDirectiveHandler
);
86 class RpcHandlerTest
: public testing::Test
, public CopresenceDelegate
{
88 RpcHandlerTest() : rpc_handler_(this), status_(SUCCESS
), api_key_("API key") {
89 rpc_handler_
.server_post_callback_
=
90 base::Bind(&RpcHandlerTest::CaptureHttpPost
, base::Unretained(this));
91 rpc_handler_
.device_id_
= "Device ID";
95 net::URLRequestContextGetter
* url_context_getter
,
96 const std::string
& rpc_name
,
97 scoped_ptr
<MessageLite
> request_proto
,
98 const RpcHandler::PostCleanupCallback
& response_callback
) {
100 request_proto_
= request_proto
.Pass();
103 void CaptureStatus(CopresenceStatus status
) {
107 inline const ReportRequest
* GetReportSent() {
108 return static_cast<ReportRequest
*>(request_proto_
.get());
111 const TokenTechnology
& GetTokenTechnologyFromReport() {
112 return GetReportSent()->update_signals_request().state().capabilities()
113 .token_technology(0);
116 const RepeatedPtrField
<PublishedMessage
>& GetMessagesPublished() {
117 return GetReportSent()->manage_messages_request().message_to_publish();
120 const RepeatedPtrField
<Subscription
>& GetSubscriptionsSent() {
121 return GetReportSent()->manage_subscriptions_request().subscription();
124 void SetDeviceId(const std::string
& device_id
) {
125 rpc_handler_
.device_id_
= device_id
;
128 const std::string
& GetDeviceId() {
129 return rpc_handler_
.device_id_
;
132 void AddInvalidToken(const std::string
& token
) {
133 rpc_handler_
.invalid_audio_token_cache_
.Add(token
, true);
136 bool TokenIsInvalid(const std::string
& token
) {
137 return rpc_handler_
.invalid_audio_token_cache_
.HasKey(token
);
140 FakeDirectiveHandler
* InstallFakeDirectiveHandler() {
141 FakeDirectiveHandler
* handler
= new FakeDirectiveHandler
;
142 rpc_handler_
.directive_handler_
.reset(handler
);
146 void InvokeReportResponseHandler(int status_code
,
147 const std::string
& response
) {
148 rpc_handler_
.ReportResponseHandler(
149 base::Bind(&RpcHandlerTest::CaptureStatus
, base::Unretained(this)),
155 // CopresenceDelegate implementation
157 virtual void HandleMessages(
158 const std::string
& app_id
,
159 const std::string
& subscription_id
,
160 const std::vector
<Message
>& messages
) OVERRIDE
{
161 // app_id is unused for now, pending a server fix.
162 messages_by_subscription_
[subscription_id
] = messages
;
165 virtual net::URLRequestContextGetter
* GetRequestContext() const OVERRIDE
{
169 virtual const std::string
GetPlatformVersionString() const OVERRIDE
{
170 return kChromeVersion
;
173 virtual const std::string
GetAPIKey() const OVERRIDE
{
177 virtual WhispernetClient
* GetWhispernetClient() OVERRIDE
{
182 // For rpc_handler_.invalid_audio_token_cache_
183 base::MessageLoop message_loop_
;
185 RpcHandler rpc_handler_
;
186 CopresenceStatus status_
;
187 std::string api_key_
;
189 std::string rpc_name_
;
190 scoped_ptr
<MessageLite
> request_proto_
;
191 std::map
<std::string
, std::vector
<Message
> > messages_by_subscription_
;
194 TEST_F(RpcHandlerTest
, Initialize
) {
196 rpc_handler_
.Initialize(RpcHandler::SuccessCallback());
197 RegisterDeviceRequest
* registration
=
198 static_cast<RegisterDeviceRequest
*>(request_proto_
.get());
199 Identity identity
= registration
->device_identifiers().registrant();
200 EXPECT_EQ(CHROME
, identity
.type());
201 EXPECT_FALSE(identity
.chrome_id().empty());
204 TEST_F(RpcHandlerTest
, GetDeviceCapabilities
) {
206 rpc_handler_
.SendReportRequest(make_scoped_ptr(new ReportRequest
));
207 EXPECT_EQ(RpcHandler::kReportRequestRpcName
, rpc_name_
);
208 const TokenTechnology
* token_technology
= &GetTokenTechnologyFromReport();
209 EXPECT_EQ(AUDIO_ULTRASOUND_PASSBAND
, token_technology
->medium());
210 EXPECT_EQ(TRANSMIT
, token_technology
->instruction_type(0));
211 EXPECT_EQ(RECEIVE
, token_technology
->instruction_type(1));
213 // Request with broadcast only.
214 scoped_ptr
<ReportRequest
> report(new ReportRequest
);
215 AddMessageWithStrategy(report
.get(), BROADCAST_ONLY
);
216 rpc_handler_
.SendReportRequest(report
.Pass());
217 token_technology
= &GetTokenTechnologyFromReport();
218 EXPECT_EQ(1, token_technology
->instruction_type_size());
219 EXPECT_EQ(TRANSMIT
, token_technology
->instruction_type(0));
220 EXPECT_FALSE(GetReportSent()->has_manage_subscriptions_request());
222 // Request with scan only.
223 report
.reset(new ReportRequest
);
224 AddSubscriptionWithStrategy(report
.get(), SCAN_ONLY
);
225 AddSubscriptionWithStrategy(report
.get(), SCAN_ONLY
);
226 rpc_handler_
.SendReportRequest(report
.Pass());
227 token_technology
= &GetTokenTechnologyFromReport();
228 EXPECT_EQ(1, token_technology
->instruction_type_size());
229 EXPECT_EQ(RECEIVE
, token_technology
->instruction_type(0));
230 EXPECT_FALSE(GetReportSent()->has_manage_messages_request());
232 // Request with both scan and broadcast only (conflict).
233 report
.reset(new ReportRequest
);
234 AddMessageWithStrategy(report
.get(), SCAN_ONLY
);
235 AddMessageWithStrategy(report
.get(), BROADCAST_ONLY
);
236 AddSubscriptionWithStrategy(report
.get(), BROADCAST_ONLY
);
237 rpc_handler_
.SendReportRequest(report
.Pass());
238 token_technology
= &GetTokenTechnologyFromReport();
239 EXPECT_EQ(TRANSMIT
, token_technology
->instruction_type(0));
240 EXPECT_EQ(RECEIVE
, token_technology
->instruction_type(1));
242 // Request with broadcast and scan.
243 report
.reset(new ReportRequest
);
244 AddMessageWithStrategy(report
.get(), SCAN_ONLY
);
245 AddSubscriptionWithStrategy(report
.get(), BROADCAST_AND_SCAN
);
246 rpc_handler_
.SendReportRequest(report
.Pass());
247 token_technology
= &GetTokenTechnologyFromReport();
248 EXPECT_EQ(TRANSMIT
, token_technology
->instruction_type(0));
249 EXPECT_EQ(RECEIVE
, token_technology
->instruction_type(1));
252 TEST_F(RpcHandlerTest
, CreateRequestHeader
) {
253 SetDeviceId("CreateRequestHeader Device ID");
254 rpc_handler_
.SendReportRequest(make_scoped_ptr(new ReportRequest
),
255 "CreateRequestHeader App ID",
257 EXPECT_EQ(RpcHandler::kReportRequestRpcName
, rpc_name_
);
258 ReportRequest
* report
= static_cast<ReportRequest
*>(request_proto_
.get());
259 EXPECT_EQ(kChromeVersion
,
260 report
->header().framework_version().version_name());
261 EXPECT_EQ("CreateRequestHeader App ID",
262 report
->header().client_version().client());
263 EXPECT_EQ("CreateRequestHeader Device ID",
264 report
->header().registered_device_id());
265 EXPECT_EQ(CHROME_PLATFORM_TYPE
,
266 report
->header().device_fingerprint().type());
269 TEST_F(RpcHandlerTest
, ReportTokens
) {
270 std::vector
<AudioToken
> test_tokens
;
271 test_tokens
.push_back(AudioToken("token 1", false));
272 test_tokens
.push_back(AudioToken("token 2", true));
273 test_tokens
.push_back(AudioToken("token 3", false));
274 AddInvalidToken("token 2");
276 rpc_handler_
.ReportTokens(test_tokens
);
277 EXPECT_EQ(RpcHandler::kReportRequestRpcName
, rpc_name_
);
278 ReportRequest
* report
= static_cast<ReportRequest
*>(request_proto_
.get());
279 google::protobuf::RepeatedPtrField
<TokenObservation
> tokens_sent
=
280 report
->update_signals_request().token_observation();
281 ASSERT_EQ(2, tokens_sent
.size());
282 EXPECT_EQ("token 1", tokens_sent
.Get(0).token_id());
283 EXPECT_EQ("token 3", tokens_sent
.Get(1).token_id());
286 TEST_F(RpcHandlerTest
, ReportResponseHandler
) {
287 // Fail on HTTP status != 200.
288 ReportResponse empty_response
;
289 empty_response
.mutable_header()->mutable_status()->set_code(OK
);
290 std::string serialized_empty_response
;
291 ASSERT_TRUE(empty_response
.SerializeToString(&serialized_empty_response
));
293 InvokeReportResponseHandler(net::HTTP_BAD_REQUEST
, serialized_empty_response
);
294 EXPECT_EQ(FAIL
, status_
);
296 std::vector
<std::string
> subscription_1(1, "Subscription 1");
297 std::vector
<std::string
> subscription_2(1, "Subscription 2");
298 std::vector
<std::string
> both_subscriptions
;
299 both_subscriptions
.push_back("Subscription 1");
300 both_subscriptions
.push_back("Subscription 2");
302 ReportResponse test_response
;
303 test_response
.mutable_header()->mutable_status()->set_code(OK
);
304 UpdateSignalsResponse
* update_response
=
305 test_response
.mutable_update_signals_response();
306 update_response
->set_status(util::error::OK
);
307 Token
* invalid_token
= update_response
->add_token();
308 invalid_token
->set_id("bad token");
309 invalid_token
->set_status(INVALID
);
310 CreateSubscribedMessage(
311 subscription_1
, "Message A", update_response
->add_message());
312 CreateSubscribedMessage(
313 subscription_2
, "Message B", update_response
->add_message());
314 CreateSubscribedMessage(
315 both_subscriptions
, "Message C", update_response
->add_message());
316 update_response
->add_directive()->set_subscription_id("Subscription 1");
317 update_response
->add_directive()->set_subscription_id("Subscription 2");
319 messages_by_subscription_
.clear();
320 FakeDirectiveHandler
* directive_handler
= InstallFakeDirectiveHandler();
321 std::string serialized_proto
;
322 ASSERT_TRUE(test_response
.SerializeToString(&serialized_proto
));
324 InvokeReportResponseHandler(net::HTTP_OK
, serialized_proto
);
326 EXPECT_EQ(SUCCESS
, status_
);
327 EXPECT_TRUE(TokenIsInvalid("bad token"));
328 ASSERT_EQ(2U, messages_by_subscription_
.size());
329 ASSERT_EQ(2U, messages_by_subscription_
["Subscription 1"].size());
330 ASSERT_EQ(2U, messages_by_subscription_
["Subscription 2"].size());
331 EXPECT_EQ("Message A",
332 messages_by_subscription_
["Subscription 1"][0].payload());
333 EXPECT_EQ("Message B",
334 messages_by_subscription_
["Subscription 2"][0].payload());
335 EXPECT_EQ("Message C",
336 messages_by_subscription_
["Subscription 1"][1].payload());
337 EXPECT_EQ("Message C",
338 messages_by_subscription_
["Subscription 2"][1].payload());
340 ASSERT_EQ(2U, directive_handler
->added_directives().size());
341 EXPECT_EQ("Subscription 1",
342 directive_handler
->added_directives()[0].subscription_id());
343 EXPECT_EQ("Subscription 2",
344 directive_handler
->added_directives()[1].subscription_id());
347 } // namespace copresence