assistant_alarm_timer_controller_unittest.cc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  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. #include "ash/assistant/assistant_alarm_timer_controller_impl.h"
  5. #include <memory>
  6. #include <utility>
  7. #include <vector>
  8. #include "ash/assistant/assistant_controller_impl.h"
  9. #include "ash/assistant/assistant_notification_controller_impl.h"
  10. #include "ash/assistant/model/assistant_alarm_timer_model.h"
  11. #include "ash/assistant/model/assistant_alarm_timer_model_observer.h"
  12. #include "ash/assistant/model/assistant_notification_model.h"
  13. #include "ash/assistant/model/assistant_notification_model_observer.h"
  14. #include "ash/assistant/test/assistant_ash_test_base.h"
  15. #include "ash/assistant/util/deep_link_util.h"
  16. #include "ash/shell.h"
  17. #include "ash/strings/grit/ash_strings.h"
  18. #include "base/test/icu_test_util.h"
  19. #include "base/test/scoped_feature_list.h"
  20. #include "base/test/task_environment.h"
  21. #include "base/time/time.h"
  22. #include "chromeos/ash/services/assistant/public/cpp/features.h"
  23. #include "chromeos/services/libassistant/public/cpp/assistant_notification.h"
  24. #include "chromeos/services/libassistant/public/cpp/assistant_timer.h"
  25. #include "testing/gmock/include/gmock/gmock.h"
  26. #include "testing/gtest/include/gtest/gtest.h"
  27. #include "ui/base/l10n/l10n_util.h"
  28. namespace ash {
  29. namespace {
  30. using chromeos::assistant::AssistantNotification;
  31. using chromeos::assistant::AssistantNotificationButton;
  32. using chromeos::assistant::AssistantNotificationPriority;
  33. using chromeos::assistant::AssistantTimer;
  34. using chromeos::assistant::AssistantTimerState;
  35. // Constants.
  36. constexpr char kClientId[] = "assistant/timer<timer-id>";
  37. constexpr char kTimerId[] = "<timer-id>";
  38. // Mocks -----------------------------------------------------------------------
  39. class MockAssistantAlarmTimerModelObserver
  40. : public testing::NiceMock<AssistantAlarmTimerModelObserver> {
  41. public:
  42. MOCK_METHOD(void, OnTimerAdded, (const AssistantTimer&), (override));
  43. MOCK_METHOD(void, OnTimerUpdated, (const AssistantTimer&), (override));
  44. };
  45. // Test Structs ----------------------------------------------------------------
  46. // Represents a test instruction to advance the tick of the mock clock and
  47. // assert an |expected_string|.
  48. typedef struct {
  49. base::TimeDelta advance_clock;
  50. std::string expected_string;
  51. } TestTick;
  52. // Represents a |locale| specific test case containing assertions to be made at
  53. // various |ticks| of the mock clock.
  54. typedef struct {
  55. std::string locale;
  56. std::vector<TestTick> ticks;
  57. } I18nTestCase;
  58. // Timer Events ----------------------------------------------------------------
  59. class TimerEvent {
  60. public:
  61. TimerEvent& WithLabel(const std::string& label) {
  62. timer_.label = label;
  63. return *this;
  64. }
  65. TimerEvent& WithCreationTime(absl::optional<base::Time> creation_time) {
  66. timer_.creation_time = creation_time;
  67. return *this;
  68. }
  69. TimerEvent& WithOriginalDuration(base::TimeDelta original_duration) {
  70. timer_.original_duration = original_duration;
  71. return *this;
  72. }
  73. TimerEvent& WithRemainingTime(base::TimeDelta remaining_time) {
  74. timer_.fire_time = base::Time::Now() + remaining_time;
  75. timer_.remaining_time = remaining_time;
  76. return *this;
  77. }
  78. protected:
  79. TimerEvent(const std::string& id, AssistantTimerState state) {
  80. timer_.id = id;
  81. timer_.state = state;
  82. timer_.fire_time = base::Time::Now();
  83. }
  84. ~TimerEvent() {
  85. std::vector<AssistantTimer> timers;
  86. timers.push_back(timer_);
  87. AssistantAlarmTimerController::Get()->OnTimerStateChanged(
  88. std::move(timers));
  89. }
  90. private:
  91. AssistantTimer timer_;
  92. };
  93. class FireTimer : public TimerEvent {
  94. public:
  95. explicit FireTimer(const std::string& id)
  96. : TimerEvent(id, AssistantTimerState::kFired) {}
  97. };
  98. class PauseTimer : public TimerEvent {
  99. public:
  100. explicit PauseTimer(const std::string& id)
  101. : TimerEvent(id, AssistantTimerState::kPaused) {}
  102. };
  103. class ScheduleTimer : public TimerEvent {
  104. public:
  105. explicit ScheduleTimer(const std::string& id)
  106. : TimerEvent(id, AssistantTimerState::kScheduled) {}
  107. };
  108. // Expectations ----------------------------------------------------------------
  109. class ExpectedNotification {
  110. public:
  111. ExpectedNotification() = default;
  112. ExpectedNotification(const ExpectedNotification&) = delete;
  113. ExpectedNotification& operator=(const ExpectedNotification&) = delete;
  114. ~ExpectedNotification() = default;
  115. friend std::ostream& operator<<(std::ostream& os,
  116. const ExpectedNotification& notif) {
  117. if (notif.action_url_.has_value())
  118. os << "\naction_url: '" << notif.action_url_.value() << "'";
  119. if (notif.client_id_.has_value())
  120. os << "\nclient_id: '" << notif.client_id_.value() << "'";
  121. if (notif.is_pinned_.has_value())
  122. os << "\nis_pinned: '" << notif.is_pinned_.value() << "'";
  123. if (notif.message_.has_value())
  124. os << "\nmessage: '" << notif.message_.value() << "'";
  125. if (notif.priority_.has_value())
  126. os << "\npriority: '" << static_cast<int>(notif.priority_.value()) << "'";
  127. if (notif.remove_on_click_.has_value())
  128. os << "\nremove_on_click: '" << notif.remove_on_click_.value() << "'";
  129. if (notif.renotify_.has_value())
  130. os << "\nrenotify: '" << notif.renotify_.value() << "'";
  131. if (notif.title_.has_value())
  132. os << "\ntitle: '" << notif.title_.value() << "'";
  133. return os;
  134. }
  135. bool operator==(const AssistantNotification& notification) const {
  136. return notification.action_url ==
  137. action_url_.value_or(notification.action_url) &&
  138. notification.client_id ==
  139. client_id_.value_or(notification.client_id) &&
  140. notification.is_pinned ==
  141. is_pinned_.value_or(notification.is_pinned) &&
  142. notification.message == message_.value_or(notification.message) &&
  143. notification.priority == priority_.value_or(notification.priority) &&
  144. notification.remove_on_click ==
  145. remove_on_click_.value_or(notification.remove_on_click) &&
  146. notification.renotify == renotify_.value_or(notification.renotify) &&
  147. notification.title == title_.value_or(notification.title);
  148. }
  149. ExpectedNotification& WithActionUrl(const GURL& action_url) {
  150. action_url_ = action_url;
  151. return *this;
  152. }
  153. ExpectedNotification& WithClientId(const std::string& client_id) {
  154. client_id_ = client_id;
  155. return *this;
  156. }
  157. ExpectedNotification& WithIsPinned(bool is_pinned) {
  158. is_pinned_ = is_pinned;
  159. return *this;
  160. }
  161. ExpectedNotification& WithMessage(const std::string& message) {
  162. message_ = message;
  163. return *this;
  164. }
  165. ExpectedNotification& WithPriority(AssistantNotificationPriority priority) {
  166. priority_ = priority;
  167. return *this;
  168. }
  169. ExpectedNotification& WithRemoveOnClick(bool remove_on_click) {
  170. remove_on_click_ = remove_on_click;
  171. return *this;
  172. }
  173. ExpectedNotification& WithRenotify(bool renotify) {
  174. renotify_ = renotify;
  175. return *this;
  176. }
  177. ExpectedNotification& WithTitle(const std::string& title) {
  178. title_ = title;
  179. return *this;
  180. }
  181. ExpectedNotification& WithTitleId(int title_id) {
  182. return WithTitle(l10n_util::GetStringUTF8(title_id));
  183. }
  184. private:
  185. absl::optional<GURL> action_url_;
  186. absl::optional<std::string> client_id_;
  187. absl::optional<bool> is_pinned_;
  188. absl::optional<std::string> message_;
  189. absl::optional<AssistantNotificationPriority> priority_;
  190. absl::optional<bool> remove_on_click_;
  191. absl::optional<bool> renotify_;
  192. absl::optional<std::string> title_;
  193. };
  194. class ExpectedButton {
  195. public:
  196. ExpectedButton() = default;
  197. ExpectedButton(const ExpectedButton&) = delete;
  198. ExpectedButton& operator=(const ExpectedButton&) = delete;
  199. ~ExpectedButton() = default;
  200. friend std::ostream& operator<<(std::ostream& os, const ExpectedButton& btr) {
  201. if (btr.action_url_.has_value())
  202. os << "\naction_url: '" << btr.action_url_.value() << "'";
  203. if (btr.label_.has_value())
  204. os << "\nlabel: '" << btr.label_.value() << "'";
  205. if (btr.remove_notification_on_click_.has_value()) {
  206. os << "\nremove_notification_on_click: '"
  207. << btr.remove_notification_on_click_.value() << "'";
  208. }
  209. return os;
  210. }
  211. bool operator==(const AssistantNotificationButton& button) const {
  212. return button.action_url == action_url_.value_or(button.action_url) &&
  213. button.label == label_.value_or(button.label) &&
  214. button.remove_notification_on_click ==
  215. remove_notification_on_click_.value_or(
  216. button.remove_notification_on_click);
  217. }
  218. ExpectedButton& WithActionUrl(const GURL& action_url) {
  219. action_url_ = action_url;
  220. return *this;
  221. }
  222. ExpectedButton& WithLabel(int message_id) {
  223. label_ = l10n_util::GetStringUTF8(message_id);
  224. return *this;
  225. }
  226. ExpectedButton& WithRemoveNotificationOnClick(
  227. bool remove_notification_on_click) {
  228. remove_notification_on_click_ = remove_notification_on_click;
  229. return *this;
  230. }
  231. private:
  232. absl::optional<GURL> action_url_;
  233. absl::optional<std::string> label_;
  234. absl::optional<bool> remove_notification_on_click_;
  235. };
  236. // ScopedNotificationModelObserver ---------------------------------------------
  237. class ScopedNotificationModelObserver
  238. : public AssistantNotificationModelObserver {
  239. public:
  240. ScopedNotificationModelObserver() {
  241. Shell::Get()
  242. ->assistant_controller()
  243. ->notification_controller()
  244. ->model()
  245. ->AddObserver(this);
  246. }
  247. ScopedNotificationModelObserver(const ScopedNotificationModelObserver&) =
  248. delete;
  249. ScopedNotificationModelObserver& operator=(
  250. const ScopedNotificationModelObserver&) = delete;
  251. ~ScopedNotificationModelObserver() override {
  252. Shell::Get()
  253. ->assistant_controller()
  254. ->notification_controller()
  255. ->model()
  256. ->RemoveObserver(this);
  257. }
  258. // AssistantNotificationModelObserver:
  259. void OnNotificationAdded(const AssistantNotification& notification) override {
  260. last_notification_ = notification;
  261. }
  262. void OnNotificationUpdated(
  263. const AssistantNotification& notification) override {
  264. last_notification_ = notification;
  265. }
  266. const AssistantNotification& last_notification() const {
  267. return last_notification_;
  268. }
  269. private:
  270. AssistantNotification last_notification_;
  271. };
  272. } // namespace
  273. // AssistantAlarmTimerControllerTest -------------------------------------------
  274. class AssistantAlarmTimerControllerTest : public AssistantAshTestBase {
  275. protected:
  276. AssistantAlarmTimerControllerTest()
  277. : AssistantAshTestBase(
  278. base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  279. AssistantAlarmTimerControllerTest(const AssistantAlarmTimerControllerTest&) =
  280. delete;
  281. AssistantAlarmTimerControllerTest& operator=(
  282. const AssistantAlarmTimerControllerTest&) = delete;
  283. ~AssistantAlarmTimerControllerTest() override = default;
  284. // AshTestBase:
  285. void SetUp() override {
  286. AssistantAshTestBase::SetUp();
  287. }
  288. void TearDown() override {
  289. controller()->OnTimerStateChanged({});
  290. AssistantAshTestBase::TearDown();
  291. }
  292. // Advances the clock by |time_delta| and waits for the next timer update.
  293. // NOTE: If |time_delta| is zero, this method is a no-op.
  294. void AdvanceClockAndWaitForTimerUpdate(base::TimeDelta time_delta) {
  295. if (time_delta.is_zero())
  296. return;
  297. task_environment()->AdvanceClock(time_delta);
  298. MockAssistantAlarmTimerModelObserver observer;
  299. controller()->GetModel()->AddObserver(&observer);
  300. base::RunLoop run_loop;
  301. EXPECT_CALL(observer, OnTimerUpdated)
  302. .WillOnce(testing::Invoke([&](const AssistantTimer& timer) {
  303. run_loop.QuitClosure().Run();
  304. }));
  305. run_loop.Run();
  306. controller()->GetModel()->RemoveObserver(&observer);
  307. }
  308. AssistantAlarmTimerController* controller() {
  309. return AssistantAlarmTimerController::Get();
  310. }
  311. };
  312. // Tests -----------------------------------------------------------------------
  313. // Tests that creation time is properly respected/defaulted when adding a timer.
  314. TEST_F(AssistantAlarmTimerControllerTest, AddedTimersShouldHaveCreationTime) {
  315. MockAssistantAlarmTimerModelObserver mock;
  316. controller()->GetModel()->AddObserver(&mock);
  317. // If unspecified, |creation_time| is expected to be now.
  318. base::Time creation_time = base::Time::Now();
  319. EXPECT_CALL(mock, OnTimerAdded)
  320. .WillOnce(testing::Invoke([&](const AssistantTimer& timer) {
  321. EXPECT_EQ(creation_time, timer.creation_time.value());
  322. }));
  323. // Schedule a timer w/o specifying |creation_time|.
  324. ScheduleTimer{kTimerId};
  325. // Reset for the next test case.
  326. controller()->OnTimerStateChanged({});
  327. testing::Mock::VerifyAndClearExpectations(&mock);
  328. // If specified, |creation_time| should be respected.
  329. creation_time -= base::Minutes(1);
  330. EXPECT_CALL(mock, OnTimerAdded)
  331. .WillOnce(testing::Invoke([&](const AssistantTimer& timer) {
  332. EXPECT_EQ(creation_time, timer.creation_time.value());
  333. }));
  334. // Schedule a timer w/ specified |creation _time|.
  335. ScheduleTimer(kTimerId).WithCreationTime(creation_time);
  336. controller()->GetModel()->RemoveObserver(&mock);
  337. }
  338. // Tests that a notification is added for a timer and has the expected title at
  339. // various states in its lifecycle.
  340. TEST_F(AssistantAlarmTimerControllerTest, TimerNotificationHasExpectedTitle) {
  341. // We're going to run our test over a few locales to ensure i18n compliance.
  342. std::vector<I18nTestCase> i18n_test_cases;
  343. // We'll test in English (United States).
  344. i18n_test_cases.push_back({
  345. /*locale=*/"en_US",
  346. /*ticks=*/
  347. {
  348. {base::TimeDelta(), "1:01:01"},
  349. {base::Hours(1), "1:01"},
  350. {base::Minutes(1), "0:01"},
  351. {base::Seconds(1), "0:00"},
  352. {base::Seconds(1), "-0:01"},
  353. {base::Minutes(1), "-1:01"},
  354. {base::Hours(1), "-1:01:01"},
  355. },
  356. });
  357. // We'll also test in Slovenian (Slovenia).
  358. i18n_test_cases.push_back({
  359. /*locale=*/"sl_SI",
  360. /*ticks=*/
  361. {
  362. {base::TimeDelta(), "1.01.01"},
  363. {base::Hours(1), "1.01"},
  364. {base::Minutes(1), "0.01"},
  365. {base::Seconds(1), "0.00"},
  366. {base::Seconds(1), "-0.01"},
  367. {base::Minutes(1), "-1.01"},
  368. {base::Hours(1), "-1.01.01"},
  369. },
  370. });
  371. // Run all of our internationalized test cases.
  372. for (auto& i18n_test_case : i18n_test_cases) {
  373. base::test::ScopedRestoreICUDefaultLocale locale(i18n_test_case.locale);
  374. // Observe notifications.
  375. ScopedNotificationModelObserver observer;
  376. // Schedule a timer.
  377. ScheduleTimer(kTimerId).WithRemainingTime(
  378. base::Hours(1) + base::Minutes(1) + base::Seconds(1));
  379. // Run each tick of the clock in the test.
  380. for (auto& tick : i18n_test_case.ticks) {
  381. // Advance clock to next tick.
  382. AdvanceClockAndWaitForTimerUpdate(tick.advance_clock);
  383. // Make assertions about the notification.
  384. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithTitle(
  385. tick.expected_string),
  386. observer.last_notification());
  387. }
  388. }
  389. }
  390. // TODO(dmblack): Add another locale after string translation.
  391. // Tests that a notification is added for a timer and has the expected message.
  392. TEST_F(AssistantAlarmTimerControllerTest, TimerNotificationHasExpectedMessage) {
  393. constexpr char kEmptyLabel[] = "";
  394. constexpr base::TimeDelta kOneSec = base::Seconds(1);
  395. constexpr base::TimeDelta kOneMin = base::Minutes(1);
  396. constexpr base::TimeDelta kOneHour = base::Hours(1);
  397. // We'll verify the message of our notification with various timers.
  398. typedef struct {
  399. base::TimeDelta original_duration;
  400. std::string label;
  401. std::string expected_message_when_scheduled;
  402. std::string expected_message_when_fired;
  403. } TestTimer;
  404. // We're going to run our test over a few locales to ensure i18n compliance.
  405. typedef struct {
  406. std::string locale;
  407. std::vector<TestTimer> timers;
  408. } I18nTestCase;
  409. std::vector<I18nTestCase> i18n_test_cases;
  410. // We'll test in English (United States).
  411. i18n_test_cases.push_back({
  412. /*locale=*/"en_US",
  413. /*timers=*/
  414. {
  415. {kOneSec, kEmptyLabel, "1s timer", "Time's up"},
  416. {kOneSec, "Eggs", "1s timer · Eggs", "Time's up · Eggs"},
  417. {kOneSec + kOneMin, kEmptyLabel, "1m 1s timer", "Time's up"},
  418. {kOneSec + kOneMin, "Eggs", "1m 1s timer · Eggs", "Time's up · Eggs"},
  419. {kOneSec + kOneMin + kOneHour, kEmptyLabel, "1h 1m 1s timer",
  420. "Time's up"},
  421. {kOneSec + kOneMin + kOneHour, "Eggs", "1h 1m 1s timer · Eggs",
  422. "Time's up · Eggs"},
  423. },
  424. });
  425. // Run all of our internationalized test cases.
  426. for (auto& i18n_test_case : i18n_test_cases) {
  427. base::test::ScopedRestoreICUDefaultLocale locale(i18n_test_case.locale);
  428. // Observe notifications.
  429. ScopedNotificationModelObserver observer;
  430. // Run each timer in the test.
  431. for (auto& timer : i18n_test_case.timers) {
  432. // Schedule timer.
  433. ScheduleTimer(kTimerId)
  434. .WithLabel(timer.label)
  435. .WithOriginalDuration(timer.original_duration);
  436. // Make assertions about the notification.
  437. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithMessage(
  438. timer.expected_message_when_scheduled),
  439. observer.last_notification());
  440. // Fire timer.
  441. FireTimer(kTimerId)
  442. .WithLabel(timer.label)
  443. .WithOriginalDuration(timer.original_duration);
  444. // Make assertions about the notification.
  445. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithMessage(
  446. timer.expected_message_when_fired),
  447. observer.last_notification());
  448. }
  449. }
  450. }
  451. // Tests that a notification is added for a timer and has the expected action.
  452. TEST_F(AssistantAlarmTimerControllerTest, TimerNotificationHasExpectedAction) {
  453. // Observe notifications.
  454. ScopedNotificationModelObserver observer;
  455. // Schedule a timer.
  456. ScheduleTimer{kTimerId};
  457. // We expect that the notification action will result in a no-op on click.
  458. EXPECT_EQ(
  459. ExpectedNotification().WithClientId(kClientId).WithActionUrl(GURL()),
  460. observer.last_notification());
  461. }
  462. // Tests that a notification is added for a timer and has the expected buttons
  463. // at each state in its lifecycle.
  464. TEST_F(AssistantAlarmTimerControllerTest, TimerNotificationHasExpectedButtons) {
  465. // Observe notifications.
  466. ScopedNotificationModelObserver observer;
  467. constexpr base::TimeDelta kTimeRemaining = base::Minutes(1);
  468. // Schedule a timer.
  469. ScheduleTimer(kTimerId).WithRemainingTime(kTimeRemaining);
  470. // We expect the timer notification to have two buttons.
  471. ASSERT_EQ(2u, observer.last_notification().buttons.size());
  472. // We expect a "PAUSE" button which will pause the timer.
  473. EXPECT_EQ(
  474. ExpectedButton()
  475. .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_PAUSE_BUTTON)
  476. .WithActionUrl(
  477. assistant::util::CreateAlarmTimerDeepLink(
  478. assistant::util::AlarmTimerAction::kPauseTimer, kTimerId)
  479. .value())
  480. .WithRemoveNotificationOnClick(false),
  481. observer.last_notification().buttons.at(0));
  482. // We expect a "CANCEL" button which will remove the timer.
  483. EXPECT_EQ(ExpectedButton()
  484. .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
  485. .WithActionUrl(
  486. assistant::util::CreateAlarmTimerDeepLink(
  487. assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer,
  488. kTimerId)
  489. .value())
  490. .WithRemoveNotificationOnClick(true),
  491. observer.last_notification().buttons.at(1));
  492. // Pause the timer.
  493. PauseTimer(kTimerId).WithRemainingTime(kTimeRemaining);
  494. // We expect the timer notification to have two buttons.
  495. ASSERT_EQ(2u, observer.last_notification().buttons.size());
  496. // We expect a "RESUME" button which will resume the timer.
  497. EXPECT_EQ(
  498. ExpectedButton()
  499. .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_RESUME_BUTTON)
  500. .WithActionUrl(
  501. assistant::util::CreateAlarmTimerDeepLink(
  502. assistant::util::AlarmTimerAction::kResumeTimer, kTimerId)
  503. .value())
  504. .WithRemoveNotificationOnClick(false),
  505. observer.last_notification().buttons.at(0));
  506. // We expect a "CANCEL" button which will remove the timer.
  507. EXPECT_EQ(ExpectedButton()
  508. .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_CANCEL_BUTTON)
  509. .WithActionUrl(
  510. assistant::util::CreateAlarmTimerDeepLink(
  511. assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer,
  512. kTimerId)
  513. .value())
  514. .WithRemoveNotificationOnClick(true),
  515. observer.last_notification().buttons.at(1));
  516. // Fire the timer.
  517. FireTimer{kTimerId};
  518. // We expect the timer notification to have two buttons.
  519. ASSERT_EQ(2u, observer.last_notification().buttons.size());
  520. // We expect a "STOP" button which will remove the timer.
  521. EXPECT_EQ(ExpectedButton()
  522. .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_STOP_BUTTON)
  523. .WithActionUrl(
  524. assistant::util::CreateAlarmTimerDeepLink(
  525. assistant::util::AlarmTimerAction::kRemoveAlarmOrTimer,
  526. kTimerId)
  527. .value())
  528. .WithRemoveNotificationOnClick(true),
  529. observer.last_notification().buttons.at(0));
  530. // We expect an "ADD 1 MIN" button which will add time to the timer.
  531. EXPECT_EQ(
  532. ExpectedButton()
  533. .WithLabel(IDS_ASSISTANT_TIMER_NOTIFICATION_ADD_1_MIN_BUTTON)
  534. .WithActionUrl(assistant::util::CreateAlarmTimerDeepLink(
  535. assistant::util::AlarmTimerAction::kAddTimeToTimer,
  536. kTimerId, base::Minutes(1))
  537. .value())
  538. .WithRemoveNotificationOnClick(false),
  539. observer.last_notification().buttons.at(1));
  540. }
  541. // Tests that a notification is added for a timer and has the expected value to
  542. // *not* cause removal on click.
  543. TEST_F(AssistantAlarmTimerControllerTest,
  544. TimerNotificationHasExpectedRemoveOnClick) {
  545. // Observe notifications.
  546. ScopedNotificationModelObserver observer;
  547. // Schedule a timer.
  548. ScheduleTimer{kTimerId};
  549. // Make assertions about the notification.
  550. EXPECT_EQ(
  551. ExpectedNotification().WithClientId(kClientId).WithRemoveOnClick(false),
  552. observer.last_notification());
  553. }
  554. // Tests that a notification is added for a timer and has the expected value to
  555. // cause renotification.
  556. TEST_F(AssistantAlarmTimerControllerTest,
  557. TimerNotificationHasExpectedRenotify) {
  558. // Observe notifications.
  559. ScopedNotificationModelObserver observer;
  560. // Schedule a timer.
  561. ScheduleTimer{kTimerId};
  562. // Make assertions about the notification.
  563. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithRenotify(false),
  564. observer.last_notification());
  565. // Fire the timer.
  566. FireTimer{kTimerId};
  567. // Make assertions about the notification.
  568. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithRenotify(true),
  569. observer.last_notification());
  570. }
  571. // Tests that a notification is added for a timer and has the expected priority
  572. // at various stages of its lifecycle.
  573. TEST_F(AssistantAlarmTimerControllerTest,
  574. TimerNotificationHasExpectedPriority) {
  575. // Observe notifications.
  576. ScopedNotificationModelObserver notification_model_observer;
  577. // Schedule a timer.
  578. ScheduleTimer(kTimerId).WithRemainingTime(base::Seconds(10));
  579. // Make assertions about the notification.
  580. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithPriority(
  581. AssistantNotificationPriority::kDefault),
  582. notification_model_observer.last_notification());
  583. // Advance the clock.
  584. // NOTE: Six seconds is the threshold for popping up our notification.
  585. AdvanceClockAndWaitForTimerUpdate(base::Seconds(6));
  586. // Make assertions about the notification.
  587. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithPriority(
  588. AssistantNotificationPriority::kLow),
  589. notification_model_observer.last_notification());
  590. // Fire the timer.
  591. FireTimer{kTimerId};
  592. // Make assertions about the notification.
  593. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithPriority(
  594. AssistantNotificationPriority::kHigh),
  595. notification_model_observer.last_notification());
  596. }
  597. // Tests that a notification is added for a timer and is pinned.
  598. TEST_F(AssistantAlarmTimerControllerTest, TimerNotificationIsPinned) {
  599. // Observe notifications.
  600. ScopedNotificationModelObserver observer;
  601. // Schedule a timer.
  602. ScheduleTimer{kTimerId};
  603. // Make assertions about the notification.
  604. EXPECT_EQ(ExpectedNotification().WithClientId(kClientId).WithIsPinned(true),
  605. observer.last_notification());
  606. }
  607. } // namespace ash