cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / chrome / browser / printing / cloud_print / test / cloud_print_proxy_process_browsertest.cc
blob768c431aea6c76c0075a20cba9a6d0c3b0701eaf
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.
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.
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/process/process.h"
14 #include "base/rand_util.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/test/multiprocess_test.h"
18 #include "base/test/test_timeouts.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "base/time/default_tick_clock.h"
21 #include "base/time/time.h"
22 #include "chrome/browser/chrome_content_browser_client.h"
23 #include "chrome/browser/prefs/browser_prefs.h"
24 #include "chrome/browser/service_process/service_process_control.h"
25 #include "chrome/browser/ui/startup/startup_browser_creator.h"
26 #include "chrome/common/chrome_content_client.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "chrome/common/service_messages.h"
30 #include "chrome/common/service_process_util.h"
31 #include "chrome/service/service_ipc_server.h"
32 #include "chrome/service/service_process.h"
33 #include "chrome/test/base/chrome_unit_test_suite.h"
34 #include "chrome/test/base/test_launcher_utils.h"
35 #include "chrome/test/base/testing_browser_process.h"
36 #include "chrome/test/base/testing_io_thread_state.h"
37 #include "chrome/test/base/testing_pref_service_syncable.h"
38 #include "chrome/test/base/testing_profile.h"
39 #include "chrome/test/base/testing_profile_manager.h"
40 #include "content/public/browser/notification_service.h"
41 #include "content/public/common/content_paths.h"
42 #include "content/public/test/test_browser_thread_bundle.h"
43 #include "content/public/test/test_utils.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"
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
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;
70 namespace {
72 enum MockServiceProcessExitCodes {
73 kMissingSwitch = 1,
74 kInitializationFailure,
75 kExpectationsNotMet,
76 kShutdownNotGood
79 #if defined(OS_MACOSX)
80 const char kTestExecutablePath[] = "test-executable-path";
81 #endif
83 bool g_good_shutdown = false;
85 void ShutdownTask() {
86 g_good_shutdown = true;
87 g_service_process->Shutdown();
90 class TestStartupClientChannelListener : public IPC::Listener {
91 public:
92 bool OnMessageReceived(const IPC::Message& message) override { return false; }
95 } // namespace
97 class TestServiceProcess : public ServiceProcess {
98 public:
99 TestServiceProcess() { }
100 ~TestServiceProcess() override {}
102 bool Initialize(base::MessageLoopForUI* message_loop,
103 ServiceProcessState* state);
106 bool TestServiceProcess::Initialize(base::MessageLoopForUI* message_loop,
107 ServiceProcessState* state) {
108 main_message_loop_ = message_loop;
110 service_process_state_.reset(state);
112 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
113 io_thread_.reset(new base::Thread("TestServiceProcess_IO"));
114 return io_thread_->StartWithOptions(options);
117 // This mocks the service side IPC message handler, allowing us to have a
118 // minimal service process.
119 class MockServiceIPCServer : public ServiceIPCServer {
120 public:
121 static std::string EnabledUserId();
123 MockServiceIPCServer(
124 ServiceIPCServer::Client* client,
125 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
126 const IPC::ChannelHandle& handle,
127 base::WaitableEvent* shutdown_event)
128 : ServiceIPCServer(client, io_task_runner, handle, shutdown_event),
129 enabled_(true) { }
131 MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message));
132 MOCK_METHOD1(OnChannelConnected, void(int32 peer_pid));
133 MOCK_METHOD0(OnChannelError, void());
135 void SetServiceEnabledExpectations();
136 void SetWillBeDisabledExpectations();
138 void CallServiceOnChannelConnected(int32 peer_pid) {
139 ServiceIPCServer::OnChannelConnected(peer_pid);
142 bool SendInfo();
144 private:
145 cloud_print::CloudPrintProxyInfo info_;
146 bool enabled_;
149 // static
150 std::string MockServiceIPCServer::EnabledUserId() {
151 return std::string("kitteh@canhazcheezburger.cat");
154 void MockServiceIPCServer::SetServiceEnabledExpectations() {
155 EXPECT_CALL(*this, OnChannelConnected(_)).Times(1)
156 .WillRepeatedly(
157 Invoke(this, &MockServiceIPCServer::CallServiceOnChannelConnected));
159 EXPECT_CALL(*this, OnChannelError()).Times(0);
160 EXPECT_CALL(*this, OnMessageReceived(_)).Times(0);
162 EXPECT_CALL(*this,
163 OnMessageReceived(
164 Property(&IPC::Message::type,
165 static_cast<int32>(ServiceMsg_GetCloudPrintProxyInfo::ID))))
166 .Times(AnyNumber()).WillRepeatedly(
167 WithoutArgs(Invoke(this, &MockServiceIPCServer::SendInfo)));
169 EXPECT_CALL(*this,
170 OnMessageReceived(
171 Property(&IPC::Message::type,
172 static_cast<int32>(ServiceMsg_Shutdown::ID))))
173 .Times(1)
174 .WillOnce(
175 DoAll(Assign(&g_good_shutdown, true),
176 WithoutArgs(
177 Invoke(g_service_process, &ServiceProcess::Shutdown)),
178 Return(true)));
181 void MockServiceIPCServer::SetWillBeDisabledExpectations() {
182 SetServiceEnabledExpectations();
184 EXPECT_CALL(*this,
185 OnMessageReceived(
186 Property(&IPC::Message::type,
187 static_cast<int32>(
188 ServiceMsg_DisableCloudPrintProxy::ID))))
189 .Times(AtLeast(1))
190 .WillRepeatedly(DoAll(Assign(&enabled_, false), Return(true)));
193 bool MockServiceIPCServer::SendInfo() {
194 if (enabled_) {
195 info_.enabled = true;
196 info_.email = EnabledUserId();
197 EXPECT_TRUE(Send(new ServiceHostMsg_CloudPrintProxy_Info(info_)));
198 } else {
199 info_.enabled = false;
200 info_.email = std::string();
201 EXPECT_TRUE(Send(new ServiceHostMsg_CloudPrintProxy_Info(info_)));
203 return true;
206 typedef base::Callback<void(MockServiceIPCServer* server)>
207 SetExpectationsCallback;
209 // The return value from this routine is used as the exit code for the mock
210 // service process. Any non-zero return value will be printed out and can help
211 // determine the failure.
212 int CloudPrintMockService_Main(SetExpectationsCallback set_expectations) {
213 base::MessageLoopForUI main_message_loop;
214 main_message_loop.set_thread_name("Main Thread");
215 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
216 content::RegisterPathProvider();
218 base::FilePath user_data_dir =
219 command_line->GetSwitchValuePath(switches::kUserDataDir);
220 CHECK(!user_data_dir.empty());
221 CHECK(test_launcher_utils::OverrideUserDataDir(user_data_dir));
223 #if defined(OS_MACOSX)
224 if (!command_line->HasSwitch(kTestExecutablePath))
225 return kMissingSwitch;
226 base::FilePath executable_path =
227 command_line->GetSwitchValuePath(kTestExecutablePath);
228 EXPECT_FALSE(executable_path.empty());
229 MockLaunchd mock_launchd(executable_path, &main_message_loop, true, true);
230 Launchd::ScopedInstance use_mock(&mock_launchd);
231 #endif
234 ServiceProcessState* state(new ServiceProcessState);
235 bool service_process_state_initialized = state->Initialize();
236 EXPECT_TRUE(service_process_state_initialized);
237 if (!service_process_state_initialized)
238 return kInitializationFailure;
240 TestServiceProcess service_process;
241 EXPECT_EQ(&service_process, g_service_process);
243 // Takes ownership of the pointer, but we can use it since we have the same
244 // lifetime.
245 EXPECT_TRUE(service_process.Initialize(&main_message_loop, state));
247 MockServiceIPCServer server(&service_process,
248 service_process.io_task_runner(),
249 state->GetServiceProcessChannel(),
250 service_process.GetShutdownEventForTesting());
252 // Here is where the expectations/mock responses need to be set up.
253 set_expectations.Run(&server);
255 EXPECT_TRUE(server.Init());
256 EXPECT_TRUE(state->SignalReady(service_process.io_task_runner().get(),
257 base::Bind(&ShutdownTask)));
258 #if defined(OS_MACOSX)
259 mock_launchd.SignalReady();
260 #endif
262 // Connect up the parent/child IPC channel to signal that the test can
263 // continue.
264 TestStartupClientChannelListener listener;
265 EXPECT_TRUE(base::CommandLine::ForCurrentProcess()->HasSwitch(
266 switches::kProcessChannelID));
267 std::string startup_channel_name =
268 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
269 switches::kProcessChannelID);
270 scoped_ptr<IPC::ChannelProxy> startup_channel;
271 startup_channel =
272 IPC::ChannelProxy::Create(startup_channel_name,
273 IPC::Channel::MODE_CLIENT,
274 &listener,
275 service_process.io_task_runner());
277 main_message_loop.Run();
278 if (!Mock::VerifyAndClearExpectations(&server))
279 return kExpectationsNotMet;
280 if (!g_good_shutdown)
281 return kShutdownNotGood;
282 return 0;
285 void SetServiceEnabledExpectations(MockServiceIPCServer* server) {
286 server->SetServiceEnabledExpectations();
289 MULTIPROCESS_IPC_TEST_MAIN(CloudPrintMockService_StartEnabledWaitForQuit) {
290 return CloudPrintMockService_Main(
291 base::Bind(&SetServiceEnabledExpectations));
294 void SetServiceWillBeDisabledExpectations(MockServiceIPCServer* server) {
295 server->SetWillBeDisabledExpectations();
298 MULTIPROCESS_IPC_TEST_MAIN(CloudPrintMockService_StartEnabledExpectDisabled) {
299 return CloudPrintMockService_Main(
300 base::Bind(&SetServiceWillBeDisabledExpectations));
303 class CloudPrintProxyPolicyStartupTest : public base::MultiProcessTest,
304 public IPC::Listener {
305 public:
306 CloudPrintProxyPolicyStartupTest();
307 ~CloudPrintProxyPolicyStartupTest() override;
309 void SetUp() override;
310 void TearDown() override;
312 scoped_refptr<base::SingleThreadTaskRunner> IOTaskRunner() {
313 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
315 base::Process Launch(const std::string& name);
316 void WaitForConnect();
317 bool Send(IPC::Message* message);
318 void ShutdownAndWaitForExitWithTimeout(base::Process process);
320 // IPC::Listener implementation
321 bool OnMessageReceived(const IPC::Message& message) override { return false; }
322 void OnChannelConnected(int32 peer_pid) override;
324 // MultiProcessTest implementation.
325 base::CommandLine MakeCmdLine(const std::string& procname) override;
327 bool LaunchBrowser(const base::CommandLine& command_line, Profile* profile) {
328 StartupBrowserCreator browser_creator;
329 return StartupBrowserCreator::ProcessCmdLineImpl(
330 command_line, base::FilePath(), false, profile,
331 StartupBrowserCreator::Profiles(), &browser_creator);
334 protected:
335 content::TestBrowserThreadBundle thread_bundle_;
336 base::ScopedTempDir temp_user_data_dir_;
338 std::string startup_channel_id_;
339 scoped_ptr<IPC::ChannelProxy> startup_channel_;
340 scoped_ptr<ChromeContentClient> content_client_;
341 scoped_ptr<chrome::ChromeContentBrowserClient> browser_content_client_;
343 #if defined(OS_MACOSX)
344 base::ScopedTempDir temp_dir_;
345 base::FilePath executable_path_, bundle_path_;
346 scoped_ptr<MockLaunchd> mock_launchd_;
347 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_;
348 #endif
350 private:
351 class WindowedChannelConnectionObserver {
352 public:
353 WindowedChannelConnectionObserver()
354 : seen_(false),
355 running_(false) { }
357 void Wait() {
358 if (seen_)
359 return;
360 running_ = true;
361 content::RunMessageLoop();
364 void Notify() {
365 seen_ = true;
366 if (running_)
367 base::MessageLoopForUI::current()->Quit();
370 private:
371 bool seen_;
372 bool running_;
375 WindowedChannelConnectionObserver observer_;
378 CloudPrintProxyPolicyStartupTest::CloudPrintProxyPolicyStartupTest()
379 : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {
380 // Although is really a unit test which runs in the browser_tests binary, it
381 // doesn't get the unit setup which normally happens in the unit test binary.
382 ChromeUnitTestSuite::InitializeProviders();
383 ChromeUnitTestSuite::InitializeResourceBundle();
386 CloudPrintProxyPolicyStartupTest::~CloudPrintProxyPolicyStartupTest() {
389 void CloudPrintProxyPolicyStartupTest::SetUp() {
390 content_client_.reset(new ChromeContentClient);
391 content::SetContentClient(content_client_.get());
392 browser_content_client_.reset(new chrome::ChromeContentBrowserClient());
393 content::SetBrowserClientForTesting(browser_content_client_.get());
395 TestingBrowserProcess::CreateInstance();
396 // Ensure test does not use the standard profile directory. This is copied
397 // from InProcessBrowserTest::SetUp(). These tests require a more complex
398 // process startup so they are unable to just inherit from
399 // InProcessBrowserTest.
400 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
401 base::FilePath user_data_dir =
402 command_line->GetSwitchValuePath(switches::kUserDataDir);
403 if (user_data_dir.empty()) {
404 ASSERT_TRUE(temp_user_data_dir_.CreateUniqueTempDir() &&
405 temp_user_data_dir_.IsValid())
406 << "Could not create temporary user data directory \""
407 << temp_user_data_dir_.path().value() << "\".";
409 user_data_dir = temp_user_data_dir_.path();
410 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
412 ASSERT_TRUE(test_launcher_utils::OverrideUserDataDir(user_data_dir));
414 #if defined(OS_MACOSX)
415 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
416 EXPECT_TRUE(MockLaunchd::MakeABundle(temp_dir_.path(),
417 "CloudPrintProxyTest",
418 &bundle_path_,
419 &executable_path_));
420 mock_launchd_.reset(new MockLaunchd(executable_path_,
421 base::MessageLoopForUI::current(),
422 true, false));
423 scoped_launchd_instance_.reset(
424 new Launchd::ScopedInstance(mock_launchd_.get()));
425 #endif
428 void CloudPrintProxyPolicyStartupTest::TearDown() {
429 browser_content_client_.reset();
430 content_client_.reset();
431 content::SetContentClient(NULL);
433 TestingBrowserProcess::DeleteInstance();
436 base::Process CloudPrintProxyPolicyStartupTest::Launch(
437 const std::string& name) {
438 EXPECT_FALSE(CheckServiceProcessReady());
440 startup_channel_id_ =
441 base::StringPrintf("%d.%p.%d",
442 base::GetCurrentProcId(), this,
443 base::RandInt(0, std::numeric_limits<int>::max()));
444 startup_channel_ = IPC::ChannelProxy::Create(startup_channel_id_,
445 IPC::Channel::MODE_SERVER,
446 this,
447 IOTaskRunner());
449 #if defined(OS_POSIX)
450 base::FileHandleMappingVector ipc_file_list;
451 ipc_file_list.push_back(std::make_pair(
452 startup_channel_->TakeClientFileDescriptor().release(),
453 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
454 base::LaunchOptions options;
455 options.fds_to_remap = &ipc_file_list;
456 base::Process process = SpawnChildWithOptions(name, options);
457 #else
458 base::Process process = SpawnChild(name);
459 #endif
460 EXPECT_TRUE(process.IsValid());
461 return process.Pass();
464 void CloudPrintProxyPolicyStartupTest::WaitForConnect() {
465 observer_.Wait();
466 EXPECT_TRUE(CheckServiceProcessReady());
467 EXPECT_TRUE(base::ThreadTaskRunnerHandle::Get().get());
468 ServiceProcessControl::GetInstance()->SetChannel(
469 IPC::ChannelProxy::Create(GetServiceProcessChannel(),
470 IPC::Channel::MODE_NAMED_CLIENT,
471 ServiceProcessControl::GetInstance(),
472 IOTaskRunner()));
475 bool CloudPrintProxyPolicyStartupTest::Send(IPC::Message* message) {
476 return ServiceProcessControl::GetInstance()->Send(message);
479 void CloudPrintProxyPolicyStartupTest::ShutdownAndWaitForExitWithTimeout(
480 base::Process process) {
481 ASSERT_TRUE(Send(new ServiceMsg_Shutdown()));
483 int exit_code = -100;
484 bool exited = process.WaitForExitWithTimeout(TestTimeouts::action_timeout(),
485 &exit_code);
486 EXPECT_TRUE(exited);
487 EXPECT_EQ(exit_code, 0);
490 void CloudPrintProxyPolicyStartupTest::OnChannelConnected(int32 peer_pid) {
491 observer_.Notify();
494 base::CommandLine CloudPrintProxyPolicyStartupTest::MakeCmdLine(
495 const std::string& procname) {
496 base::CommandLine cl = MultiProcessTest::MakeCmdLine(procname);
497 cl.AppendSwitchASCII(switches::kProcessChannelID, startup_channel_id_);
498 #if defined(OS_MACOSX)
499 cl.AppendSwitchASCII(kTestExecutablePath, executable_path_.value());
500 #endif
501 return cl;
504 TEST_F(CloudPrintProxyPolicyStartupTest, StartAndShutdown) {
505 TestingBrowserProcess* browser_process =
506 TestingBrowserProcess::GetGlobal();
507 TestingProfileManager profile_manager(browser_process);
508 ASSERT_TRUE(profile_manager.SetUp());
510 // Must be created after the TestingProfileManager since that creates the
511 // LocalState for the BrowserProcess. Must be created before profiles are
512 // constructed.
513 chrome::TestingIOThreadState testing_io_thread_state;
515 base::Process process =
516 Launch("CloudPrintMockService_StartEnabledWaitForQuit");
517 WaitForConnect();
518 ShutdownAndWaitForExitWithTimeout(process.Pass());
519 content::RunAllPendingInMessageLoop();