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 CreateSubscribedMessage(const std::vector
<std::string
>& subscription_ids
,
31 const std::string
& message_string
,
32 SubscribedMessage
* message_proto
) {
33 message_proto
->mutable_published_message()->set_payload(message_string
);
34 for (const std::string
& subscription_id
: subscription_ids
) {
35 message_proto
->add_subscription_id(subscription_id
);
39 // TODO(ckehoe): Make DirectiveHandler an interface.
40 class FakeDirectiveHandler
: public DirectiveHandler
{
42 FakeDirectiveHandler() {}
43 virtual ~FakeDirectiveHandler() {}
45 const std::vector
<Directive
>& added_directives() const {
46 return added_directives_
;
49 virtual void Initialize(
50 const AudioRecorder::DecodeSamplesCallback
& decode_cb
,
51 const AudioDirectiveHandler::EncodeTokenCallback
& encode_cb
) override
{}
53 virtual void AddDirective(const Directive
& directive
) override
{
54 added_directives_
.push_back(directive
);
57 virtual void RemoveDirectives(const std::string
& op_id
) override
{
58 // TODO(ckehoe): Add a parallel implementation when prod has one.
62 std::vector
<Directive
> added_directives_
;
64 DISALLOW_COPY_AND_ASSIGN(FakeDirectiveHandler
);
69 class RpcHandlerTest
: public testing::Test
, public CopresenceDelegate
{
71 RpcHandlerTest() : rpc_handler_(this), status_(SUCCESS
), api_key_("API key") {
72 rpc_handler_
.server_post_callback_
=
73 base::Bind(&RpcHandlerTest::CaptureHttpPost
, base::Unretained(this));
74 rpc_handler_
.device_id_
= "Device ID";
78 net::URLRequestContextGetter
* url_context_getter
,
79 const std::string
& rpc_name
,
80 scoped_ptr
<MessageLite
> request_proto
,
81 const RpcHandler::PostCleanupCallback
& response_callback
) {
83 request_proto_
= request_proto
.Pass();
86 void CaptureStatus(CopresenceStatus status
) {
90 inline const ReportRequest
* GetReportSent() {
91 return static_cast<ReportRequest
*>(request_proto_
.get());
94 const TokenTechnology
& GetTokenTechnologyFromReport() {
95 return GetReportSent()->update_signals_request().state().capabilities()
99 const RepeatedPtrField
<PublishedMessage
>& GetMessagesPublished() {
100 return GetReportSent()->manage_messages_request().message_to_publish();
103 const RepeatedPtrField
<Subscription
>& GetSubscriptionsSent() {
104 return GetReportSent()->manage_subscriptions_request().subscription();
107 void SetDeviceId(const std::string
& device_id
) {
108 rpc_handler_
.device_id_
= device_id
;
111 const std::string
& GetDeviceId() {
112 return rpc_handler_
.device_id_
;
115 void AddInvalidToken(const std::string
& token
) {
116 rpc_handler_
.invalid_audio_token_cache_
.Add(token
, true);
119 bool TokenIsInvalid(const std::string
& token
) {
120 return rpc_handler_
.invalid_audio_token_cache_
.HasKey(token
);
123 FakeDirectiveHandler
* InstallFakeDirectiveHandler() {
124 FakeDirectiveHandler
* handler
= new FakeDirectiveHandler
;
125 rpc_handler_
.directive_handler_
.reset(handler
);
129 void InvokeReportResponseHandler(int status_code
,
130 const std::string
& response
) {
131 rpc_handler_
.ReportResponseHandler(
132 base::Bind(&RpcHandlerTest::CaptureStatus
, base::Unretained(this)),
138 // CopresenceDelegate implementation
140 virtual void HandleMessages(
141 const std::string
& app_id
,
142 const std::string
& subscription_id
,
143 const std::vector
<Message
>& messages
) override
{
144 // app_id is unused for now, pending a server fix.
145 messages_by_subscription_
[subscription_id
] = messages
;
148 virtual net::URLRequestContextGetter
* GetRequestContext() const override
{
152 virtual const std::string
GetPlatformVersionString() const override
{
153 return kChromeVersion
;
156 virtual const std::string
GetAPIKey() const override
{
160 virtual WhispernetClient
* GetWhispernetClient() override
{
165 // For rpc_handler_.invalid_audio_token_cache_
166 base::MessageLoop message_loop_
;
168 RpcHandler rpc_handler_
;
169 CopresenceStatus status_
;
170 std::string api_key_
;
172 std::string rpc_name_
;
173 scoped_ptr
<MessageLite
> request_proto_
;
174 std::map
<std::string
, std::vector
<Message
>> messages_by_subscription_
;
177 TEST_F(RpcHandlerTest
, Initialize
) {
179 rpc_handler_
.Initialize(RpcHandler::SuccessCallback());
180 RegisterDeviceRequest
* registration
=
181 static_cast<RegisterDeviceRequest
*>(request_proto_
.get());
182 Identity identity
= registration
->device_identifiers().registrant();
183 EXPECT_EQ(CHROME
, identity
.type());
184 EXPECT_FALSE(identity
.chrome_id().empty());
187 TEST_F(RpcHandlerTest
, CreateRequestHeader
) {
188 SetDeviceId("CreateRequestHeader Device ID");
189 rpc_handler_
.SendReportRequest(make_scoped_ptr(new ReportRequest
),
190 "CreateRequestHeader App ID",
192 EXPECT_EQ(RpcHandler::kReportRequestRpcName
, rpc_name_
);
193 ReportRequest
* report
= static_cast<ReportRequest
*>(request_proto_
.get());
194 EXPECT_EQ(kChromeVersion
,
195 report
->header().framework_version().version_name());
196 EXPECT_EQ("CreateRequestHeader App ID",
197 report
->header().client_version().client());
198 EXPECT_EQ("CreateRequestHeader Device ID",
199 report
->header().registered_device_id());
200 EXPECT_EQ(CHROME_PLATFORM_TYPE
,
201 report
->header().device_fingerprint().type());
204 TEST_F(RpcHandlerTest
, ReportTokens
) {
205 std::vector
<AudioToken
> test_tokens
;
206 test_tokens
.push_back(AudioToken("token 1", false));
207 test_tokens
.push_back(AudioToken("token 2", true));
208 test_tokens
.push_back(AudioToken("token 3", false));
209 AddInvalidToken("token 2");
211 rpc_handler_
.ReportTokens(test_tokens
);
212 EXPECT_EQ(RpcHandler::kReportRequestRpcName
, rpc_name_
);
213 ReportRequest
* report
= static_cast<ReportRequest
*>(request_proto_
.get());
214 RepeatedPtrField
<TokenObservation
> tokens_sent
=
215 report
->update_signals_request().token_observation();
216 ASSERT_EQ(2, tokens_sent
.size());
217 EXPECT_EQ("token 1", tokens_sent
.Get(0).token_id());
218 EXPECT_EQ("token 3", tokens_sent
.Get(1).token_id());
221 TEST_F(RpcHandlerTest
, ReportResponseHandler
) {
222 // Fail on HTTP status != 200.
223 ReportResponse empty_response
;
224 empty_response
.mutable_header()->mutable_status()->set_code(OK
);
225 std::string serialized_empty_response
;
226 ASSERT_TRUE(empty_response
.SerializeToString(&serialized_empty_response
));
228 InvokeReportResponseHandler(net::HTTP_BAD_REQUEST
, serialized_empty_response
);
229 EXPECT_EQ(FAIL
, status_
);
231 std::vector
<std::string
> subscription_1(1, "Subscription 1");
232 std::vector
<std::string
> subscription_2(1, "Subscription 2");
233 std::vector
<std::string
> both_subscriptions
;
234 both_subscriptions
.push_back("Subscription 1");
235 both_subscriptions
.push_back("Subscription 2");
237 ReportResponse test_response
;
238 test_response
.mutable_header()->mutable_status()->set_code(OK
);
239 UpdateSignalsResponse
* update_response
=
240 test_response
.mutable_update_signals_response();
241 update_response
->set_status(util::error::OK
);
242 Token
* invalid_token
= update_response
->add_token();
243 invalid_token
->set_id("bad token");
244 invalid_token
->set_status(INVALID
);
245 CreateSubscribedMessage(
246 subscription_1
, "Message A", update_response
->add_message());
247 CreateSubscribedMessage(
248 subscription_2
, "Message B", update_response
->add_message());
249 CreateSubscribedMessage(
250 both_subscriptions
, "Message C", update_response
->add_message());
251 update_response
->add_directive()->set_subscription_id("Subscription 1");
252 update_response
->add_directive()->set_subscription_id("Subscription 2");
254 messages_by_subscription_
.clear();
255 FakeDirectiveHandler
* directive_handler
= InstallFakeDirectiveHandler();
256 std::string serialized_proto
;
257 ASSERT_TRUE(test_response
.SerializeToString(&serialized_proto
));
259 InvokeReportResponseHandler(net::HTTP_OK
, serialized_proto
);
261 EXPECT_EQ(SUCCESS
, status_
);
262 EXPECT_TRUE(TokenIsInvalid("bad token"));
263 ASSERT_EQ(2U, messages_by_subscription_
.size());
264 ASSERT_EQ(2U, messages_by_subscription_
["Subscription 1"].size());
265 ASSERT_EQ(2U, messages_by_subscription_
["Subscription 2"].size());
266 EXPECT_EQ("Message A",
267 messages_by_subscription_
["Subscription 1"][0].payload());
268 EXPECT_EQ("Message B",
269 messages_by_subscription_
["Subscription 2"][0].payload());
270 EXPECT_EQ("Message C",
271 messages_by_subscription_
["Subscription 1"][1].payload());
272 EXPECT_EQ("Message C",
273 messages_by_subscription_
["Subscription 2"][1].payload());
275 ASSERT_EQ(2U, directive_handler
->added_directives().size());
276 EXPECT_EQ("Subscription 1",
277 directive_handler
->added_directives()[0].subscription_id());
278 EXPECT_EQ("Subscription 2",
279 directive_handler
->added_directives()[1].subscription_id());
282 } // namespace copresence