assistant_controller_impl_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // Copyright 2020 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_controller_impl.h"
  5. #include <map>
  6. #include <memory>
  7. #include <string>
  8. #include "ash/assistant/test/assistant_ash_test_base.h"
  9. #include "ash/assistant/test/test_assistant_service.h"
  10. #include "ash/assistant/util/deep_link_util.h"
  11. #include "ash/constants/ash_features.h"
  12. #include "ash/constants/ash_pref_names.h"
  13. #include "ash/public/cpp/assistant/controller/assistant_controller_observer.h"
  14. #include "ash/public/cpp/test/test_new_window_delegate.h"
  15. #include "ash/session/session_controller_impl.h"
  16. #include "ash/shell.h"
  17. #include "ash/style/dark_light_mode_controller_impl.h"
  18. #include "base/scoped_observation.h"
  19. #include "base/test/scoped_feature_list.h"
  20. #include "chromeos/ash/services/assistant/public/cpp/assistant_service.h"
  21. #include "chromeos/constants/chromeos_features.h"
  22. #include "testing/gmock/include/gmock/gmock.h"
  23. namespace ash {
  24. namespace {
  25. // MockAssistantControllerObserver ---------------------------------------------
  26. class MockAssistantControllerObserver : public AssistantControllerObserver {
  27. public:
  28. MockAssistantControllerObserver() = default;
  29. ~MockAssistantControllerObserver() override = default;
  30. // AssistantControllerObserver:
  31. MOCK_METHOD(void, OnAssistantControllerConstructed, (), (override));
  32. MOCK_METHOD(void, OnAssistantControllerDestroying, (), (override));
  33. MOCK_METHOD(void, OnAssistantReady, (), (override));
  34. MOCK_METHOD(void,
  35. OnDeepLinkReceived,
  36. (assistant::util::DeepLinkType type,
  37. (const std::map<std::string, std::string>& params)),
  38. (override));
  39. MOCK_METHOD(void,
  40. OnOpeningUrl,
  41. (const GURL& url, bool in_background, bool from_server),
  42. (override));
  43. MOCK_METHOD(void,
  44. OnUrlOpened,
  45. (const GURL& url, bool from_server),
  46. (override));
  47. };
  48. class MockAssistantUiModelObserver : public AssistantUiModelObserver {
  49. public:
  50. MockAssistantUiModelObserver() = default;
  51. ~MockAssistantUiModelObserver() override = default;
  52. MOCK_METHOD(void,
  53. OnUiVisibilityChanged,
  54. (AssistantVisibility new_visibility,
  55. AssistantVisibility old_visibility,
  56. absl::optional<AssistantEntryPoint> entry_point,
  57. absl::optional<AssistantExitPoint> exit_point),
  58. (override));
  59. };
  60. // MockNewWindowDelegate -------------------------------------------------------
  61. class MockNewWindowDelegate : public testing::NiceMock<TestNewWindowDelegate> {
  62. public:
  63. // TestNewWindowDelegate:
  64. MOCK_METHOD(void,
  65. OpenUrl,
  66. (const GURL& url, OpenUrlFrom from, Disposition disposition),
  67. (override));
  68. MOCK_METHOD(void,
  69. OpenFeedbackPage,
  70. (NewWindowDelegate::FeedbackSource source,
  71. const std::string& description_template),
  72. (override));
  73. };
  74. // AssistantControllerImplTest -------------------------------------------------
  75. class AssistantControllerImplTest : public AssistantAshTestBase {
  76. public:
  77. AssistantControllerImplTest() {
  78. auto delegate = std::make_unique<MockNewWindowDelegate>();
  79. new_window_delegate_ = delegate.get();
  80. delegate_provider_ =
  81. std::make_unique<TestNewWindowDelegateProvider>(std::move(delegate));
  82. }
  83. AssistantController* controller() { return AssistantController::Get(); }
  84. MockNewWindowDelegate& new_window_delegate() { return *new_window_delegate_; }
  85. const AssistantUiModel* ui_model() {
  86. return AssistantUiController::Get()->GetModel();
  87. }
  88. TestAssistantService* test_assistant_service() {
  89. return &test_assistant_service_;
  90. }
  91. private:
  92. MockNewWindowDelegate* new_window_delegate_;
  93. std::unique_ptr<TestNewWindowDelegateProvider> delegate_provider_;
  94. // AssistantService must outlive AssistantController as destructor can
  95. // reference AssistantService.
  96. TestAssistantService test_assistant_service_;
  97. };
  98. } // namespace
  99. // Tests -----------------------------------------------------------------------
  100. // Tests that AssistantController observers are notified of deep link received.
  101. TEST_F(AssistantControllerImplTest, NotifiesDeepLinkReceived) {
  102. testing::NiceMock<MockAssistantControllerObserver> controller_observer_mock;
  103. base::ScopedObservation<AssistantController, AssistantControllerObserver>
  104. scoped_controller_obs{&controller_observer_mock};
  105. scoped_controller_obs.Observe(controller());
  106. EXPECT_CALL(controller_observer_mock, OnDeepLinkReceived)
  107. .WillOnce(
  108. testing::Invoke([](assistant::util::DeepLinkType type,
  109. const std::map<std::string, std::string>& params) {
  110. EXPECT_EQ(assistant::util::DeepLinkType::kQuery, type);
  111. EXPECT_EQ("weather",
  112. assistant::util::GetDeepLinkParam(
  113. params, assistant::util::DeepLinkParam::kQuery)
  114. .value());
  115. }));
  116. controller()->OpenUrl(
  117. assistant::util::CreateAssistantQueryDeepLink("weather"));
  118. }
  119. // Tests that AssistantController observers are notified of URLs opening and
  120. // having been opened. Note that it is important that these events be notified
  121. // before and after the URL is actually opened respectively.
  122. TEST_F(AssistantControllerImplTest, NotifiesOpeningUrlAndUrlOpened) {
  123. testing::NiceMock<MockAssistantControllerObserver> controller_observer_mock;
  124. base::ScopedObservation<AssistantController, AssistantControllerObserver>
  125. scoped_controller_obs{&controller_observer_mock};
  126. scoped_controller_obs.Observe(controller());
  127. // Enforce ordering of events.
  128. testing::InSequence sequence;
  129. EXPECT_CALL(controller_observer_mock, OnOpeningUrl)
  130. .WillOnce(testing::Invoke(
  131. [](const GURL& url, bool in_background, bool from_server) {
  132. EXPECT_EQ(GURL("https://g.co/"), url);
  133. EXPECT_TRUE(in_background);
  134. EXPECT_TRUE(from_server);
  135. }));
  136. EXPECT_CALL(new_window_delegate(),
  137. OpenUrl(GURL("https://g.co/"),
  138. NewWindowDelegate::OpenUrlFrom::kUserInteraction,
  139. NewWindowDelegate::Disposition::kNewForegroundTab));
  140. EXPECT_CALL(controller_observer_mock, OnUrlOpened)
  141. .WillOnce(testing::Invoke([](const GURL& url, bool from_server) {
  142. EXPECT_EQ(GURL("https://g.co/"), url);
  143. EXPECT_TRUE(from_server);
  144. }));
  145. controller()->OpenUrl(GURL("https://g.co/"), /*in_background=*/true,
  146. /*from_server=*/true);
  147. }
  148. TEST_F(AssistantControllerImplTest, NotOpenUrlIfAssistantNotReady) {
  149. testing::NiceMock<MockAssistantControllerObserver> controller_observer_mock;
  150. base::ScopedObservation<AssistantController, AssistantControllerObserver>
  151. scoped_controller_obs{&controller_observer_mock};
  152. scoped_controller_obs.Observe(controller());
  153. EXPECT_CALL(controller_observer_mock, OnOpeningUrl).Times(0);
  154. controller()->SetAssistant(nullptr);
  155. controller()->OpenUrl(GURL("https://g.co/"), /*in_background=*/true,
  156. /*from_server=*/true);
  157. }
  158. TEST_F(AssistantControllerImplTest, OpensFeedbackPageForFeedbackDeeplink) {
  159. testing::NiceMock<MockAssistantControllerObserver> controller_observer_mock;
  160. base::ScopedObservation<AssistantController, AssistantControllerObserver>
  161. scoped_controller_obs{&controller_observer_mock};
  162. scoped_controller_obs.Observe(controller());
  163. EXPECT_CALL(controller_observer_mock, OnDeepLinkReceived)
  164. .WillOnce(
  165. testing::Invoke([](assistant::util::DeepLinkType type,
  166. const std::map<std::string, std::string>& params) {
  167. EXPECT_EQ(assistant::util::DeepLinkType::kFeedback, type);
  168. std::map<std::string, std::string> expected_params;
  169. EXPECT_EQ(params, expected_params);
  170. }));
  171. EXPECT_CALL(new_window_delegate(), OpenFeedbackPage)
  172. .WillOnce([](NewWindowDelegate::FeedbackSource source,
  173. const std::string& description_template) {
  174. EXPECT_EQ(NewWindowDelegate::FeedbackSource::kFeedbackSourceAssistant,
  175. source);
  176. EXPECT_EQ(std::string(), description_template);
  177. });
  178. controller()->OpenUrl(GURL("googleassistant://send-feedback"),
  179. /*in_background=*/false, /*from_server=*/true);
  180. }
  181. TEST_F(AssistantControllerImplTest, ClosesAssistantUiForFeedbackDeeplink) {
  182. ShowAssistantUi();
  183. testing::NiceMock<MockAssistantUiModelObserver> ui_model_observer_mock;
  184. ui_model()->AddObserver(&ui_model_observer_mock);
  185. testing::InSequence sequence;
  186. EXPECT_CALL(ui_model_observer_mock, OnUiVisibilityChanged)
  187. .WillOnce([](AssistantVisibility new_visibility,
  188. AssistantVisibility old_visibility,
  189. absl::optional<AssistantEntryPoint> entry_point,
  190. absl::optional<AssistantExitPoint> exit_point) {
  191. EXPECT_EQ(old_visibility, AssistantVisibility::kVisible);
  192. EXPECT_EQ(new_visibility, AssistantVisibility::kClosing);
  193. EXPECT_FALSE(entry_point.has_value());
  194. EXPECT_EQ(exit_point.value(), AssistantExitPoint::kUnspecified);
  195. });
  196. EXPECT_CALL(ui_model_observer_mock, OnUiVisibilityChanged)
  197. .WillOnce([](AssistantVisibility new_visibility,
  198. AssistantVisibility old_visibility,
  199. absl::optional<AssistantEntryPoint> entry_point,
  200. absl::optional<AssistantExitPoint> exit_point) {
  201. EXPECT_EQ(old_visibility, AssistantVisibility::kClosing);
  202. EXPECT_EQ(new_visibility, AssistantVisibility::kClosed);
  203. EXPECT_FALSE(entry_point.has_value());
  204. EXPECT_EQ(exit_point.value(), AssistantExitPoint::kUnspecified);
  205. });
  206. controller()->OpenUrl(GURL("googleassistant://send-feedback"),
  207. /*in_background=*/false, /*from_server=*/true);
  208. ui_model()->RemoveObserver(&ui_model_observer_mock);
  209. }
  210. // Make sure that AssistantControllerImpl sets dark mode = false even if the
  211. // flag is off. SettingsController won't set options if dark mode bit is not
  212. // set.
  213. TEST_F(AssistantControllerImplTest, ColorModeIsSetWhenAssistantIsReadyFlagOff) {
  214. // ProductivityLauncher uses DarkLightMode colors.
  215. base::test::ScopedFeatureList scoped_feature_list;
  216. scoped_feature_list.InitWithFeatures(
  217. /*enabled_features=*/{}, /*disabled_features=*/{
  218. chromeos::features::kDarkLightMode, features::kNotificationsRefresh,
  219. features::kProductivityLauncher});
  220. controller()->SetAssistant(test_assistant_service());
  221. ASSERT_TRUE(test_assistant_service()->dark_mode_enabled().has_value());
  222. EXPECT_FALSE(test_assistant_service()->dark_mode_enabled().value());
  223. }
  224. TEST_F(AssistantControllerImplTest, ColorModeIsUpdated) {
  225. base::test::ScopedFeatureList feature_list;
  226. feature_list.InitAndEnableFeature(chromeos::features::kDarkLightMode);
  227. ASSERT_TRUE(chromeos::features::IsDarkLightModeEnabled());
  228. auto* active_user_pref_service =
  229. Shell::Get()->session_controller()->GetPrimaryUserPrefService();
  230. ASSERT_TRUE(active_user_pref_service);
  231. auto* dark_light_mode_controller = DarkLightModeControllerImpl::Get();
  232. dark_light_mode_controller->OnActiveUserPrefServiceChanged(
  233. active_user_pref_service);
  234. controller()->SetAssistant(test_assistant_service());
  235. const bool initial_dark_mode_status =
  236. dark_light_mode_controller->IsDarkModeEnabled();
  237. ASSERT_TRUE(test_assistant_service()->dark_mode_enabled().has_value());
  238. EXPECT_EQ(initial_dark_mode_status,
  239. test_assistant_service()->dark_mode_enabled().value());
  240. // Switch the color mode.
  241. dark_light_mode_controller->ToggleColorMode();
  242. ASSERT_TRUE(test_assistant_service()->dark_mode_enabled().has_value());
  243. EXPECT_NE(initial_dark_mode_status,
  244. test_assistant_service()->dark_mode_enabled().value());
  245. }
  246. } // namespace ash