api_event_listeners_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. // Copyright 2017 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 "extensions/renderer/bindings/api_event_listeners.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/test/mock_callback.h"
  9. #include "base/values.h"
  10. #include "extensions/common/event_filter.h"
  11. #include "extensions/common/mojom/event_dispatcher.mojom.h"
  12. #include "extensions/renderer/bindings/api_binding_test.h"
  13. #include "extensions/renderer/bindings/api_binding_test_util.h"
  14. #include "extensions/renderer/bindings/api_binding_types.h"
  15. #include "extensions/renderer/bindings/listener_tracker.h"
  16. #include "testing/gmock/include/gmock/gmock.h"
  17. namespace extensions {
  18. namespace {
  19. using APIEventListenersTest = APIBindingTest;
  20. using MockEventChangeHandler = ::testing::StrictMock<
  21. base::MockCallback<APIEventListeners::ListenersUpdated>>;
  22. const char kFunction[] = "(function() {})";
  23. const char kEvent[] = "event";
  24. const char kContextOwner[] = "context";
  25. APIEventListeners::ContextOwnerIdGetter CreateContextOwnerIdGetter() {
  26. return base::BindRepeating(
  27. [](v8::Local<v8::Context>) { return std::string(kContextOwner); });
  28. }
  29. } // namespace
  30. // Test unfiltered listeners.
  31. TEST_F(APIEventListenersTest, UnfilteredListeners) {
  32. v8::HandleScope handle_scope(isolate());
  33. v8::Local<v8::Context> context = MainContext();
  34. MockEventChangeHandler handler;
  35. ListenerTracker tracker;
  36. UnfilteredEventListeners listeners(handler.Get(), kEvent,
  37. CreateContextOwnerIdGetter(),
  38. binding::kNoListenerMax, true, &tracker);
  39. // Starting out, there should be no listeners.
  40. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  41. EXPECT_EQ(0u, listeners.GetNumListeners());
  42. EXPECT_FALSE(listeners.HasListener(function_a));
  43. std::string error;
  44. v8::Local<v8::Object> filter;
  45. // Adding a new listener should trigger the callback (0 -> 1).
  46. EXPECT_CALL(handler, Run(kEvent,
  47. binding::EventListenersChanged::
  48. kFirstUnfilteredListenerForContextOwnerAdded,
  49. nullptr, true, context));
  50. EXPECT_TRUE(listeners.AddListener(function_a, filter, context, &error));
  51. ::testing::Mock::VerifyAndClearExpectations(&handler);
  52. // function_a should be registered as a listener, and should be returned when
  53. // we get the listeners.
  54. EXPECT_TRUE(listeners.HasListener(function_a));
  55. EXPECT_EQ(1u, listeners.GetNumListeners());
  56. EXPECT_THAT(listeners.GetListeners(nullptr, context),
  57. testing::UnorderedElementsAre(function_a));
  58. // Trying to add function_a again should have no effect.
  59. EXPECT_FALSE(listeners.AddListener(function_a, filter, context, &error));
  60. EXPECT_TRUE(listeners.HasListener(function_a));
  61. EXPECT_EQ(1u, listeners.GetNumListeners());
  62. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  63. // We should not yet have function_b registered, and trying to remove it
  64. // should have no effect.
  65. EXPECT_FALSE(listeners.HasListener(function_b));
  66. listeners.RemoveListener(function_b, context);
  67. EXPECT_EQ(1u, listeners.GetNumListeners());
  68. EXPECT_THAT(listeners.GetListeners(nullptr, context),
  69. testing::UnorderedElementsAre(function_a));
  70. // Add function_b; there should now be two listeners, and both should be
  71. // returned when we get the listeners. However, the callback shouldn't be
  72. // triggered, since this isn't a 0 -> 1 or 1 -> 0 transition.
  73. EXPECT_TRUE(listeners.AddListener(function_b, filter, context, &error));
  74. EXPECT_TRUE(listeners.HasListener(function_b));
  75. EXPECT_EQ(2u, listeners.GetNumListeners());
  76. EXPECT_THAT(listeners.GetListeners(nullptr, context),
  77. testing::UnorderedElementsAre(function_a, function_b));
  78. // Remove function_a; there should now be only one listener. The callback
  79. // shouldn't be triggered.
  80. listeners.RemoveListener(function_a, context);
  81. EXPECT_FALSE(listeners.HasListener(function_a));
  82. EXPECT_EQ(1u, listeners.GetNumListeners());
  83. EXPECT_THAT(listeners.GetListeners(nullptr, context),
  84. testing::UnorderedElementsAre(function_b));
  85. // Remove function_b (the final listener). No more listeners should remain.
  86. EXPECT_CALL(handler, Run(kEvent,
  87. binding::EventListenersChanged::
  88. kLastUnfilteredListenerForContextOwnerRemoved,
  89. nullptr, true, context));
  90. listeners.RemoveListener(function_b, context);
  91. ::testing::Mock::VerifyAndClearExpectations(&handler);
  92. EXPECT_FALSE(listeners.HasListener(function_b));
  93. EXPECT_EQ(0u, listeners.GetNumListeners());
  94. EXPECT_TRUE(listeners.GetListeners(nullptr, context).empty());
  95. }
  96. // Tests the invalidation of unfiltered listeners.
  97. TEST_F(APIEventListenersTest, UnfilteredListenersInvalidation) {
  98. v8::HandleScope handle_scope(isolate());
  99. v8::Local<v8::Context> context = MainContext();
  100. MockEventChangeHandler handler;
  101. ListenerTracker tracker;
  102. UnfilteredEventListeners listeners(handler.Get(), kEvent,
  103. CreateContextOwnerIdGetter(),
  104. binding::kNoListenerMax, true, &tracker);
  105. listeners.Invalidate(context);
  106. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  107. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  108. std::string error;
  109. v8::Local<v8::Object> filter;
  110. EXPECT_CALL(handler, Run(kEvent,
  111. binding::EventListenersChanged::
  112. kFirstUnfilteredListenerForContextOwnerAdded,
  113. nullptr, true, context));
  114. EXPECT_TRUE(listeners.AddListener(function_a, filter, context, &error));
  115. ::testing::Mock::VerifyAndClearExpectations(&handler);
  116. EXPECT_TRUE(listeners.AddListener(function_b, filter, context, &error));
  117. EXPECT_CALL(handler, Run(kEvent,
  118. binding::EventListenersChanged::
  119. kLastUnfilteredListenerForContextOwnerRemoved,
  120. nullptr, false, context));
  121. listeners.Invalidate(context);
  122. ::testing::Mock::VerifyAndClearExpectations(&handler);
  123. EXPECT_EQ(0u, listeners.GetNumListeners());
  124. }
  125. // Tests that unfiltered listeners ignore the filtering info.
  126. TEST_F(APIEventListenersTest, UnfilteredListenersIgnoreFilteringInfo) {
  127. v8::HandleScope handle_scope(isolate());
  128. v8::Local<v8::Context> context = MainContext();
  129. ListenerTracker tracker;
  130. UnfilteredEventListeners listeners(base::DoNothing(), kEvent,
  131. CreateContextOwnerIdGetter(),
  132. binding::kNoListenerMax, true, &tracker);
  133. v8::Local<v8::Function> function = FunctionFromString(context, kFunction);
  134. std::string error;
  135. v8::Local<v8::Object> filter;
  136. EXPECT_TRUE(listeners.AddListener(function, filter, context, &error));
  137. mojom::EventFilteringInfoPtr filtering_info =
  138. mojom::EventFilteringInfo::New();
  139. filtering_info->url = GURL("http://example.com/foo");
  140. EXPECT_THAT(listeners.GetListeners(std::move(filtering_info), context),
  141. testing::UnorderedElementsAre(function));
  142. }
  143. TEST_F(APIEventListenersTest, UnfilteredListenersMaxListenersTest) {
  144. v8::HandleScope handle_scope(isolate());
  145. v8::Local<v8::Context> context = MainContext();
  146. ListenerTracker tracker;
  147. UnfilteredEventListeners listeners(base::DoNothing(), kEvent,
  148. CreateContextOwnerIdGetter(), 1, true,
  149. &tracker);
  150. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  151. EXPECT_EQ(0u, listeners.GetNumListeners());
  152. std::string error;
  153. v8::Local<v8::Object> filter;
  154. EXPECT_TRUE(listeners.AddListener(function_a, filter, context, &error));
  155. EXPECT_TRUE(listeners.HasListener(function_a));
  156. EXPECT_EQ(1u, listeners.GetNumListeners());
  157. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  158. EXPECT_FALSE(listeners.AddListener(function_b, filter, context, &error));
  159. EXPECT_FALSE(error.empty());
  160. EXPECT_FALSE(listeners.HasListener(function_b));
  161. EXPECT_TRUE(listeners.HasListener(function_a));
  162. EXPECT_EQ(1u, listeners.GetNumListeners());
  163. }
  164. TEST_F(APIEventListenersTest, UnfilteredListenersLazyListeners) {
  165. v8::HandleScope handle_scope(isolate());
  166. v8::Local<v8::Context> context = MainContext();
  167. ListenerTracker tracker;
  168. MockEventChangeHandler handler;
  169. UnfilteredEventListeners listeners(handler.Get(), kEvent,
  170. CreateContextOwnerIdGetter(),
  171. binding::kNoListenerMax, false, &tracker);
  172. v8::Local<v8::Function> listener = FunctionFromString(context, kFunction);
  173. std::string error;
  174. EXPECT_CALL(handler, Run(kEvent,
  175. binding::EventListenersChanged::
  176. kFirstUnfilteredListenerForContextOwnerAdded,
  177. nullptr, false, context));
  178. listeners.AddListener(listener, v8::Local<v8::Object>(), context, &error);
  179. ::testing::Mock::VerifyAndClearExpectations(&handler);
  180. EXPECT_CALL(handler, Run(kEvent,
  181. binding::EventListenersChanged::
  182. kLastUnfilteredListenerForContextOwnerRemoved,
  183. nullptr, false, context));
  184. listeners.RemoveListener(listener, context);
  185. ::testing::Mock::VerifyAndClearExpectations(&handler);
  186. }
  187. // Tests filtered listeners.
  188. TEST_F(APIEventListenersTest, FilteredListeners) {
  189. v8::HandleScope handle_scope(isolate());
  190. v8::Local<v8::Context> context = MainContext();
  191. MockEventChangeHandler handler;
  192. ListenerTracker tracker;
  193. FilteredEventListeners listeners(handler.Get(), kEvent,
  194. CreateContextOwnerIdGetter(),
  195. binding::kNoListenerMax, true, &tracker);
  196. // Starting out, there should be no listeners registered.
  197. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  198. EXPECT_EQ(0u, listeners.GetNumListeners());
  199. EXPECT_EQ(
  200. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  201. kEvent));
  202. EXPECT_FALSE(listeners.HasListener(function_a));
  203. v8::Local<v8::Object> empty_filter;
  204. std::string error;
  205. // Register function_a with no filter; this is equivalent to registering for
  206. // all events. The callback should be triggered since this is a 0 -> 1
  207. // transition.
  208. // Note that we don't test the passed filter here. This is mostly because it's
  209. // a pain to match against a DictionaryValue (which doesn't have an
  210. // operator==).
  211. EXPECT_CALL(handler, Run(kEvent,
  212. binding::EventListenersChanged::
  213. kFirstListenerWithFilterForContextOwnerAdded,
  214. testing::NotNull(), true, context));
  215. EXPECT_TRUE(listeners.AddListener(function_a, empty_filter, context, &error));
  216. ::testing::Mock::VerifyAndClearExpectations(&handler);
  217. // function_a should be registered, and should be returned when we get the
  218. // listeners.
  219. EXPECT_TRUE(listeners.HasListener(function_a));
  220. EXPECT_EQ(1u, listeners.GetNumListeners());
  221. EXPECT_THAT(listeners.GetListeners(nullptr, context),
  222. testing::UnorderedElementsAre(function_a));
  223. // It should also be registered in the event filter.
  224. EXPECT_EQ(
  225. 1, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  226. kEvent));
  227. // Since function_a has no filter, associating a specific url should still
  228. // return function_a.
  229. mojom::EventFilteringInfo filtering_info_match;
  230. filtering_info_match.url = GURL("http://example.com/foo");
  231. EXPECT_THAT(listeners.GetListeners(filtering_info_match.Clone(), context),
  232. testing::UnorderedElementsAre(function_a));
  233. // Trying to add function_a again should have no effect.
  234. EXPECT_FALSE(
  235. listeners.AddListener(function_a, empty_filter, context, &error));
  236. EXPECT_TRUE(listeners.HasListener(function_a));
  237. EXPECT_EQ(1u, listeners.GetNumListeners());
  238. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  239. // function_b should not yet be registered, and trying to remove it should
  240. // have no effect.
  241. EXPECT_FALSE(listeners.HasListener(function_b));
  242. listeners.RemoveListener(function_b, context);
  243. EXPECT_EQ(1u, listeners.GetNumListeners());
  244. EXPECT_THAT(listeners.GetListeners(nullptr, context),
  245. testing::UnorderedElementsAre(function_a));
  246. // Register function_b with a filter for pathContains: 'foo'. Unlike
  247. // unfiltered listeners, this *should* trigger the callback, since there is
  248. // no other listener registered with this same filter.
  249. v8::Local<v8::Object> path_filter;
  250. {
  251. v8::Local<v8::Value> val =
  252. V8ValueFromScriptSource(context, "({url: [{pathContains: 'foo'}]})");
  253. ASSERT_TRUE(val->IsObject());
  254. path_filter = val.As<v8::Object>();
  255. }
  256. EXPECT_CALL(handler, Run(kEvent,
  257. binding::EventListenersChanged::
  258. kFirstListenerWithFilterForContextOwnerAdded,
  259. testing::NotNull(), true, context));
  260. EXPECT_TRUE(listeners.AddListener(function_b, path_filter, context, &error));
  261. ::testing::Mock::VerifyAndClearExpectations(&handler);
  262. // function_b should be present.
  263. EXPECT_TRUE(listeners.HasListener(function_b));
  264. EXPECT_EQ(2u, listeners.GetNumListeners());
  265. EXPECT_EQ(
  266. 2, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  267. kEvent));
  268. // function_b should ignore calls that don't specify an url, since they, by
  269. // definition, don't match.
  270. EXPECT_THAT(listeners.GetListeners(nullptr, context),
  271. testing::UnorderedElementsAre(function_a));
  272. // function_b should be included for matching urls...
  273. EXPECT_THAT(listeners.GetListeners(filtering_info_match.Clone(), context),
  274. testing::UnorderedElementsAre(function_a, function_b));
  275. // ... but not urls that don't match.
  276. mojom::EventFilteringInfo filtering_info_no_match;
  277. filtering_info_no_match.url = GURL("http://example.com/bar");
  278. EXPECT_THAT(listeners.GetListeners(filtering_info_no_match.Clone(), context),
  279. testing::UnorderedElementsAre(function_a));
  280. // Remove function_a. Since filtered listeners notify whenever there's a
  281. // change in listeners registered with a specific filter, this should trigger
  282. // the callback.
  283. EXPECT_CALL(handler, Run(kEvent,
  284. binding::EventListenersChanged::
  285. kLastListenerWithFilterForContextOwnerRemoved,
  286. testing::NotNull(), true, context));
  287. listeners.RemoveListener(function_a, context);
  288. ::testing::Mock::VerifyAndClearExpectations(&handler);
  289. EXPECT_FALSE(listeners.HasListener(function_a));
  290. EXPECT_EQ(1u, listeners.GetNumListeners());
  291. EXPECT_EQ(
  292. 1, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  293. kEvent));
  294. // function_b should be the only listener remaining, so we shouldn't find
  295. // any listeners for events without matching filters.
  296. EXPECT_TRUE(listeners.GetListeners(nullptr, context).empty());
  297. EXPECT_THAT(listeners.GetListeners(filtering_info_match.Clone(), context),
  298. testing::UnorderedElementsAre(function_b));
  299. EXPECT_TRUE(
  300. listeners.GetListeners(filtering_info_no_match.Clone(), context).empty());
  301. // Remove function_b. No listeners should remain.
  302. EXPECT_CALL(handler, Run(kEvent,
  303. binding::EventListenersChanged::
  304. kLastListenerWithFilterForContextOwnerRemoved,
  305. testing::NotNull(), true, context));
  306. listeners.RemoveListener(function_b, context);
  307. ::testing::Mock::VerifyAndClearExpectations(&handler);
  308. EXPECT_FALSE(listeners.HasListener(function_b));
  309. EXPECT_EQ(0u, listeners.GetNumListeners());
  310. EXPECT_TRUE(listeners.GetListeners(nullptr, context).empty());
  311. EXPECT_TRUE(
  312. listeners.GetListeners(filtering_info_match.Clone(), context).empty());
  313. EXPECT_EQ(
  314. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  315. kEvent));
  316. }
  317. // Tests that adding multiple listeners with the same filter doesn't trigger
  318. // the update callback.
  319. TEST_F(APIEventListenersTest,
  320. UnfilteredListenersWithSameFilterDontTriggerUpdate) {
  321. v8::HandleScope handle_scope(isolate());
  322. v8::Local<v8::Context> context = MainContext();
  323. MockEventChangeHandler handler;
  324. ListenerTracker tracker;
  325. FilteredEventListeners listeners(handler.Get(), kEvent,
  326. CreateContextOwnerIdGetter(),
  327. binding::kNoListenerMax, true, &tracker);
  328. auto get_filter = [context]() {
  329. return V8ValueFromScriptSource(context, "({url: [{pathContains: 'foo'}]})")
  330. .As<v8::Object>();
  331. };
  332. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  333. std::string error;
  334. EXPECT_CALL(handler, Run(kEvent,
  335. binding::EventListenersChanged::
  336. kFirstListenerWithFilterForContextOwnerAdded,
  337. testing::NotNull(), true, context));
  338. EXPECT_TRUE(listeners.AddListener(function_a, get_filter(), context, &error));
  339. ::testing::Mock::VerifyAndClearExpectations(&handler);
  340. EXPECT_EQ(
  341. 1, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  342. kEvent));
  343. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  344. v8::Local<v8::Function> function_c = FunctionFromString(context, kFunction);
  345. EXPECT_TRUE(listeners.AddListener(function_b, get_filter(), context, &error));
  346. EXPECT_TRUE(listeners.AddListener(function_c, get_filter(), context, &error));
  347. EXPECT_EQ(3u, listeners.GetNumListeners());
  348. EXPECT_EQ(
  349. 3, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  350. kEvent));
  351. mojom::EventFilteringInfoPtr filtering_info_match =
  352. mojom::EventFilteringInfo::New();
  353. filtering_info_match->url = GURL("http://example.com/foo");
  354. EXPECT_THAT(
  355. listeners.GetListeners(std::move(filtering_info_match), context),
  356. testing::UnorderedElementsAre(function_a, function_b, function_c));
  357. listeners.RemoveListener(function_c, context);
  358. listeners.RemoveListener(function_b, context);
  359. EXPECT_CALL(handler, Run(kEvent,
  360. binding::EventListenersChanged::
  361. kLastListenerWithFilterForContextOwnerRemoved,
  362. testing::NotNull(), true, context));
  363. listeners.RemoveListener(function_a, context);
  364. ::testing::Mock::VerifyAndClearExpectations(&handler);
  365. EXPECT_EQ(
  366. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  367. kEvent));
  368. }
  369. // Tests that trying to add a listener with an invalid filter fails.
  370. TEST_F(APIEventListenersTest, UnfilteredListenersError) {
  371. v8::HandleScope handle_scope(isolate());
  372. v8::Local<v8::Context> context = MainContext();
  373. ListenerTracker tracker;
  374. FilteredEventListeners listeners(base::DoNothing(), kEvent,
  375. CreateContextOwnerIdGetter(),
  376. binding::kNoListenerMax, true, &tracker);
  377. v8::Local<v8::Object> invalid_filter =
  378. V8ValueFromScriptSource(context, "({url: 'some string'})")
  379. .As<v8::Object>();
  380. v8::Local<v8::Function> function = FunctionFromString(context, kFunction);
  381. std::string error;
  382. EXPECT_FALSE(
  383. listeners.AddListener(function, invalid_filter, context, &error));
  384. EXPECT_FALSE(error.empty());
  385. }
  386. // Tests that adding listeners for multiple different events is correctly
  387. // recorded in the EventFilter.
  388. TEST_F(APIEventListenersTest, MultipleUnfilteredListenerEvents) {
  389. v8::HandleScope handle_scope(isolate());
  390. v8::Local<v8::Context> context = MainContext();
  391. const char kAlpha[] = "alpha";
  392. const char kBeta[] = "beta";
  393. ListenerTracker tracker;
  394. FilteredEventListeners listeners_a(base::DoNothing(), kAlpha,
  395. CreateContextOwnerIdGetter(),
  396. binding::kNoListenerMax, true, &tracker);
  397. FilteredEventListeners listeners_b(base::DoNothing(), kBeta,
  398. CreateContextOwnerIdGetter(),
  399. binding::kNoListenerMax, true, &tracker);
  400. EXPECT_EQ(
  401. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  402. kAlpha));
  403. EXPECT_EQ(
  404. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  405. kBeta));
  406. std::string error;
  407. v8::Local<v8::Object> filter;
  408. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  409. EXPECT_TRUE(listeners_a.AddListener(function_a, filter, context, &error));
  410. EXPECT_EQ(
  411. 1, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  412. kAlpha));
  413. EXPECT_EQ(
  414. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  415. kBeta));
  416. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  417. EXPECT_TRUE(listeners_b.AddListener(function_b, filter, context, &error));
  418. EXPECT_EQ(
  419. 1, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  420. kAlpha));
  421. EXPECT_EQ(
  422. 1, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  423. kBeta));
  424. listeners_b.RemoveListener(function_b, context);
  425. EXPECT_EQ(
  426. 1, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  427. kAlpha));
  428. EXPECT_EQ(
  429. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  430. kBeta));
  431. listeners_a.RemoveListener(function_a, context);
  432. EXPECT_EQ(
  433. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  434. kAlpha));
  435. EXPECT_EQ(
  436. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  437. kBeta));
  438. }
  439. // Tests the invalidation of filtered listeners.
  440. TEST_F(APIEventListenersTest, FilteredListenersInvalidation) {
  441. v8::HandleScope handle_scope(isolate());
  442. v8::Local<v8::Context> context = MainContext();
  443. MockEventChangeHandler handler;
  444. ListenerTracker tracker;
  445. FilteredEventListeners listeners(handler.Get(), kEvent,
  446. CreateContextOwnerIdGetter(),
  447. binding::kNoListenerMax, true, &tracker);
  448. listeners.Invalidate(context);
  449. v8::Local<v8::Object> empty_filter;
  450. v8::Local<v8::Object> filter =
  451. V8ValueFromScriptSource(context, "({url: [{pathContains: 'foo'}]})")
  452. .As<v8::Object>();
  453. std::string error;
  454. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  455. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  456. v8::Local<v8::Function> function_c = FunctionFromString(context, kFunction);
  457. EXPECT_CALL(handler, Run(kEvent,
  458. binding::EventListenersChanged::
  459. kFirstListenerWithFilterForContextOwnerAdded,
  460. testing::NotNull(), true, context));
  461. EXPECT_TRUE(listeners.AddListener(function_a, empty_filter, context, &error));
  462. ::testing::Mock::VerifyAndClearExpectations(&handler);
  463. EXPECT_CALL(handler, Run(kEvent,
  464. binding::EventListenersChanged::
  465. kFirstListenerWithFilterForContextOwnerAdded,
  466. testing::NotNull(), true, context));
  467. EXPECT_TRUE(listeners.AddListener(function_b, filter, context, &error));
  468. ::testing::Mock::VerifyAndClearExpectations(&handler);
  469. EXPECT_TRUE(listeners.AddListener(function_c, filter, context, &error));
  470. // Since two listener filters are present in the list, we should be notified
  471. // of each going away when we invalidate the context.
  472. EXPECT_CALL(handler, Run(kEvent,
  473. binding::EventListenersChanged::
  474. kLastListenerWithFilterForContextOwnerRemoved,
  475. testing::NotNull(), false, context))
  476. .Times(2);
  477. listeners.Invalidate(context);
  478. ::testing::Mock::VerifyAndClearExpectations(&handler);
  479. EXPECT_EQ(0u, listeners.GetNumListeners());
  480. EXPECT_EQ(
  481. 0, tracker.event_filter_for_testing()->GetMatcherCountForEventForTesting(
  482. kEvent));
  483. }
  484. TEST_F(APIEventListenersTest, FilteredListenersMaxListenersTest) {
  485. v8::HandleScope handle_scope(isolate());
  486. v8::Local<v8::Context> context = MainContext();
  487. ListenerTracker tracker;
  488. FilteredEventListeners listeners(base::DoNothing(), kEvent,
  489. CreateContextOwnerIdGetter(), 1, true,
  490. &tracker);
  491. v8::Local<v8::Function> function_a = FunctionFromString(context, kFunction);
  492. EXPECT_EQ(0u, listeners.GetNumListeners());
  493. std::string error;
  494. v8::Local<v8::Object> filter;
  495. EXPECT_TRUE(listeners.AddListener(function_a, filter, context, &error));
  496. EXPECT_TRUE(listeners.HasListener(function_a));
  497. EXPECT_EQ(1u, listeners.GetNumListeners());
  498. v8::Local<v8::Function> function_b = FunctionFromString(context, kFunction);
  499. EXPECT_FALSE(listeners.AddListener(function_b, filter, context, &error));
  500. EXPECT_FALSE(error.empty());
  501. EXPECT_FALSE(listeners.HasListener(function_b));
  502. EXPECT_TRUE(listeners.HasListener(function_a));
  503. EXPECT_EQ(1u, listeners.GetNumListeners());
  504. }
  505. TEST_F(APIEventListenersTest, FilteredListenersLazyListeners) {
  506. v8::HandleScope handle_scope(isolate());
  507. v8::Local<v8::Context> context = MainContext();
  508. MockEventChangeHandler handler;
  509. ListenerTracker tracker;
  510. FilteredEventListeners listeners(handler.Get(), kEvent,
  511. CreateContextOwnerIdGetter(),
  512. binding::kNoListenerMax, false, &tracker);
  513. v8::Local<v8::Function> listener = FunctionFromString(context, kFunction);
  514. std::string error;
  515. EXPECT_CALL(handler, Run(kEvent,
  516. binding::EventListenersChanged::
  517. kFirstListenerWithFilterForContextOwnerAdded,
  518. testing::NotNull(), false, context));
  519. listeners.AddListener(listener, v8::Local<v8::Object>(), context, &error);
  520. ::testing::Mock::VerifyAndClearExpectations(&handler);
  521. EXPECT_CALL(handler, Run(kEvent,
  522. binding::EventListenersChanged::
  523. kLastListenerWithFilterForContextOwnerRemoved,
  524. testing::NotNull(), false, context));
  525. listeners.RemoveListener(listener, context);
  526. ::testing::Mock::VerifyAndClearExpectations(&handler);
  527. }
  528. } // namespace extensions