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