1 // Copyright (c) 2012 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 // Create a service process that uses a Mock to respond to the browser in order 6 // to test launching the browser using the cloud print policy check command 7 // line switch. 8 9 #include "base/bind.h" 10 #include "base/command_line.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/process/kill.h" 13 #include "base/rand_util.h" 14 #include "base/synchronization/waitable_event.h" 15 #include "base/test/multiprocess_test.h" 16 #include "base/test/test_timeouts.h" 17 #include "base/time/default_tick_clock.h" 18 #include "base/time/time.h" 19 #include "chrome/browser/chrome_content_browser_client.h" 20 #include "chrome/browser/prefs/browser_prefs.h" 21 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h" 22 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h" 23 #include "chrome/browser/service_process/service_process_control.h" 24 #include "chrome/browser/ui/startup/startup_browser_creator.h" 25 #include "chrome/common/chrome_content_client.h" 26 #include "chrome/common/chrome_switches.h" 27 #include "chrome/common/pref_names.h" 28 #include "chrome/common/service_messages.h" 29 #include "chrome/common/service_process_util.h" 30 #include "chrome/service/service_ipc_server.h" 31 #include "chrome/service/service_process.h" 32 #include "chrome/test/base/chrome_unit_test_suite.h" 33 #include "chrome/test/base/test_launcher_utils.h" 34 #include "chrome/test/base/testing_browser_process.h" 35 #include "chrome/test/base/testing_io_thread_state.h" 36 #include "chrome/test/base/testing_pref_service_syncable.h" 37 #include "chrome/test/base/testing_profile.h" 38 #include "chrome/test/base/testing_profile_manager.h" 39 #include "chrome/test/base/ui_test_utils.h" 40 #include "components/keyed_service/core/keyed_service.h" 41 #include "content/public/browser/notification_service.h" 42 #include "content/public/common/content_paths.h" 43 #include "content/public/test/test_browser_thread_bundle.h" 44 #include "ipc/ipc_descriptors.h" 45 #include "ipc/ipc_multiprocess_test.h" 46 #include "ipc/ipc_switches.h" 47 #include "testing/gmock/include/gmock/gmock.h" 48 #include "testing/gtest/include/gtest/gtest.h" 49 #include "testing/multiprocess_func_list.h" 50 51 #if defined(OS_MACOSX) 52 #include "chrome/common/mac/mock_launchd.h" 53 #endif 54 #if defined(OS_POSIX) 55 #include "base/posix/global_descriptors.h" 56 #endif 57 58 using ::testing::AnyNumber; 59 using ::testing::Assign; 60 using ::testing::AtLeast; 61 using ::testing::DoAll; 62 using ::testing::Invoke; 63 using ::testing::Mock; 64 using ::testing::Property; 65 using ::testing::Return; 66 using ::testing::WithoutArgs; 67 using ::testing::_; 68 using content::BrowserThread; 69 70 namespace { 71 72 enum MockServiceProcessExitCodes { 73 kMissingSwitch = 1, 74 kInitializationFailure, 75 kExpectationsNotMet, 76 kShutdownNotGood 77 }; 78 79 #if defined(OS_MACOSX) 80 const char kTestExecutablePath[] = "test-executable-path"; 81 #endif 82 83 bool g_good_shutdown = false; 84 85 void ShutdownTask() { 86 g_good_shutdown = true; 87 g_service_process->Shutdown(); 88 } 89 90 class TestStartupClientChannelListener : public IPC::Listener { 91 public: 92 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 93 return false; 94 } 95 }; 96 97 } // namespace 98 99 class TestServiceProcess : public ServiceProcess { 100 public: 101 TestServiceProcess() { } 102 virtual ~TestServiceProcess() { } 103 104 bool Initialize(base::MessageLoopForUI* message_loop, 105 ServiceProcessState* state); 106 107 base::MessageLoopProxy* IOMessageLoopProxy() { 108 return io_thread_->message_loop_proxy().get(); 109 } 110 }; 111 112 bool TestServiceProcess::Initialize(base::MessageLoopForUI* message_loop, 113 ServiceProcessState* state) { 114 main_message_loop_ = message_loop; 115 116 service_process_state_.reset(state); 117 118 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0); 119 io_thread_.reset(new base::Thread("TestServiceProcess_IO")); 120 return io_thread_->StartWithOptions(options); 121 } 122 123 // This mocks the service side IPC message handler, allowing us to have a 124 // minimal service process. 125 class MockServiceIPCServer : public ServiceIPCServer { 126 public: 127 static std::string EnabledUserId(); 128 129 explicit MockServiceIPCServer(const IPC::ChannelHandle& handle) 130 : ServiceIPCServer(handle), 131 enabled_(true) { } 132 133 MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message)); 134 MOCK_METHOD1(OnChannelConnected, void(int32 peer_pid)); 135 MOCK_METHOD0(OnChannelError, void()); 136 137 void SetServiceEnabledExpectations(); 138 void SetWillBeDisabledExpectations(); 139 140 void CallServiceOnChannelConnected(int32 peer_pid) { 141 ServiceIPCServer::OnChannelConnected(peer_pid); 142 } 143 144 bool SendInfo(); 145 146 private: 147 cloud_print::CloudPrintProxyInfo info_; 148 bool enabled_; 149 }; 150 151 // static 152 std::string MockServiceIPCServer::EnabledUserId() { 153 return std::string("kitteh (at) canhazcheezburger.cat"); 154 } 155 156 void MockServiceIPCServer::SetServiceEnabledExpectations() { 157 EXPECT_CALL(*this, OnChannelConnected(_)).Times(1) 158 .WillRepeatedly( 159 Invoke(this, &MockServiceIPCServer::CallServiceOnChannelConnected)); 160 161 EXPECT_CALL(*this, OnChannelError()).Times(0); 162 EXPECT_CALL(*this, OnMessageReceived(_)).Times(0); 163 164 EXPECT_CALL(*this, 165 OnMessageReceived( 166 Property(&IPC::Message::type, 167 static_cast<int32>(ServiceMsg_GetCloudPrintProxyInfo::ID)))) 168 .Times(AnyNumber()).WillRepeatedly( 169 WithoutArgs(Invoke(this, &MockServiceIPCServer::SendInfo))); 170 171 EXPECT_CALL(*this, 172 OnMessageReceived( 173 Property(&IPC::Message::type, 174 static_cast<int32>(ServiceMsg_Shutdown::ID)))) 175 .Times(1) 176 .WillOnce( 177 DoAll(Assign(&g_good_shutdown, true), 178 WithoutArgs( 179 Invoke(g_service_process, &ServiceProcess::Shutdown)), 180 Return(true))); 181 } 182 183 void MockServiceIPCServer::SetWillBeDisabledExpectations() { 184 SetServiceEnabledExpectations(); 185 186 EXPECT_CALL(*this, 187 OnMessageReceived( 188 Property(&IPC::Message::type, 189 static_cast<int32>( 190 ServiceMsg_DisableCloudPrintProxy::ID)))) 191 .Times(AtLeast(1)) 192 .WillRepeatedly(DoAll(Assign(&enabled_, false), Return(true))); 193 } 194 195 bool MockServiceIPCServer::SendInfo() { 196 if (enabled_) { 197 info_.enabled = true; 198 info_.email = EnabledUserId(); 199 EXPECT_TRUE(Send(new ServiceHostMsg_CloudPrintProxy_Info(info_))); 200 } else { 201 info_.enabled = false; 202 info_.email = std::string(); 203 EXPECT_TRUE(Send(new ServiceHostMsg_CloudPrintProxy_Info(info_))); 204 } 205 return true; 206 } 207 208 typedef base::Callback<void(MockServiceIPCServer* server)> 209 SetExpectationsCallback; 210 211 // The return value from this routine is used as the exit code for the mock 212 // service process. Any non-zero return value will be printed out and can help 213 // determine the failure. 214 int CloudPrintMockService_Main(SetExpectationsCallback set_expectations) { 215 base::MessageLoopForUI main_message_loop; 216 main_message_loop.set_thread_name("Main Thread"); 217 CommandLine* command_line = CommandLine::ForCurrentProcess(); 218 content::RegisterPathProvider(); 219 220 #if defined(OS_MACOSX) 221 if (!command_line->HasSwitch(kTestExecutablePath)) 222 return kMissingSwitch; 223 base::FilePath executable_path = 224 command_line->GetSwitchValuePath(kTestExecutablePath); 225 EXPECT_FALSE(executable_path.empty()); 226 MockLaunchd mock_launchd(executable_path, &main_message_loop, true, true); 227 Launchd::ScopedInstance use_mock(&mock_launchd); 228 #endif 229 230 base::FilePath user_data_dir = 231 command_line->GetSwitchValuePath(switches::kUserDataDir); 232 CHECK(!user_data_dir.empty()); 233 CHECK(test_launcher_utils::OverrideUserDataDir(user_data_dir)); 234 235 ServiceProcessState* state(new ServiceProcessState); 236 bool service_process_state_initialized = state->Initialize(); 237 EXPECT_TRUE(service_process_state_initialized); 238 if (!service_process_state_initialized) 239 return kInitializationFailure; 240 241 TestServiceProcess service_process; 242 EXPECT_EQ(&service_process, g_service_process); 243 244 // Takes ownership of the pointer, but we can use it since we have the same 245 // lifetime. 246 EXPECT_TRUE(service_process.Initialize(&main_message_loop, state)); 247 248 MockServiceIPCServer server(state->GetServiceProcessChannel()); 249 250 // Here is where the expectations/mock responses need to be set up. 251 set_expectations.Run(&server); 252 253 EXPECT_TRUE(server.Init()); 254 EXPECT_TRUE(state->SignalReady(service_process.IOMessageLoopProxy(), 255 base::Bind(&ShutdownTask))); 256 #if defined(OS_MACOSX) 257 mock_launchd.SignalReady(); 258 #endif 259 260 // Connect up the parent/child IPC channel to signal that the test can 261 // continue. 262 TestStartupClientChannelListener listener; 263 EXPECT_TRUE(CommandLine::ForCurrentProcess()->HasSwitch( 264 switches::kProcessChannelID)); 265 std::string startup_channel_name = 266 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 267 switches::kProcessChannelID); 268 scoped_ptr<IPC::ChannelProxy> startup_channel; 269 startup_channel = 270 IPC::ChannelProxy::Create(startup_channel_name, 271 IPC::Channel::MODE_CLIENT, 272 &listener, 273 service_process.IOMessageLoopProxy()); 274 275 main_message_loop.Run(); 276 if (!Mock::VerifyAndClearExpectations(&server)) 277 return kExpectationsNotMet; 278 if (!g_good_shutdown) 279 return kShutdownNotGood; 280 return 0; 281 } 282 283 void SetServiceEnabledExpectations(MockServiceIPCServer* server) { 284 server->SetServiceEnabledExpectations(); 285 } 286 287 MULTIPROCESS_IPC_TEST_MAIN(CloudPrintMockService_StartEnabledWaitForQuit) { 288 return CloudPrintMockService_Main( 289 base::Bind(&SetServiceEnabledExpectations)); 290 } 291 292 void SetServiceWillBeDisabledExpectations(MockServiceIPCServer* server) { 293 server->SetWillBeDisabledExpectations(); 294 } 295 296 MULTIPROCESS_IPC_TEST_MAIN(CloudPrintMockService_StartEnabledExpectDisabled) { 297 return CloudPrintMockService_Main( 298 base::Bind(&SetServiceWillBeDisabledExpectations)); 299 } 300 301 class CloudPrintProxyPolicyStartupTest : public base::MultiProcessTest, 302 public IPC::Listener { 303 public: 304 CloudPrintProxyPolicyStartupTest(); 305 virtual ~CloudPrintProxyPolicyStartupTest(); 306 307 virtual void SetUp() OVERRIDE; 308 virtual void TearDown() OVERRIDE; 309 310 scoped_refptr<base::MessageLoopProxy> IOMessageLoopProxy() { 311 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); 312 } 313 base::ProcessHandle Launch(const std::string& name); 314 void WaitForConnect(); 315 bool Send(IPC::Message* message); 316 void ShutdownAndWaitForExitWithTimeout(base::ProcessHandle handle); 317 318 // IPC::Listener implementation 319 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 320 return false; 321 } 322 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; 323 324 // MultiProcessTest implementation. 325 virtual CommandLine MakeCmdLine(const std::string& procname) OVERRIDE; 326 327 bool LaunchBrowser(const CommandLine& command_line, Profile* profile) { 328 int return_code = 0; 329 StartupBrowserCreator browser_creator; 330 return StartupBrowserCreator::ProcessCmdLineImpl( 331 command_line, base::FilePath(), false, profile, 332 StartupBrowserCreator::Profiles(), &return_code, &browser_creator); 333 } 334 335 protected: 336 content::TestBrowserThreadBundle thread_bundle_; 337 base::ScopedTempDir temp_user_data_dir_; 338 339 std::string startup_channel_id_; 340 scoped_ptr<IPC::ChannelProxy> startup_channel_; 341 scoped_ptr<ChromeContentClient> content_client_; 342 scoped_ptr<chrome::ChromeContentBrowserClient> browser_content_client_; 343 344 #if defined(OS_MACOSX) 345 base::ScopedTempDir temp_dir_; 346 base::FilePath executable_path_, bundle_path_; 347 scoped_ptr<MockLaunchd> mock_launchd_; 348 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_; 349 #endif 350 351 private: 352 class WindowedChannelConnectionObserver { 353 public: 354 WindowedChannelConnectionObserver() 355 : seen_(false), 356 running_(false) { } 357 358 void Wait() { 359 if (seen_) 360 return; 361 running_ = true; 362 content::RunMessageLoop(); 363 } 364 365 void Notify() { 366 seen_ = true; 367 if (running_) 368 base::MessageLoopForUI::current()->Quit(); 369 } 370 371 private: 372 bool seen_; 373 bool running_; 374 }; 375 376 WindowedChannelConnectionObserver observer_; 377 }; 378 379 CloudPrintProxyPolicyStartupTest::CloudPrintProxyPolicyStartupTest() 380 : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) { 381 // Although is really a unit test which runs in the browser_tests binary, it 382 // doesn't get the unit setup which normally happens in the unit test binary. 383 ChromeUnitTestSuite::InitializeProviders(); 384 ChromeUnitTestSuite::InitializeResourceBundle(); 385 } 386 387 CloudPrintProxyPolicyStartupTest::~CloudPrintProxyPolicyStartupTest() { 388 } 389 390 void CloudPrintProxyPolicyStartupTest::SetUp() { 391 content_client_.reset(new ChromeContentClient); 392 content::SetContentClient(content_client_.get()); 393 browser_content_client_.reset(new chrome::ChromeContentBrowserClient()); 394 content::SetBrowserClientForTesting(browser_content_client_.get()); 395 396 TestingBrowserProcess::CreateInstance(); 397 #if defined(OS_MACOSX) 398 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); 399 EXPECT_TRUE(MockLaunchd::MakeABundle(temp_dir_.path(), 400 "CloudPrintProxyTest", 401 &bundle_path_, 402 &executable_path_)); 403 mock_launchd_.reset(new MockLaunchd(executable_path_, 404 base::MessageLoopForUI::current(), 405 true, false)); 406 scoped_launchd_instance_.reset( 407 new Launchd::ScopedInstance(mock_launchd_.get())); 408 #endif 409 410 // Ensure test does not use the standard profile directory. This is copied 411 // from InProcessBrowserTest::SetUp(). These tests require a more complex 412 // process startup so they are unable to just inherit from 413 // InProcessBrowserTest. 414 CommandLine* command_line = CommandLine::ForCurrentProcess(); 415 base::FilePath user_data_dir = 416 command_line->GetSwitchValuePath(switches::kUserDataDir); 417 if (user_data_dir.empty()) { 418 ASSERT_TRUE(temp_user_data_dir_.CreateUniqueTempDir() && 419 temp_user_data_dir_.IsValid()) 420 << "Could not create temporary user data directory \"" 421 << temp_user_data_dir_.path().value() << "\"."; 422 423 user_data_dir = temp_user_data_dir_.path(); 424 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir); 425 } 426 ASSERT_TRUE(test_launcher_utils::OverrideUserDataDir(user_data_dir)); 427 } 428 429 void CloudPrintProxyPolicyStartupTest::TearDown() { 430 browser_content_client_.reset(); 431 content_client_.reset(); 432 content::SetContentClient(NULL); 433 434 TestingBrowserProcess::DeleteInstance(); 435 } 436 437 base::ProcessHandle CloudPrintProxyPolicyStartupTest::Launch( 438 const std::string& name) { 439 EXPECT_FALSE(CheckServiceProcessReady()); 440 441 startup_channel_id_ = 442 base::StringPrintf("%d.%p.%d", 443 base::GetCurrentProcId(), this, 444 base::RandInt(0, std::numeric_limits<int>::max())); 445 startup_channel_ = IPC::ChannelProxy::Create(startup_channel_id_, 446 IPC::Channel::MODE_SERVER, 447 this, 448 IOMessageLoopProxy()); 449 450 #if defined(OS_POSIX) 451 base::FileHandleMappingVector ipc_file_list; 452 ipc_file_list.push_back(std::make_pair( 453 startup_channel_->TakeClientFileDescriptor(), 454 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor)); 455 base::LaunchOptions options; 456 options.fds_to_remap = &ipc_file_list; 457 base::ProcessHandle handle = SpawnChildWithOptions(name, options); 458 #else 459 base::ProcessHandle handle = SpawnChild(name); 460 #endif 461 EXPECT_TRUE(handle); 462 return handle; 463 } 464 465 void CloudPrintProxyPolicyStartupTest::WaitForConnect() { 466 observer_.Wait(); 467 EXPECT_TRUE(CheckServiceProcessReady()); 468 EXPECT_TRUE(base::MessageLoopProxy::current().get()); 469 ServiceProcessControl::GetInstance()->SetChannel( 470 IPC::ChannelProxy::Create(GetServiceProcessChannel(), 471 IPC::Channel::MODE_NAMED_CLIENT, 472 ServiceProcessControl::GetInstance(), 473 IOMessageLoopProxy())); 474 } 475 476 bool CloudPrintProxyPolicyStartupTest::Send(IPC::Message* message) { 477 return ServiceProcessControl::GetInstance()->Send(message); 478 } 479 480 void CloudPrintProxyPolicyStartupTest::ShutdownAndWaitForExitWithTimeout( 481 base::ProcessHandle handle) { 482 ASSERT_TRUE(Send(new ServiceMsg_Shutdown())); 483 484 int exit_code = -100; 485 bool exited = 486 base::WaitForExitCodeWithTimeout(handle, &exit_code, 487 TestTimeouts::action_timeout()); 488 EXPECT_TRUE(exited); 489 EXPECT_EQ(exit_code, 0); 490 base::CloseProcessHandle(handle); 491 } 492 493 void CloudPrintProxyPolicyStartupTest::OnChannelConnected(int32 peer_pid) { 494 observer_.Notify(); 495 } 496 497 CommandLine CloudPrintProxyPolicyStartupTest::MakeCmdLine( 498 const std::string& procname) { 499 CommandLine cl = MultiProcessTest::MakeCmdLine(procname); 500 cl.AppendSwitchASCII(switches::kProcessChannelID, startup_channel_id_); 501 #if defined(OS_MACOSX) 502 cl.AppendSwitchASCII(kTestExecutablePath, executable_path_.value()); 503 #endif 504 return cl; 505 } 506 507 TEST_F(CloudPrintProxyPolicyStartupTest, StartAndShutdown) { 508 TestingBrowserProcess* browser_process = 509 TestingBrowserProcess::GetGlobal(); 510 TestingProfileManager profile_manager(browser_process); 511 ASSERT_TRUE(profile_manager.SetUp()); 512 513 // Must be created after the TestingProfileManager since that creates the 514 // LocalState for the BrowserProcess. Must be created before profiles are 515 // constructed. 516 chrome::TestingIOThreadState testing_io_thread_state; 517 518 base::ProcessHandle handle = 519 Launch("CloudPrintMockService_StartEnabledWaitForQuit"); 520 WaitForConnect(); 521 ShutdownAndWaitForExitWithTimeout(handle); 522 content::RunAllPendingInMessageLoop(); 523 } 524 525 KeyedService* CloudPrintProxyServiceFactoryForPolicyTest( 526 content::BrowserContext* profile) { 527 CloudPrintProxyService* service = 528 new CloudPrintProxyService(static_cast<Profile*>(profile)); 529 service->Initialize(); 530 return service; 531 } 532 533 TEST_F(CloudPrintProxyPolicyStartupTest, StartBrowserWithoutPolicy) { 534 base::ProcessHandle handle = 535 Launch("CloudPrintMockService_StartEnabledWaitForQuit"); 536 537 // Setup the Browser Process with a full IOThread::Globals. 538 TestingBrowserProcess* browser_process = 539 TestingBrowserProcess::GetGlobal(); 540 541 TestingProfileManager profile_manager(browser_process); 542 ASSERT_TRUE(profile_manager.SetUp()); 543 544 // Must be created after the TestingProfileManager since that creates the 545 // LocalState for the BrowserProcess. Must be created before profiles are 546 // constructed. 547 chrome::TestingIOThreadState testing_io_thread_state; 548 549 TestingProfile* profile = 550 profile_manager.CreateTestingProfile("StartBrowserWithoutPolicy"); 551 CloudPrintProxyServiceFactory::GetInstance()-> 552 SetTestingFactory(profile, CloudPrintProxyServiceFactoryForPolicyTest); 553 554 TestingPrefServiceSyncable* prefs = profile->GetTestingPrefService(); 555 prefs->SetUserPref(prefs::kCloudPrintEmail, 556 base::Value::CreateStringValue( 557 MockServiceIPCServer::EnabledUserId())); 558 559 CommandLine command_line(CommandLine::NO_PROGRAM); 560 command_line.AppendSwitch(switches::kCheckCloudPrintConnectorPolicy); 561 test_launcher_utils::PrepareBrowserCommandLineForTests(&command_line); 562 563 WaitForConnect(); 564 base::RunLoop run_loop; 565 base::MessageLoop::current()->PostDelayedTask( 566 FROM_HERE, 567 run_loop.QuitClosure(), 568 TestTimeouts::action_timeout()); 569 570 bool should_run_loop = LaunchBrowser(command_line, profile); 571 EXPECT_FALSE(should_run_loop); 572 if (should_run_loop) 573 run_loop.Run(); 574 575 EXPECT_EQ(MockServiceIPCServer::EnabledUserId(), 576 prefs->GetString(prefs::kCloudPrintEmail)); 577 578 ShutdownAndWaitForExitWithTimeout(handle); 579 content::RunAllPendingInMessageLoop(); 580 profile_manager.DeleteTestingProfile("StartBrowserWithoutPolicy"); 581 } 582 583 TEST_F(CloudPrintProxyPolicyStartupTest, StartBrowserWithPolicy) { 584 base::ProcessHandle handle = 585 Launch("CloudPrintMockService_StartEnabledExpectDisabled"); 586 587 TestingBrowserProcess* browser_process = 588 TestingBrowserProcess::GetGlobal(); 589 TestingProfileManager profile_manager(browser_process); 590 ASSERT_TRUE(profile_manager.SetUp()); 591 592 // Must be created after the TestingProfileManager since that creates the 593 // LocalState for the BrowserProcess. Must be created before profiles are 594 // constructed. 595 chrome::TestingIOThreadState testing_io_thread_state; 596 597 TestingProfile* profile = 598 profile_manager.CreateTestingProfile("StartBrowserWithPolicy"); 599 CloudPrintProxyServiceFactory::GetInstance()-> 600 SetTestingFactory(profile, CloudPrintProxyServiceFactoryForPolicyTest); 601 602 TestingPrefServiceSyncable* prefs = profile->GetTestingPrefService(); 603 prefs->SetUserPref(prefs::kCloudPrintEmail, 604 base::Value::CreateStringValue( 605 MockServiceIPCServer::EnabledUserId())); 606 prefs->SetManagedPref(prefs::kCloudPrintProxyEnabled, 607 base::Value::CreateBooleanValue(false)); 608 609 CommandLine command_line(CommandLine::NO_PROGRAM); 610 command_line.AppendSwitch(switches::kCheckCloudPrintConnectorPolicy); 611 test_launcher_utils::PrepareBrowserCommandLineForTests(&command_line); 612 613 WaitForConnect(); 614 base::RunLoop run_loop; 615 base::MessageLoop::current()->PostDelayedTask( 616 FROM_HERE, 617 run_loop.QuitClosure(), 618 TestTimeouts::action_timeout()); 619 620 bool should_run_loop = LaunchBrowser(command_line, profile); 621 622 // No expectations on run_loop being true here; that would be a race 623 // condition. 624 if (should_run_loop) 625 run_loop.Run(); 626 627 EXPECT_EQ("", prefs->GetString(prefs::kCloudPrintEmail)); 628 629 ShutdownAndWaitForExitWithTimeout(handle); 630 content::RunAllPendingInMessageLoop(); 631 profile_manager.DeleteTestingProfile("StartBrowserWithPolicy"); 632 } 633