OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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 "chrome/browser/multi_process_notification.h" |
| 6 |
| 7 #include "base/basictypes.h" |
| 8 #include "base/compiler_specific.h" |
| 9 #include "base/environment.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/message_loop.h" |
| 12 #include "base/test/multiprocess_test.h" |
| 13 #include "base/test/test_timeouts.h" |
| 14 #include "base/time.h" |
| 15 #include "chrome/browser/browser_thread.h" |
| 16 #include "testing/multiprocess_func_list.h" |
| 17 |
| 18 #if defined(OS_MACOSX) |
| 19 // TODO(dmaclach): Remove defined(OS_MACOSX) once |
| 20 // MultiProcessNotification is implemented on Win/Linux. |
| 21 |
| 22 namespace { |
| 23 |
| 24 const char kStartedNotificationName[] = "MultiProcessTestStartedNotification"; |
| 25 const char kQuitNotificationName[] = "MultiProcessTestQuitNotification"; |
| 26 |
| 27 void SpinRunLoop(int milliseconds) { |
| 28 MessageLoop *loop = MessageLoop::current(); |
| 29 |
| 30 // Post a quit task so that this loop eventually ends and we don't hang |
| 31 // in the case of a bad test. Usually, the run loop will quit sooner than |
| 32 // that because all tests use a MultiProcessNotificationTestQuit which quits |
| 33 // the current run loop when it gets a notification. |
| 34 loop->PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask(), milliseconds); |
| 35 loop->Run(); |
| 36 } |
| 37 |
| 38 class SimpleDelegate |
| 39 : public multi_process_notification::Listener::Delegate { |
| 40 public: |
| 41 SimpleDelegate() |
| 42 : notification_received_(false), started_received_(false) { } |
| 43 virtual ~SimpleDelegate(); |
| 44 |
| 45 virtual void OnNotificationReceived( |
| 46 const std::string& name, |
| 47 multi_process_notification::Domain domain) OVERRIDE; |
| 48 virtual void OnListenerStarted( |
| 49 const std::string& name, multi_process_notification::Domain domain, |
| 50 bool success) OVERRIDE; |
| 51 |
| 52 bool WasNotificationReceived() { return notification_received_; } |
| 53 bool WasStartedReceived() { return started_received_; } |
| 54 |
| 55 private: |
| 56 bool notification_received_; |
| 57 bool started_received_; |
| 58 DISALLOW_COPY_AND_ASSIGN(SimpleDelegate); |
| 59 }; |
| 60 |
| 61 SimpleDelegate::~SimpleDelegate() { |
| 62 } |
| 63 |
| 64 void SimpleDelegate::OnNotificationReceived( |
| 65 const std::string& name, multi_process_notification::Domain domain) { |
| 66 notification_received_ = true; |
| 67 } |
| 68 |
| 69 void SimpleDelegate::OnListenerStarted( |
| 70 const std::string& name, multi_process_notification::Domain domain, |
| 71 bool success) { |
| 72 ASSERT_TRUE(success); |
| 73 started_received_ = true; |
| 74 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| 75 } |
| 76 |
| 77 class QuitterDelegate : public SimpleDelegate { |
| 78 public: |
| 79 QuitterDelegate() : SimpleDelegate() { } |
| 80 virtual ~QuitterDelegate(); |
| 81 |
| 82 virtual void OnNotificationReceived( |
| 83 const std::string& name, |
| 84 multi_process_notification::Domain domain) OVERRIDE; |
| 85 |
| 86 private: |
| 87 DISALLOW_COPY_AND_ASSIGN(QuitterDelegate); |
| 88 }; |
| 89 |
| 90 QuitterDelegate::~QuitterDelegate() { |
| 91 } |
| 92 |
| 93 void QuitterDelegate::OnNotificationReceived( |
| 94 const std::string& name, multi_process_notification::Domain domain) { |
| 95 SimpleDelegate::OnNotificationReceived(name, domain); |
| 96 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); |
| 97 } |
| 98 |
| 99 int MultiProcessNotificationMain(multi_process_notification::Domain domain) { |
| 100 BrowserThread browser_thread(BrowserThread::IO); |
| 101 base::Thread::Options options(MessageLoop::TYPE_IO, 0); |
| 102 EXPECT_TRUE(browser_thread.StartWithOptions(options)); |
| 103 MessageLoop loop; |
| 104 QuitterDelegate quitter; |
| 105 multi_process_notification::Listener listener( |
| 106 kQuitNotificationName, domain, &quitter); |
| 107 EXPECT_TRUE(listener.Start()); |
| 108 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 109 EXPECT_TRUE(quitter.WasStartedReceived()); |
| 110 EXPECT_TRUE(multi_process_notification::Post(kStartedNotificationName, |
| 111 domain)); |
| 112 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 113 EXPECT_TRUE(quitter.WasNotificationReceived()); |
| 114 return 0; |
| 115 } |
| 116 |
| 117 } // namespace |
| 118 |
| 119 class MultiProcessNotificationTest : public base::MultiProcessTest { |
| 120 public: |
| 121 MultiProcessNotificationTest(); |
| 122 |
| 123 void PostNotificationTest(multi_process_notification::Domain domain); |
| 124 void CrossPostNotificationTest(multi_process_notification::Domain domain); |
| 125 |
| 126 static void SetUpTestCase(); |
| 127 static void TearDownTestCase(); |
| 128 |
| 129 private: |
| 130 MessageLoop loop_; |
| 131 static BrowserThread* g_io_thread; |
| 132 }; |
| 133 |
| 134 MultiProcessNotificationTest::MultiProcessNotificationTest() { |
| 135 } |
| 136 |
| 137 BrowserThread* MultiProcessNotificationTest::g_io_thread = NULL; |
| 138 |
| 139 void MultiProcessNotificationTest::SetUpTestCase() { |
| 140 g_io_thread = new BrowserThread(BrowserThread::IO); |
| 141 base::Thread::Options options(MessageLoop::TYPE_IO, 0); |
| 142 ASSERT_TRUE(g_io_thread->StartWithOptions(options)); |
| 143 } |
| 144 |
| 145 void MultiProcessNotificationTest::TearDownTestCase() { |
| 146 delete g_io_thread; |
| 147 } |
| 148 |
| 149 void MultiProcessNotificationTest::PostNotificationTest( |
| 150 multi_process_notification::Domain domain) { |
| 151 QuitterDelegate process_started; |
| 152 multi_process_notification::Listener listener( |
| 153 kStartedNotificationName, domain, &process_started); |
| 154 ASSERT_TRUE(listener.Start()); |
| 155 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 156 ASSERT_TRUE(process_started.WasStartedReceived()); |
| 157 std::string process_name; |
| 158 switch (domain) { |
| 159 case multi_process_notification::ProfileDomain: |
| 160 process_name = "MultiProcessProfileNotificationMain"; |
| 161 break; |
| 162 |
| 163 case multi_process_notification::UserDomain: |
| 164 process_name = "MultiProcessUserNotificationMain"; |
| 165 break; |
| 166 |
| 167 case multi_process_notification::SystemDomain: |
| 168 process_name = "MultiProcessSystemNotificationMain"; |
| 169 break; |
| 170 } |
| 171 base::ProcessHandle handle = SpawnChild(process_name, false); |
| 172 ASSERT_TRUE(handle); |
| 173 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 174 ASSERT_TRUE(process_started.WasNotificationReceived()); |
| 175 ASSERT_TRUE(multi_process_notification::Post(kQuitNotificationName, domain)); |
| 176 int exit_code = 0; |
| 177 EXPECT_TRUE(base::WaitForExitCodeWithTimeout( |
| 178 handle, &exit_code, TestTimeouts::action_max_timeout_ms())); |
| 179 } |
| 180 |
| 181 void MultiProcessNotificationTest::CrossPostNotificationTest( |
| 182 multi_process_notification::Domain domain) { |
| 183 // Check to make sure notifications sent to user domain aren't picked up |
| 184 // by system domain listeners and vice versa. |
| 185 std::string local_notification("QuitLocalNotification"); |
| 186 std::string final_notification("FinalQuitLocalNotification"); |
| 187 QuitterDelegate profile_quitter; |
| 188 QuitterDelegate user_quitter; |
| 189 QuitterDelegate system_quitter; |
| 190 QuitterDelegate final_quitter; |
| 191 multi_process_notification::Listener profile_listener( |
| 192 local_notification, multi_process_notification::ProfileDomain, |
| 193 &profile_quitter); |
| 194 multi_process_notification::Listener user_listener( |
| 195 local_notification, multi_process_notification::UserDomain, |
| 196 &user_quitter); |
| 197 multi_process_notification::Listener system_listener( |
| 198 local_notification, multi_process_notification::SystemDomain, |
| 199 &system_quitter); |
| 200 multi_process_notification::Listener final_listener( |
| 201 final_notification, multi_process_notification::UserDomain, |
| 202 &final_quitter); |
| 203 |
| 204 ASSERT_TRUE(profile_listener.Start()); |
| 205 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 206 ASSERT_TRUE(profile_quitter.WasStartedReceived()); |
| 207 ASSERT_TRUE(user_listener.Start()); |
| 208 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 209 ASSERT_TRUE(user_quitter.WasStartedReceived()); |
| 210 ASSERT_TRUE(system_listener.Start()); |
| 211 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 212 ASSERT_TRUE(system_quitter.WasStartedReceived()); |
| 213 |
| 214 ASSERT_TRUE(multi_process_notification::Post(local_notification, domain)); |
| 215 SpinRunLoop(TestTimeouts::action_timeout_ms()); |
| 216 |
| 217 // Now send out a final_notification to queue up a notification |
| 218 // after the local_notification and make sure that all listeners have had a |
| 219 // chance to process local_notification before we check to see if they |
| 220 // were called. |
| 221 ASSERT_TRUE(final_listener.Start()); |
| 222 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 223 EXPECT_TRUE(final_quitter.WasStartedReceived()); |
| 224 ASSERT_TRUE(multi_process_notification::Post( |
| 225 final_notification, multi_process_notification::UserDomain)); |
| 226 SpinRunLoop(TestTimeouts::action_timeout_ms()); |
| 227 ASSERT_TRUE(final_quitter.WasNotificationReceived()); |
| 228 switch (domain) { |
| 229 case multi_process_notification::ProfileDomain: |
| 230 ASSERT_TRUE(profile_quitter.WasNotificationReceived()); |
| 231 ASSERT_FALSE(user_quitter.WasNotificationReceived()); |
| 232 ASSERT_FALSE(system_quitter.WasNotificationReceived()); |
| 233 break; |
| 234 |
| 235 case multi_process_notification::UserDomain: |
| 236 ASSERT_FALSE(profile_quitter.WasNotificationReceived()); |
| 237 ASSERT_TRUE(user_quitter.WasNotificationReceived()); |
| 238 ASSERT_FALSE(system_quitter.WasNotificationReceived()); |
| 239 break; |
| 240 |
| 241 case multi_process_notification::SystemDomain: |
| 242 ASSERT_FALSE(profile_quitter.WasNotificationReceived()); |
| 243 ASSERT_FALSE(user_quitter.WasNotificationReceived()); |
| 244 ASSERT_TRUE(system_quitter.WasNotificationReceived()); |
| 245 break; |
| 246 } |
| 247 } |
| 248 |
| 249 TEST_F(MultiProcessNotificationTest, BasicCreationTest) { |
| 250 QuitterDelegate quitter; |
| 251 multi_process_notification::Listener local_listener( |
| 252 "BasicCreationTest", multi_process_notification::UserDomain, &quitter); |
| 253 ASSERT_TRUE(local_listener.Start()); |
| 254 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 255 ASSERT_TRUE(quitter.WasStartedReceived()); |
| 256 multi_process_notification::Listener system_listener( |
| 257 "BasicCreationTest", multi_process_notification::SystemDomain, &quitter); |
| 258 ASSERT_TRUE(system_listener.Start()); |
| 259 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 260 ASSERT_TRUE(quitter.WasStartedReceived()); |
| 261 } |
| 262 |
| 263 TEST_F(MultiProcessNotificationTest, PostInProcessNotification) { |
| 264 std::string local_notification("QuitLocalNotification"); |
| 265 QuitterDelegate quitter; |
| 266 multi_process_notification::Listener listener( |
| 267 local_notification, multi_process_notification::UserDomain, &quitter); |
| 268 |
| 269 ASSERT_TRUE(listener.Start()); |
| 270 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 271 ASSERT_TRUE(quitter.WasStartedReceived()); |
| 272 ASSERT_TRUE(multi_process_notification::Post( |
| 273 local_notification, multi_process_notification::UserDomain)); |
| 274 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 275 ASSERT_TRUE(quitter.WasNotificationReceived()); |
| 276 } |
| 277 |
| 278 TEST_F(MultiProcessNotificationTest, MultiListener) { |
| 279 std::string local_notification("LocalNotification"); |
| 280 std::string quit_local_notification("QuitLocalNotification"); |
| 281 |
| 282 SimpleDelegate delegate1; |
| 283 SimpleDelegate delegate2; |
| 284 multi_process_notification::Listener local_listener1( |
| 285 local_notification, multi_process_notification::UserDomain, |
| 286 &delegate1); |
| 287 multi_process_notification::Listener local_listener2( |
| 288 local_notification, multi_process_notification::UserDomain, |
| 289 &delegate2); |
| 290 |
| 291 QuitterDelegate quitter; |
| 292 |
| 293 multi_process_notification::Listener quit_listener(quit_local_notification, |
| 294 multi_process_notification::UserDomain, &quitter); |
| 295 |
| 296 ASSERT_TRUE(local_listener1.Start()); |
| 297 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 298 ASSERT_TRUE(delegate1.WasStartedReceived()); |
| 299 ASSERT_TRUE(local_listener2.Start()); |
| 300 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 301 ASSERT_TRUE(delegate2.WasStartedReceived()); |
| 302 ASSERT_TRUE(quit_listener.Start()); |
| 303 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 304 ASSERT_TRUE(quitter.WasStartedReceived()); |
| 305 ASSERT_TRUE(multi_process_notification::Post( |
| 306 local_notification, multi_process_notification::UserDomain)); |
| 307 ASSERT_TRUE(multi_process_notification::Post( |
| 308 quit_local_notification, multi_process_notification::UserDomain)); |
| 309 SpinRunLoop(TestTimeouts::action_max_timeout_ms()); |
| 310 ASSERT_TRUE(delegate1.WasNotificationReceived()); |
| 311 ASSERT_TRUE(delegate2.WasNotificationReceived()); |
| 312 ASSERT_TRUE(quitter.WasNotificationReceived()); |
| 313 } |
| 314 |
| 315 TEST_F(MultiProcessNotificationTest, PostProfileNotification) { |
| 316 PostNotificationTest(multi_process_notification::ProfileDomain); |
| 317 } |
| 318 |
| 319 TEST_F(MultiProcessNotificationTest, PostUserNotification) { |
| 320 PostNotificationTest(multi_process_notification::UserDomain); |
| 321 } |
| 322 |
| 323 TEST_F(MultiProcessNotificationTest, PostSystemNotification) { |
| 324 PostNotificationTest(multi_process_notification::SystemDomain); |
| 325 } |
| 326 |
| 327 TEST_F(MultiProcessNotificationTest, ProfileCrossDomainPosting) { |
| 328 CrossPostNotificationTest(multi_process_notification::ProfileDomain); |
| 329 } |
| 330 |
| 331 TEST_F(MultiProcessNotificationTest, UserCrossDomainPosting) { |
| 332 CrossPostNotificationTest(multi_process_notification::UserDomain); |
| 333 } |
| 334 |
| 335 TEST_F(MultiProcessNotificationTest, SystemCrossDomainPosting) { |
| 336 CrossPostNotificationTest(multi_process_notification::SystemDomain); |
| 337 } |
| 338 |
| 339 MULTIPROCESS_TEST_MAIN(MultiProcessProfileNotificationMain) { |
| 340 return MultiProcessNotificationMain( |
| 341 multi_process_notification::ProfileDomain); |
| 342 } |
| 343 |
| 344 MULTIPROCESS_TEST_MAIN(MultiProcessUserNotificationMain) { |
| 345 return MultiProcessNotificationMain(multi_process_notification::UserDomain); |
| 346 } |
| 347 |
| 348 MULTIPROCESS_TEST_MAIN(MultiProcessSystemNotificationMain) { |
| 349 return MultiProcessNotificationMain(multi_process_notification::SystemDomain); |
| 350 } |
| 351 |
| 352 #endif // defined(OS_MACOSX) |
OLD | NEW |