arc_intent_helper_bridge_unittest.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. // Copyright 2016 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 "components/arc/intent_helper/arc_intent_helper_bridge.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "ash/components/arc/mojom/intent_helper.mojom-forward.h"
  10. #include "ash/components/arc/mojom/intent_helper.mojom-shared.h"
  11. #include "ash/components/arc/mojom/intent_helper.mojom.h"
  12. #include "ash/components/arc/session/arc_bridge_service.h"
  13. #include "base/files/file_path.h"
  14. #include "base/memory/ptr_util.h"
  15. #include "base/test/metrics/histogram_tester.h"
  16. #include "components/arc/common/intent_helper/arc_intent_helper_package.h"
  17. #include "components/arc/intent_helper/intent_constants.h"
  18. #include "components/arc/intent_helper/open_url_delegate.h"
  19. #include "mojo/public/cpp/bindings/clone_traits.h"
  20. #include "testing/gmock/include/gmock/gmock.h"
  21. #include "testing/gtest/include/gtest/gtest.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. namespace arc {
  24. class ArcIntentHelperTest : public testing::Test {
  25. protected:
  26. ArcIntentHelperTest() = default;
  27. ArcIntentHelperTest(const ArcIntentHelperTest&) = delete;
  28. ArcIntentHelperTest& operator=(const ArcIntentHelperTest&) = delete;
  29. class TestOpenUrlDelegate : public OpenUrlDelegate {
  30. public:
  31. ~TestOpenUrlDelegate() override = default;
  32. // OpenUrlDelegate:
  33. void OpenUrlFromArc(const GURL& url) override { last_opened_url_ = url; }
  34. void OpenWebAppFromArc(const GURL& url) override { last_opened_url_ = url; }
  35. void OpenArcCustomTab(
  36. const GURL& url,
  37. int32_t task_id,
  38. mojom::IntentHelperHost::OnOpenCustomTabCallback callback) override {
  39. std::move(callback).Run(mojo::NullRemote());
  40. }
  41. void OpenChromePageFromArc(mojom::ChromePage chrome_page) override {}
  42. void OpenAppWithIntent(const GURL& url,
  43. mojom::LaunchIntentPtr intent) override {
  44. last_opened_url_ = url;
  45. last_opened_intent_ = std::move(intent);
  46. }
  47. GURL TakeLastOpenedUrl() {
  48. GURL result = std::move(last_opened_url_);
  49. last_opened_url_ = GURL();
  50. return result;
  51. }
  52. mojom::LaunchIntentPtr TakeLastOpenedIntent() {
  53. auto result = std::move(last_opened_intent_);
  54. last_opened_intent_.reset();
  55. return result;
  56. }
  57. private:
  58. GURL last_opened_url_;
  59. mojom::LaunchIntentPtr last_opened_intent_;
  60. };
  61. std::unique_ptr<ArcBridgeService> arc_bridge_service_;
  62. std::unique_ptr<TestOpenUrlDelegate> test_open_url_delegate_;
  63. std::unique_ptr<ArcIntentHelperBridge> instance_;
  64. private:
  65. void SetUp() override {
  66. arc_bridge_service_ = std::make_unique<ArcBridgeService>();
  67. test_open_url_delegate_ = std::make_unique<TestOpenUrlDelegate>();
  68. instance_ = std::make_unique<ArcIntentHelperBridge>(
  69. nullptr /* context */, arc_bridge_service_.get());
  70. ArcIntentHelperBridge::SetOpenUrlDelegate(test_open_url_delegate_.get());
  71. }
  72. void TearDown() override {
  73. ArcIntentHelperBridge::SetOpenUrlDelegate(nullptr);
  74. instance_.reset();
  75. test_open_url_delegate_.reset();
  76. arc_bridge_service_.reset();
  77. }
  78. };
  79. // Tests if FilterOutIntentHelper removes handlers as expected.
  80. TEST_F(ArcIntentHelperTest, TestFilterOutIntentHelper) {
  81. {
  82. std::vector<mojom::IntentHandlerInfoPtr> orig;
  83. std::vector<mojom::IntentHandlerInfoPtr> filtered =
  84. ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
  85. EXPECT_EQ(0U, filtered.size());
  86. }
  87. {
  88. std::vector<mojom::IntentHandlerInfoPtr> orig;
  89. orig.push_back(mojom::IntentHandlerInfo::New());
  90. orig[0]->name = "0";
  91. orig[0]->package_name = "package_name0";
  92. orig.push_back(mojom::IntentHandlerInfo::New());
  93. orig[1]->name = "1";
  94. orig[1]->package_name = "package_name1";
  95. // FilterOutIntentHelper is no-op in this case.
  96. std::vector<mojom::IntentHandlerInfoPtr> filtered =
  97. ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
  98. EXPECT_EQ(2U, filtered.size());
  99. }
  100. {
  101. std::vector<mojom::IntentHandlerInfoPtr> orig;
  102. orig.push_back(mojom::IntentHandlerInfo::New());
  103. orig[0]->name = "0";
  104. orig[0]->package_name = kArcIntentHelperPackageName;
  105. orig.push_back(mojom::IntentHandlerInfo::New());
  106. orig[1]->name = "1";
  107. orig[1]->package_name = "package_name1";
  108. // FilterOutIntentHelper should remove the first element.
  109. std::vector<mojom::IntentHandlerInfoPtr> filtered =
  110. ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
  111. ASSERT_EQ(1U, filtered.size());
  112. EXPECT_EQ("1", filtered[0]->name);
  113. EXPECT_EQ("package_name1", filtered[0]->package_name);
  114. }
  115. {
  116. std::vector<mojom::IntentHandlerInfoPtr> orig;
  117. orig.push_back(mojom::IntentHandlerInfo::New());
  118. orig[0]->name = "0";
  119. orig[0]->package_name = kArcIntentHelperPackageName;
  120. orig.push_back(mojom::IntentHandlerInfo::New());
  121. orig[1]->name = "1";
  122. orig[1]->package_name = "package_name1";
  123. orig.push_back(mojom::IntentHandlerInfo::New());
  124. orig[2]->name = "2";
  125. orig[2]->package_name = kArcIntentHelperPackageName;
  126. // FilterOutIntentHelper should remove two elements.
  127. std::vector<mojom::IntentHandlerInfoPtr> filtered =
  128. ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
  129. ASSERT_EQ(1U, filtered.size());
  130. EXPECT_EQ("1", filtered[0]->name);
  131. EXPECT_EQ("package_name1", filtered[0]->package_name);
  132. }
  133. {
  134. std::vector<mojom::IntentHandlerInfoPtr> orig;
  135. orig.push_back(mojom::IntentHandlerInfo::New());
  136. orig[0]->name = "0";
  137. orig[0]->package_name = kArcIntentHelperPackageName;
  138. orig.push_back(mojom::IntentHandlerInfo::New());
  139. orig[1]->name = "1";
  140. orig[1]->package_name = kArcIntentHelperPackageName;
  141. // FilterOutIntentHelper should remove all elements.
  142. std::vector<mojom::IntentHandlerInfoPtr> filtered =
  143. ArcIntentHelperBridge::FilterOutIntentHelper(std::move(orig));
  144. EXPECT_EQ(0U, filtered.size());
  145. }
  146. }
  147. // Tests if observer works as expected.
  148. TEST_F(ArcIntentHelperTest, TestObserver) {
  149. class MockObserver : public ArcIntentHelperObserver {
  150. public:
  151. MOCK_METHOD(void,
  152. OnArcDownloadAdded,
  153. (const base::FilePath& relative_path,
  154. const std::string& owner_package_name),
  155. (override));
  156. MOCK_METHOD(void,
  157. OnIntentFiltersUpdated,
  158. (const absl::optional<std::string>& package_name),
  159. (override));
  160. MOCK_METHOD(
  161. void,
  162. OnArcSupportedLinksChanged,
  163. (const std::vector<arc::mojom::SupportedLinksPtr>& added_packages,
  164. const std::vector<arc::mojom::SupportedLinksPtr>& removed_packages,
  165. arc::mojom::SupportedLinkChangeSource source),
  166. (override));
  167. };
  168. // Create and add observer.
  169. testing::StrictMock<MockObserver> observer;
  170. instance_->AddObserver(&observer);
  171. {
  172. // Observer should be called when a download is added.
  173. std::string relative_path("Download/foo/bar.pdf");
  174. std::string owner_package_name("owner_package_name");
  175. EXPECT_CALL(observer,
  176. OnArcDownloadAdded(testing::Eq(base::FilePath(relative_path)),
  177. testing::Ref(owner_package_name)));
  178. instance_->OnDownloadAdded(relative_path, owner_package_name);
  179. testing::Mock::VerifyAndClearExpectations(&observer);
  180. }
  181. {
  182. // Observer should *not* be called when a download is added outside of the
  183. // Download/ folder. This would be an unexpected event coming from ARC but
  184. // we protect against it because ARC is treated as an untrusted source.
  185. instance_->OnDownloadAdded(/*relative_path=*/"Download/../foo/bar.pdf",
  186. /*owner_package_name=*/"owner_package_name");
  187. testing::Mock::VerifyAndClearExpectations(&observer);
  188. }
  189. {
  190. // Observer should be called when an intent filter is updated.
  191. EXPECT_CALL(observer, OnIntentFiltersUpdated(testing::Eq(absl::nullopt)));
  192. instance_->OnIntentFiltersUpdated(/*filters=*/std::vector<IntentFilter>());
  193. testing::Mock::VerifyAndClearExpectations(&observer);
  194. }
  195. {
  196. // Observer should be called when supported links change.
  197. EXPECT_CALL(observer, OnArcSupportedLinksChanged);
  198. instance_->OnSupportedLinksChanged(
  199. /*added_packages=*/{},
  200. /*removed_packages=*/{},
  201. arc::mojom::SupportedLinkChangeSource::kArcSystem);
  202. testing::Mock::VerifyAndClearExpectations(&observer);
  203. }
  204. // Observer should not be called after it's removed.
  205. instance_->RemoveObserver(&observer);
  206. instance_->OnDownloadAdded(/*relative_path=*/"Download/foo/bar.pdf",
  207. /*owner_package_name=*/"owner_package_name");
  208. instance_->OnIntentFiltersUpdated(/*filters=*/{});
  209. instance_->OnSupportedLinksChanged(
  210. /*added_packages=*/{},
  211. /*removed_packages=*/{},
  212. arc::mojom::SupportedLinkChangeSource::kArcSystem);
  213. }
  214. // Tests that OnOpenUrl opens the URL in Chrome browser.
  215. TEST_F(ArcIntentHelperTest, TestOnOpenUrl) {
  216. instance_->OnOpenUrl("http://google.com");
  217. EXPECT_EQ(GURL("http://google.com"),
  218. test_open_url_delegate_->TakeLastOpenedUrl());
  219. instance_->OnOpenUrl("https://google.com");
  220. EXPECT_EQ(GURL("https://google.com"),
  221. test_open_url_delegate_->TakeLastOpenedUrl());
  222. }
  223. // Tests that OnOpenWebApp opens only HTTPS URLs or localhost.
  224. TEST_F(ArcIntentHelperTest, TestOnOpenWebApp) {
  225. instance_->OnOpenWebApp("http://google.com");
  226. EXPECT_EQ(GURL(), test_open_url_delegate_->TakeLastOpenedUrl());
  227. instance_->OnOpenWebApp("http://localhost/");
  228. EXPECT_EQ(GURL("http://localhost/"),
  229. test_open_url_delegate_->TakeLastOpenedUrl());
  230. instance_->OnOpenWebApp("https://google.com");
  231. EXPECT_EQ(GURL("https://google.com"),
  232. test_open_url_delegate_->TakeLastOpenedUrl());
  233. }
  234. // Tests that OnOpenUrl does not open URLs with the 'chrome://' and equivalent
  235. // schemes like 'about:'.
  236. TEST_F(ArcIntentHelperTest, TestOnOpenUrl_ChromeScheme) {
  237. instance_->OnOpenUrl("chrome://www.google.com");
  238. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  239. instance_->OnOpenUrl("chrome://settings");
  240. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  241. instance_->OnOpenUrl("about:");
  242. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  243. instance_->OnOpenUrl("about:settings");
  244. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  245. instance_->OnOpenUrl("about:blank");
  246. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  247. }
  248. // Tests that OnOpenAppWithIntents opens only HTTPS URLs.
  249. TEST_F(ArcIntentHelperTest, TestOnOpenAppWithIntent) {
  250. base::HistogramTester histograms;
  251. auto intent = mojom::LaunchIntent::New();
  252. intent->action = arc::kIntentActionSend;
  253. intent->extra_text = "Foo";
  254. instance_->OnOpenAppWithIntent(GURL("https://www.google.com"),
  255. std::move(intent));
  256. EXPECT_EQ(GURL("https://www.google.com"),
  257. test_open_url_delegate_->TakeLastOpenedUrl());
  258. EXPECT_EQ("Foo", test_open_url_delegate_->TakeLastOpenedIntent()->extra_text);
  259. histograms.ExpectBucketCount("Arc.IntentHelper.OpenAppWithIntentAction",
  260. 2 /* OpenIntentAction::kSend */, 1);
  261. instance_->OnOpenAppWithIntent(GURL("http://www.google.com"),
  262. mojom::LaunchIntent::New());
  263. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  264. EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
  265. instance_->OnOpenAppWithIntent(GURL("http://localhost:8000/foo"),
  266. mojom::LaunchIntent::New());
  267. EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  268. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
  269. instance_->OnOpenAppWithIntent(GURL("chrome://settings"),
  270. mojom::LaunchIntent::New());
  271. EXPECT_FALSE(test_open_url_delegate_->TakeLastOpenedUrl().is_valid());
  272. EXPECT_TRUE(test_open_url_delegate_->TakeLastOpenedIntent().is_null());
  273. }
  274. // Tests that AppendStringToIntentHelperPackageName works.
  275. TEST_F(ArcIntentHelperTest, TestAppendStringToIntentHelperPackageName) {
  276. std::string package_name = kArcIntentHelperPackageName;
  277. std::string fake_activity = "this_is_a_fake_activity";
  278. EXPECT_EQ(ArcIntentHelperBridge::AppendStringToIntentHelperPackageName(
  279. fake_activity),
  280. package_name + "." + fake_activity);
  281. const std::string empty_string;
  282. EXPECT_EQ(ArcIntentHelperBridge::AppendStringToIntentHelperPackageName(
  283. empty_string),
  284. package_name + ".");
  285. }
  286. } // namespace arc