diff options
author | dmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-14 05:36:25 +0000 |
---|---|---|
committer | dmaclach@chromium.org <dmaclach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-14 05:36:25 +0000 |
commit | 502b937c355c991645a3b88bf59d678862b7b8ff (patch) | |
tree | e47ac89de6e31c38d32865bb936a2392d619e49f /chrome/browser/multi_process_notification_unittest.cc | |
parent | 1b0d7c5bf0c166886b842c0044bb3192a751d212 (diff) | |
download | chromium_src-502b937c355c991645a3b88bf59d678862b7b8ff.zip chromium_src-502b937c355c991645a3b88bf59d678862b7b8ff.tar.gz chromium_src-502b937c355c991645a3b88bf59d678862b7b8ff.tar.bz2 |
Add multi-process notification class.
This is a platform abstraction for a notification that can be sent between processes.
Currently only implemented on Mac. Windows and Linux will be done in a future CL.
BUG=NONE
TEST=BUILD
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=70629
Review URL: http://codereview.chromium.org/5970015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71418 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/multi_process_notification_unittest.cc')
-rw-r--r-- | chrome/browser/multi_process_notification_unittest.cc | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/chrome/browser/multi_process_notification_unittest.cc b/chrome/browser/multi_process_notification_unittest.cc new file mode 100644 index 0000000..8c42fcb --- /dev/null +++ b/chrome/browser/multi_process_notification_unittest.cc @@ -0,0 +1,352 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/multi_process_notification.h" + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/environment.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/test/multiprocess_test.h" +#include "base/test/test_timeouts.h" +#include "base/time.h" +#include "chrome/browser/browser_thread.h" +#include "testing/multiprocess_func_list.h" + +#if defined(OS_MACOSX) +// TODO(dmaclach): Remove defined(OS_MACOSX) once +// MultiProcessNotification is implemented on Win/Linux. + +namespace { + +const char kStartedNotificationName[] = "MultiProcessTestStartedNotification"; +const char kQuitNotificationName[] = "MultiProcessTestQuitNotification"; + +void SpinRunLoop(int milliseconds) { + MessageLoop *loop = MessageLoop::current(); + + // Post a quit task so that this loop eventually ends and we don't hang + // in the case of a bad test. Usually, the run loop will quit sooner than + // that because all tests use a MultiProcessNotificationTestQuit which quits + // the current run loop when it gets a notification. + loop->PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask(), milliseconds); + loop->Run(); +} + +class SimpleDelegate + : public multi_process_notification::Listener::Delegate { + public: + SimpleDelegate() + : notification_received_(false), started_received_(false) { } + virtual ~SimpleDelegate(); + + virtual void OnNotificationReceived( + const std::string& name, + multi_process_notification::Domain domain) OVERRIDE; + virtual void OnListenerStarted( + const std::string& name, multi_process_notification::Domain domain, + bool success) OVERRIDE; + + bool WasNotificationReceived() { return notification_received_; } + bool WasStartedReceived() { return started_received_; } + + private: + bool notification_received_; + bool started_received_; + DISALLOW_COPY_AND_ASSIGN(SimpleDelegate); +}; + +SimpleDelegate::~SimpleDelegate() { +} + +void SimpleDelegate::OnNotificationReceived( + const std::string& name, multi_process_notification::Domain domain) { + notification_received_ = true; +} + +void SimpleDelegate::OnListenerStarted( + const std::string& name, multi_process_notification::Domain domain, + bool success) { + ASSERT_TRUE(success); + started_received_ = true; + MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +} + +class QuitterDelegate : public SimpleDelegate { + public: + QuitterDelegate() : SimpleDelegate() { } + virtual ~QuitterDelegate(); + + virtual void OnNotificationReceived( + const std::string& name, + multi_process_notification::Domain domain) OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(QuitterDelegate); +}; + +QuitterDelegate::~QuitterDelegate() { +} + +void QuitterDelegate::OnNotificationReceived( + const std::string& name, multi_process_notification::Domain domain) { + SimpleDelegate::OnNotificationReceived(name, domain); + MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +} + +int MultiProcessNotificationMain(multi_process_notification::Domain domain) { + BrowserThread browser_thread(BrowserThread::IO); + base::Thread::Options options(MessageLoop::TYPE_IO, 0); + EXPECT_TRUE(browser_thread.StartWithOptions(options)); + MessageLoop loop; + QuitterDelegate quitter; + multi_process_notification::Listener listener( + kQuitNotificationName, domain, &quitter); + EXPECT_TRUE(listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + EXPECT_TRUE(quitter.WasStartedReceived()); + EXPECT_TRUE(multi_process_notification::Post(kStartedNotificationName, + domain)); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + EXPECT_TRUE(quitter.WasNotificationReceived()); + return 0; +} + +} // namespace + +class MultiProcessNotificationTest : public base::MultiProcessTest { + public: + MultiProcessNotificationTest(); + + void PostNotificationTest(multi_process_notification::Domain domain); + void CrossPostNotificationTest(multi_process_notification::Domain domain); + + static void SetUpTestCase(); + static void TearDownTestCase(); + + private: + MessageLoop loop_; + static BrowserThread* g_io_thread; +}; + +MultiProcessNotificationTest::MultiProcessNotificationTest() { +} + +BrowserThread* MultiProcessNotificationTest::g_io_thread = NULL; + +void MultiProcessNotificationTest::SetUpTestCase() { + g_io_thread = new BrowserThread(BrowserThread::IO); + base::Thread::Options options(MessageLoop::TYPE_IO, 0); + ASSERT_TRUE(g_io_thread->StartWithOptions(options)); +} + +void MultiProcessNotificationTest::TearDownTestCase() { + delete g_io_thread; +} + +void MultiProcessNotificationTest::PostNotificationTest( + multi_process_notification::Domain domain) { + QuitterDelegate process_started; + multi_process_notification::Listener listener( + kStartedNotificationName, domain, &process_started); + ASSERT_TRUE(listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(process_started.WasStartedReceived()); + std::string process_name; + switch (domain) { + case multi_process_notification::ProfileDomain: + process_name = "MultiProcessProfileNotificationMain"; + break; + + case multi_process_notification::UserDomain: + process_name = "MultiProcessUserNotificationMain"; + break; + + case multi_process_notification::SystemDomain: + process_name = "MultiProcessSystemNotificationMain"; + break; + } + base::ProcessHandle handle = SpawnChild(process_name, false); + ASSERT_TRUE(handle); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(process_started.WasNotificationReceived()); + ASSERT_TRUE(multi_process_notification::Post(kQuitNotificationName, domain)); + int exit_code = 0; + EXPECT_TRUE(base::WaitForExitCodeWithTimeout( + handle, &exit_code, TestTimeouts::action_max_timeout_ms())); +} + +void MultiProcessNotificationTest::CrossPostNotificationTest( + multi_process_notification::Domain domain) { + // Check to make sure notifications sent to user domain aren't picked up + // by system domain listeners and vice versa. + std::string local_notification("QuitLocalNotification"); + std::string final_notification("FinalQuitLocalNotification"); + QuitterDelegate profile_quitter; + QuitterDelegate user_quitter; + QuitterDelegate system_quitter; + QuitterDelegate final_quitter; + multi_process_notification::Listener profile_listener( + local_notification, multi_process_notification::ProfileDomain, + &profile_quitter); + multi_process_notification::Listener user_listener( + local_notification, multi_process_notification::UserDomain, + &user_quitter); + multi_process_notification::Listener system_listener( + local_notification, multi_process_notification::SystemDomain, + &system_quitter); + multi_process_notification::Listener final_listener( + final_notification, multi_process_notification::UserDomain, + &final_quitter); + + ASSERT_TRUE(profile_listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(profile_quitter.WasStartedReceived()); + ASSERT_TRUE(user_listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(user_quitter.WasStartedReceived()); + ASSERT_TRUE(system_listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(system_quitter.WasStartedReceived()); + + ASSERT_TRUE(multi_process_notification::Post(local_notification, domain)); + SpinRunLoop(TestTimeouts::action_timeout_ms()); + + // Now send out a final_notification to queue up a notification + // after the local_notification and make sure that all listeners have had a + // chance to process local_notification before we check to see if they + // were called. + ASSERT_TRUE(final_listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + EXPECT_TRUE(final_quitter.WasStartedReceived()); + ASSERT_TRUE(multi_process_notification::Post( + final_notification, multi_process_notification::UserDomain)); + SpinRunLoop(TestTimeouts::action_timeout_ms()); + ASSERT_TRUE(final_quitter.WasNotificationReceived()); + switch (domain) { + case multi_process_notification::ProfileDomain: + ASSERT_TRUE(profile_quitter.WasNotificationReceived()); + ASSERT_FALSE(user_quitter.WasNotificationReceived()); + ASSERT_FALSE(system_quitter.WasNotificationReceived()); + break; + + case multi_process_notification::UserDomain: + ASSERT_FALSE(profile_quitter.WasNotificationReceived()); + ASSERT_TRUE(user_quitter.WasNotificationReceived()); + ASSERT_FALSE(system_quitter.WasNotificationReceived()); + break; + + case multi_process_notification::SystemDomain: + ASSERT_FALSE(profile_quitter.WasNotificationReceived()); + ASSERT_FALSE(user_quitter.WasNotificationReceived()); + ASSERT_TRUE(system_quitter.WasNotificationReceived()); + break; + } +} + +TEST_F(MultiProcessNotificationTest, BasicCreationTest) { + QuitterDelegate quitter; + multi_process_notification::Listener local_listener( + "BasicCreationTest", multi_process_notification::UserDomain, &quitter); + ASSERT_TRUE(local_listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(quitter.WasStartedReceived()); + multi_process_notification::Listener system_listener( + "BasicCreationTest", multi_process_notification::SystemDomain, &quitter); + ASSERT_TRUE(system_listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(quitter.WasStartedReceived()); +} + +TEST_F(MultiProcessNotificationTest, PostInProcessNotification) { + std::string local_notification("QuitLocalNotification"); + QuitterDelegate quitter; + multi_process_notification::Listener listener( + local_notification, multi_process_notification::UserDomain, &quitter); + + ASSERT_TRUE(listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(quitter.WasStartedReceived()); + ASSERT_TRUE(multi_process_notification::Post( + local_notification, multi_process_notification::UserDomain)); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(quitter.WasNotificationReceived()); +} + +TEST_F(MultiProcessNotificationTest, MultiListener) { + std::string local_notification("LocalNotification"); + std::string quit_local_notification("QuitLocalNotification"); + + SimpleDelegate delegate1; + SimpleDelegate delegate2; + multi_process_notification::Listener local_listener1( + local_notification, multi_process_notification::UserDomain, + &delegate1); + multi_process_notification::Listener local_listener2( + local_notification, multi_process_notification::UserDomain, + &delegate2); + + QuitterDelegate quitter; + + multi_process_notification::Listener quit_listener(quit_local_notification, + multi_process_notification::UserDomain, &quitter); + + ASSERT_TRUE(local_listener1.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(delegate1.WasStartedReceived()); + ASSERT_TRUE(local_listener2.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(delegate2.WasStartedReceived()); + ASSERT_TRUE(quit_listener.Start()); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(quitter.WasStartedReceived()); + ASSERT_TRUE(multi_process_notification::Post( + local_notification, multi_process_notification::UserDomain)); + ASSERT_TRUE(multi_process_notification::Post( + quit_local_notification, multi_process_notification::UserDomain)); + SpinRunLoop(TestTimeouts::action_max_timeout_ms()); + ASSERT_TRUE(delegate1.WasNotificationReceived()); + ASSERT_TRUE(delegate2.WasNotificationReceived()); + ASSERT_TRUE(quitter.WasNotificationReceived()); +} + +TEST_F(MultiProcessNotificationTest, PostProfileNotification) { + PostNotificationTest(multi_process_notification::ProfileDomain); +} + +TEST_F(MultiProcessNotificationTest, PostUserNotification) { + PostNotificationTest(multi_process_notification::UserDomain); +} + +TEST_F(MultiProcessNotificationTest, PostSystemNotification) { + PostNotificationTest(multi_process_notification::SystemDomain); +} + +TEST_F(MultiProcessNotificationTest, ProfileCrossDomainPosting) { + CrossPostNotificationTest(multi_process_notification::ProfileDomain); +} + +TEST_F(MultiProcessNotificationTest, UserCrossDomainPosting) { + CrossPostNotificationTest(multi_process_notification::UserDomain); +} + +TEST_F(MultiProcessNotificationTest, SystemCrossDomainPosting) { + CrossPostNotificationTest(multi_process_notification::SystemDomain); +} + +MULTIPROCESS_TEST_MAIN(MultiProcessProfileNotificationMain) { + return MultiProcessNotificationMain( + multi_process_notification::ProfileDomain); +} + +MULTIPROCESS_TEST_MAIN(MultiProcessUserNotificationMain) { + return MultiProcessNotificationMain(multi_process_notification::UserDomain); +} + +MULTIPROCESS_TEST_MAIN(MultiProcessSystemNotificationMain) { + return MultiProcessNotificationMain(multi_process_notification::SystemDomain); +} + +#endif // defined(OS_MACOSX) |