1 // Copyright 2019 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 "remoting/client/notification/notification_client.h"
6
7 #include <memory>
8
9 #include "base/memory/ptr_util.h"
10 #include "base/optional.h"
11 #include "base/test/mock_callback.h"
12 #include "base/values.h"
13 #include "remoting/client/notification/json_fetcher.h"
14 #include "remoting/client/notification/notification_message.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace remoting {
19
20 namespace {
21
22 using ::testing::ByMove;
23 using ::testing::Return;
24
25 constexpr char kTestEmail[] = "test@example.com";
26 constexpr char kTestPlatform[] = "IOS";
27 constexpr char kTestVersion[] = "76.0.3809.13";
28 constexpr char kTestLocale[] = "zh-CN";
29
30 class MockJsonFetcher : public JsonFetcher {
31 public:
32 // GMock doesn't work with rvalue parameters. This works around it.
33 MOCK_CONST_METHOD1(FetchJsonFile,
34 base::Optional<base::Value>(const std::string&));
FetchJsonFile(const std::string & relative_path,FetchJsonFileCallback done,const net::NetworkTrafficAnnotationTag &)35 void FetchJsonFile(const std::string& relative_path,
36 FetchJsonFileCallback done,
37 const net::NetworkTrafficAnnotationTag&) override {
38 auto value_opt = FetchJsonFile(relative_path);
39 std::move(done).Run(std::move(value_opt));
40 }
41 };
42
43 MATCHER(NoMessage, "") {
44 return !arg.has_value();
45 }
46
47 MATCHER_P(MessageMatches, expected, "") {
48 return arg->message_id == expected.message_id &&
49 arg->message_text == expected.message_text &&
50 arg->link_text == expected.link_text &&
51 arg->link_url == expected.link_url;
52 }
53
54 template <typename T>
ReturnByMove(T t)55 decltype(auto) ReturnByMove(T t) {
56 return Return(ByMove(std::move(t)));
57 }
58
CreateDefaultRule()59 base::Value CreateDefaultRule() {
60 base::Value rule(base::Value::Type::DICTIONARY);
61 rule.SetStringKey("target_platform", "IOS");
62 rule.SetStringKey("version", "[75-)");
63 rule.SetStringKey("message_id", "test_message");
64 rule.SetStringKey("message_text", "message_text.json");
65 rule.SetStringKey("link_text", "link_text.json");
66 rule.SetStringKey("link_url", "https://example.com/some_link");
67 rule.SetIntKey("percent", 100);
68 rule.SetBoolKey("allow_silence", true);
69 return rule;
70 }
71
CreateDefaultTranslations(const std::string & text)72 base::Value CreateDefaultTranslations(const std::string& text) {
73 base::Value translations(base::Value::Type::DICTIONARY);
74 translations.SetStringKey("en-US", "en-US:" + text);
75 translations.SetStringKey("zh-CN", "zh-CN:" + text);
76 return translations;
77 }
78
CreateDefaultNotification()79 NotificationMessage CreateDefaultNotification() {
80 NotificationMessage message;
81 message.message_id = "test_message";
82 message.message_text = "zh-CN:message";
83 message.link_text = "zh-CN:link";
84 message.link_url = "https://example.com/some_link";
85 message.allow_silence = true;
86 return message;
87 }
88
89 } // namespace
90
91 class NotificationClientTest : public ::testing::Test {
92 public:
NotificationClientTest()93 NotificationClientTest() { Reset(true); }
94
95 ~NotificationClientTest() override = default;
96
97 protected:
Reset(bool should_ignore_dev_messages)98 void Reset(bool should_ignore_dev_messages) {
99 auto fetcher = std::make_unique<MockJsonFetcher>();
100 fetcher_ = fetcher.get();
101 client_ = base::WrapUnique(
102 new NotificationClient(std::move(fetcher), kTestPlatform, kTestVersion,
103 kTestLocale, should_ignore_dev_messages));
104 }
105
106 MockJsonFetcher* fetcher_;
107 std::unique_ptr<NotificationClient> client_;
108 };
109
TEST_F(NotificationClientTest,NoRule)110 TEST_F(NotificationClientTest, NoRule) {
111 base::Value rules(base::Value::Type::LIST);
112 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
113 .WillOnce(ReturnByMove(std::move(rules)));
114
115 base::MockCallback<NotificationClient::NotificationCallback> callback;
116 EXPECT_CALL(callback, Run(NoMessage()));
117 client_->GetNotification(kTestEmail, callback.Get());
118 }
119
TEST_F(NotificationClientTest,DefaultRule)120 TEST_F(NotificationClientTest, DefaultRule) {
121 base::Value rules(base::Value::Type::LIST);
122 rules.Append(CreateDefaultRule());
123 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
124 .WillOnce(ReturnByMove(std::move(rules)));
125 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
126 .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
127 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
128 .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
129
130 base::MockCallback<NotificationClient::NotificationCallback> callback;
131 EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
132 client_->GetNotification(kTestEmail, callback.Get());
133 }
134
TEST_F(NotificationClientTest,PlatformNotMatched)135 TEST_F(NotificationClientTest, PlatformNotMatched) {
136 base::Value rule = CreateDefaultRule();
137 rule.SetStringKey("target_platform", "ANDROID");
138 base::Value rules(base::Value::Type::LIST);
139 rules.Append(std::move(rule));
140 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
141 .WillOnce(ReturnByMove(std::move(rules)));
142
143 base::MockCallback<NotificationClient::NotificationCallback> callback;
144 EXPECT_CALL(callback, Run(NoMessage()));
145 client_->GetNotification(kTestEmail, callback.Get());
146 }
147
TEST_F(NotificationClientTest,VersionNotMatched)148 TEST_F(NotificationClientTest, VersionNotMatched) {
149 base::Value rule = CreateDefaultRule();
150 rule.SetStringKey("version", "[77-)");
151 base::Value rules(base::Value::Type::LIST);
152 rules.Append(std::move(rule));
153 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
154 .WillOnce(ReturnByMove(std::move(rules)));
155
156 base::MockCallback<NotificationClient::NotificationCallback> callback;
157 EXPECT_CALL(callback, Run(NoMessage()));
158 client_->GetNotification(kTestEmail, callback.Get());
159 }
160
TEST_F(NotificationClientTest,UserNotSelected)161 TEST_F(NotificationClientTest, UserNotSelected) {
162 base::Value rule = CreateDefaultRule();
163 rule.SetIntKey("percent", 0);
164 base::Value rules(base::Value::Type::LIST);
165 rules.Append(std::move(rule));
166 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
167 .WillOnce(ReturnByMove(std::move(rules)));
168
169 base::MockCallback<NotificationClient::NotificationCallback> callback;
170 EXPECT_CALL(callback, Run(NoMessage()));
171 client_->GetNotification(kTestEmail, callback.Get());
172 }
173
TEST_F(NotificationClientTest,SecondRuleMatches)174 TEST_F(NotificationClientTest, SecondRuleMatches) {
175 base::Value rules(base::Value::Type::LIST);
176 base::Value rule_1 = CreateDefaultRule();
177 rule_1.SetStringKey("target_platform", "ANDROID");
178 rule_1.SetStringKey("message_text", "message_text_1.json");
179 rules.Append(std::move(rule_1));
180 rules.Append(CreateDefaultRule());
181 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
182 .WillOnce(ReturnByMove(std::move(rules)));
183 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
184 .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
185 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
186 .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
187
188 base::MockCallback<NotificationClient::NotificationCallback> callback;
189 EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
190 client_->GetNotification(kTestEmail, callback.Get());
191 }
192
TEST_F(NotificationClientTest,MultipleMatchingRules_FirstRuleSelected)193 TEST_F(NotificationClientTest, MultipleMatchingRules_FirstRuleSelected) {
194 base::Value rules(base::Value::Type::LIST);
195 rules.Append(CreateDefaultRule());
196 base::Value rule_2 = CreateDefaultRule();
197 rule_2.SetStringKey("message_text", "message_text_2.json");
198 rules.Append(std::move(rule_2));
199 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
200 .WillOnce(ReturnByMove(std::move(rules)));
201 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
202 .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
203 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
204 .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
205
206 base::MockCallback<NotificationClient::NotificationCallback> callback;
207 EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
208 client_->GetNotification(kTestEmail, callback.Get());
209 }
210
TEST_F(NotificationClientTest,TextFilesNotFound)211 TEST_F(NotificationClientTest, TextFilesNotFound) {
212 base::Value rules(base::Value::Type::LIST);
213 rules.Append(CreateDefaultRule());
214 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
215 .WillOnce(ReturnByMove(std::move(rules)));
216
217 base::Value translation = CreateDefaultTranslations("message");
218
219 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
220 .WillOnce(ReturnByMove(base::nullopt));
221 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
222 .WillOnce(ReturnByMove(base::nullopt));
223
224 base::MockCallback<NotificationClient::NotificationCallback> callback;
225 EXPECT_CALL(callback, Run(NoMessage()));
226 client_->GetNotification(kTestEmail, callback.Get());
227 }
228
TEST_F(NotificationClientTest,TranslationNotFound_FallbackToEnglish)229 TEST_F(NotificationClientTest, TranslationNotFound_FallbackToEnglish) {
230 base::Value rules(base::Value::Type::LIST);
231 rules.Append(CreateDefaultRule());
232 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
233 .WillOnce(ReturnByMove(std::move(rules)));
234
235 base::Value translations = CreateDefaultTranslations("message");
236 translations.RemoveKey("zh-CN");
237 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
238 .WillOnce(ReturnByMove(std::move(translations)));
239 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
240 .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
241
242 NotificationMessage notification = CreateDefaultNotification();
243 notification.message_text = "en-US:message";
244 base::MockCallback<NotificationClient::NotificationCallback> callback;
245 EXPECT_CALL(callback, Run(MessageMatches(notification)));
246 client_->GetNotification(kTestEmail, callback.Get());
247 }
248
TEST_F(NotificationClientTest,NoAvailableTranslation)249 TEST_F(NotificationClientTest, NoAvailableTranslation) {
250 base::Value rules(base::Value::Type::LIST);
251 rules.Append(CreateDefaultRule());
252 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
253 .WillOnce(ReturnByMove(std::move(rules)));
254
255 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
256 .WillOnce(ReturnByMove(base::Value(base::Value::Type::DICTIONARY)));
257 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
258 .WillOnce(ReturnByMove(base::Value(base::Value::Type::DICTIONARY)));
259
260 base::MockCallback<NotificationClient::NotificationCallback> callback;
261 EXPECT_CALL(callback, Run(NoMessage()));
262 client_->GetNotification(kTestEmail, callback.Get());
263 }
264
TEST_F(NotificationClientTest,ReleaseBuildsIgnoreDevMessages)265 TEST_F(NotificationClientTest, ReleaseBuildsIgnoreDevMessages) {
266 base::Value rules(base::Value::Type::LIST);
267 base::Value rule = CreateDefaultRule();
268 rule.SetBoolKey("dev_mode", true);
269 rules.Append(std::move(rule));
270 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
271 .WillOnce(ReturnByMove(std::move(rules)));
272
273 base::MockCallback<NotificationClient::NotificationCallback> callback;
274 EXPECT_CALL(callback, Run(NoMessage()));
275 client_->GetNotification(kTestEmail, callback.Get());
276 }
277
TEST_F(NotificationClientTest,ReleaseBuildsDontIgnoreDevMessages)278 TEST_F(NotificationClientTest, ReleaseBuildsDontIgnoreDevMessages) {
279 base::Value rules(base::Value::Type::LIST);
280 base::Value rule = CreateDefaultRule();
281 rule.SetBoolKey("dev_mode", false);
282 rules.Append(std::move(rule));
283 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
284 .WillOnce(ReturnByMove(std::move(rules)));
285 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
286 .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
287 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
288 .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
289
290 base::MockCallback<NotificationClient::NotificationCallback> callback;
291 EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
292 client_->GetNotification(kTestEmail, callback.Get());
293 }
294
TEST_F(NotificationClientTest,DebugBuildsDontIgnoreDevMessages)295 TEST_F(NotificationClientTest, DebugBuildsDontIgnoreDevMessages) {
296 Reset(/* should_ignore_dev_messages */ false);
297
298 base::Value rules(base::Value::Type::LIST);
299 base::Value rule = CreateDefaultRule();
300 rule.SetBoolKey("dev_mode", true);
301 rules.Append(std::move(rule));
302 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
303 .WillOnce(ReturnByMove(std::move(rules)));
304 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
305 .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
306 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
307 .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
308
309 base::MockCallback<NotificationClient::NotificationCallback> callback;
310 EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
311 client_->GetNotification(kTestEmail, callback.Get());
312 }
313
TEST_F(NotificationClientTest,AllowSilenceNotSet_DefaultToFalse)314 TEST_F(NotificationClientTest, AllowSilenceNotSet_DefaultToFalse) {
315 base::Value rules(base::Value::Type::LIST);
316 base::Value rule = CreateDefaultRule();
317 rule.RemoveKey("allow_silence");
318 rules.Append(std::move(rule));
319 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
320 .WillOnce(ReturnByMove(std::move(rules)));
321 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
322 .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
323 EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
324 .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
325
326 NotificationMessage notification = CreateDefaultNotification();
327 notification.allow_silence = false;
328 base::MockCallback<NotificationClient::NotificationCallback> callback;
329 EXPECT_CALL(callback, Run(MessageMatches(notification)));
330 client_->GetNotification(kTestEmail, callback.Get());
331 }
332
333 } // namespace remoting