1 // Copyright 2013 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 "extensions/browser/event_router.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/compiler_specific.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/values.h" 13 #include "content/public/browser/notification_service.h" 14 #include "extensions/browser/event_listener_map.h" 15 #include "extensions/browser/extensions_test.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 namespace extensions { 19 20 namespace { 21 22 // A simple mock to keep track of listener additions and removals. 23 class MockEventRouterObserver : public EventRouter::Observer { 24 public: 25 MockEventRouterObserver() 26 : listener_added_count_(0), 27 listener_removed_count_(0) {} 28 virtual ~MockEventRouterObserver() {} 29 30 int listener_added_count() const { return listener_added_count_; } 31 int listener_removed_count() const { return listener_removed_count_; } 32 const std::string& last_event_name() const { return last_event_name_; } 33 34 void Reset() { 35 listener_added_count_ = 0; 36 listener_removed_count_ = 0; 37 last_event_name_.clear(); 38 } 39 40 // EventRouter::Observer overrides: 41 virtual void OnListenerAdded(const EventListenerInfo& details) OVERRIDE { 42 listener_added_count_++; 43 last_event_name_ = details.event_name; 44 } 45 46 virtual void OnListenerRemoved(const EventListenerInfo& details) OVERRIDE { 47 listener_removed_count_++; 48 last_event_name_ = details.event_name; 49 } 50 51 private: 52 int listener_added_count_; 53 int listener_removed_count_; 54 std::string last_event_name_; 55 56 DISALLOW_COPY_AND_ASSIGN(MockEventRouterObserver); 57 }; 58 59 typedef base::Callback<scoped_ptr<EventListener>( 60 const std::string&, // event_name 61 content::RenderProcessHost*, // process 62 base::DictionaryValue* // filter (takes ownership) 63 )> EventListenerConstructor; 64 65 scoped_ptr<EventListener> CreateEventListenerForExtension( 66 const std::string& extension_id, 67 const std::string& event_name, 68 content::RenderProcessHost* process, 69 base::DictionaryValue* filter) { 70 return EventListener::ForExtension( 71 event_name, extension_id, process, make_scoped_ptr(filter)); 72 } 73 74 scoped_ptr<EventListener> CreateEventListenerForURL( 75 const GURL& listener_url, 76 const std::string& event_name, 77 content::RenderProcessHost* process, 78 base::DictionaryValue* filter) { 79 return EventListener::ForURL( 80 event_name, listener_url, process, make_scoped_ptr(filter)); 81 } 82 83 } // namespace 84 85 class EventRouterTest : public ExtensionsTest { 86 public: 87 EventRouterTest() 88 : notification_service_(content::NotificationService::Create()) {} 89 90 protected: 91 // Tests adding and removing observers from EventRouter. 92 void RunEventRouterObserverTest(const EventListenerConstructor& constructor); 93 94 private: 95 scoped_ptr<content::NotificationService> notification_service_; 96 97 DISALLOW_COPY_AND_ASSIGN(EventRouterTest); 98 }; 99 100 TEST_F(EventRouterTest, GetBaseEventName) { 101 // Normal event names are passed through unchanged. 102 EXPECT_EQ("foo.onBar", EventRouter::GetBaseEventName("foo.onBar")); 103 104 // Sub-events are converted to the part before the slash. 105 EXPECT_EQ("foo.onBar", EventRouter::GetBaseEventName("foo.onBar/123")); 106 } 107 108 // Tests adding and removing observers from EventRouter. 109 void EventRouterTest::RunEventRouterObserverTest( 110 const EventListenerConstructor& constructor) { 111 EventRouter router(NULL, NULL); 112 scoped_ptr<EventListener> listener = 113 constructor.Run("event_name", NULL, new base::DictionaryValue()); 114 115 // Add/remove works without any observers. 116 router.OnListenerAdded(listener.get()); 117 router.OnListenerRemoved(listener.get()); 118 119 // Register observers that both match and don't match the event above. 120 MockEventRouterObserver matching_observer; 121 router.RegisterObserver(&matching_observer, "event_name"); 122 MockEventRouterObserver non_matching_observer; 123 router.RegisterObserver(&non_matching_observer, "other"); 124 125 // Adding a listener notifies the appropriate observers. 126 router.OnListenerAdded(listener.get()); 127 EXPECT_EQ(1, matching_observer.listener_added_count()); 128 EXPECT_EQ(0, non_matching_observer.listener_added_count()); 129 130 // Removing a listener notifies the appropriate observers. 131 router.OnListenerRemoved(listener.get()); 132 EXPECT_EQ(1, matching_observer.listener_removed_count()); 133 EXPECT_EQ(0, non_matching_observer.listener_removed_count()); 134 135 // Adding the listener again notifies again. 136 router.OnListenerAdded(listener.get()); 137 EXPECT_EQ(2, matching_observer.listener_added_count()); 138 EXPECT_EQ(0, non_matching_observer.listener_added_count()); 139 140 // Removing the listener again notifies again. 141 router.OnListenerRemoved(listener.get()); 142 EXPECT_EQ(2, matching_observer.listener_removed_count()); 143 EXPECT_EQ(0, non_matching_observer.listener_removed_count()); 144 145 // Adding a listener with a sub-event notifies the main observer with 146 // proper details. 147 matching_observer.Reset(); 148 scoped_ptr<EventListener> sub_event_listener = 149 constructor.Run("event_name/1", NULL, new base::DictionaryValue()); 150 router.OnListenerAdded(sub_event_listener.get()); 151 EXPECT_EQ(1, matching_observer.listener_added_count()); 152 EXPECT_EQ(0, matching_observer.listener_removed_count()); 153 EXPECT_EQ("event_name/1", matching_observer.last_event_name()); 154 155 // Ditto for removing the listener. 156 matching_observer.Reset(); 157 router.OnListenerRemoved(sub_event_listener.get()); 158 EXPECT_EQ(0, matching_observer.listener_added_count()); 159 EXPECT_EQ(1, matching_observer.listener_removed_count()); 160 EXPECT_EQ("event_name/1", matching_observer.last_event_name()); 161 } 162 163 TEST_F(EventRouterTest, EventRouterObserverForExtensions) { 164 RunEventRouterObserverTest( 165 base::Bind(&CreateEventListenerForExtension, "extension_id")); 166 } 167 168 TEST_F(EventRouterTest, EventRouterObserverForURLs) { 169 RunEventRouterObserverTest( 170 base::Bind(&CreateEventListenerForURL, GURL("http://google.com/path"))); 171 } 172 173 } // namespace extensions 174