NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / printing / cloud_print / test / cloud_print_proxy_process_browsertest.cc
blobe5c89874b5436307654671849c4d57952171c200
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/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_process/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"
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
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;
66 namespace {
68 enum MockServiceProcessExitCodes {
69 kMissingSwitch = 1,
70 kInitializationFailure,
71 kExpectationsNotMet,
72 kShutdownNotGood
75 #if defined(OS_MACOSX)
76 const char kTestExecutablePath[] = "test-executable-path";
77 #endif
79 bool g_good_shutdown = false;
81 void ShutdownTask() {
82 g_good_shutdown = true;
83 g_service_process->Shutdown();
86 class TestStartupClientChannelListener : public IPC::Listener {
87 public:
88 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
89 return false;
93 } // namespace
95 class TestServiceProcess : public ServiceProcess {
96 public:
97 TestServiceProcess() { }
98 virtual ~TestServiceProcess() { }
100 bool Initialize(base::MessageLoopForUI* message_loop,
101 ServiceProcessState* state);
103 base::MessageLoopProxy* IOMessageLoopProxy() {
104 return io_thread_->message_loop_proxy().get();
108 bool TestServiceProcess::Initialize(base::MessageLoopForUI* message_loop,
109 ServiceProcessState* state) {
110 main_message_loop_ = message_loop;
112 service_process_state_.reset(state);
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);
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();
125 explicit MockServiceIPCServer(const IPC::ChannelHandle& handle)
126 : ServiceIPCServer(handle),
127 enabled_(true) { }
129 MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message));
130 MOCK_METHOD1(OnChannelConnected, void(int32 peer_pid));
131 MOCK_METHOD0(OnChannelError, void());
133 void SetServiceEnabledExpectations();
134 void SetWillBeDisabledExpectations();
136 void CallServiceOnChannelConnected(int32 peer_pid) {
137 ServiceIPCServer::OnChannelConnected(peer_pid);
140 bool SendInfo();
142 private:
143 cloud_print::CloudPrintProxyInfo info_;
144 bool enabled_;
147 // static
148 std::string MockServiceIPCServer::EnabledUserId() {
149 return std::string("kitteh@canhazcheezburger.cat");
152 void MockServiceIPCServer::SetServiceEnabledExpectations() {
153 EXPECT_CALL(*this, OnChannelConnected(_)).Times(1)
154 .WillRepeatedly(
155 Invoke(this, &MockServiceIPCServer::CallServiceOnChannelConnected));
157 EXPECT_CALL(*this, OnChannelError()).Times(0);
158 EXPECT_CALL(*this, OnMessageReceived(_)).Times(0);
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)));
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)));
179 void MockServiceIPCServer::SetWillBeDisabledExpectations() {
180 SetServiceEnabledExpectations();
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)));
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_)));
201 return true;
204 typedef base::Callback<void(MockServiceIPCServer* server)>
205 SetExpectationsCallback;
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();
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
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));
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;
236 TestServiceProcess service_process;
237 EXPECT_EQ(&service_process, g_service_process);
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));
243 MockServiceIPCServer server(state->GetServiceProcessChannel());
245 // Here is where the expectations/mock responses need to be set up.
246 set_expectations.Run(&server);
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
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()));
270 main_message_loop.Run();
271 if (!Mock::VerifyAndClearExpectations(&server))
272 return kExpectationsNotMet;
273 if (!g_good_shutdown)
274 return kShutdownNotGood;
275 return 0;
278 void SetServiceEnabledExpectations(MockServiceIPCServer* server) {
279 server->SetServiceEnabledExpectations();
282 MULTIPROCESS_IPC_TEST_MAIN(CloudPrintMockService_StartEnabledWaitForQuit) {
283 return CloudPrintMockService_Main(
284 base::Bind(&SetServiceEnabledExpectations));
287 void SetServiceWillBeDisabledExpectations(MockServiceIPCServer* server) {
288 server->SetWillBeDisabledExpectations();
291 MULTIPROCESS_IPC_TEST_MAIN(CloudPrintMockService_StartEnabledExpectDisabled) {
292 return CloudPrintMockService_Main(
293 base::Bind(&SetServiceWillBeDisabledExpectations));
296 class CloudPrintProxyPolicyStartupTest : public base::MultiProcessTest,
297 public IPC::Listener {
298 public:
299 CloudPrintProxyPolicyStartupTest();
300 virtual ~CloudPrintProxyPolicyStartupTest();
302 virtual void SetUp() OVERRIDE;
303 virtual void TearDown() OVERRIDE;
305 scoped_refptr<base::MessageLoopProxy> IOMessageLoopProxy() {
306 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
308 base::ProcessHandle Launch(const std::string& name);
309 void WaitForConnect();
310 bool Send(IPC::Message* message);
311 void ShutdownAndWaitForExitWithTimeout(base::ProcessHandle handle);
313 // IPC::Listener implementation
314 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
315 return false;
317 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
319 // MultiProcessTest implementation.
320 virtual CommandLine MakeCmdLine(const std::string& procname,
321 bool debug_on_start) OVERRIDE;
323 bool LaunchBrowser(const CommandLine& command_line, Profile* profile) {
324 int return_code = 0;
325 StartupBrowserCreator browser_creator;
326 return StartupBrowserCreator::ProcessCmdLineImpl(
327 command_line, base::FilePath(), false, profile,
328 StartupBrowserCreator::Profiles(), &return_code, &browser_creator);
331 protected:
332 content::TestBrowserThreadBundle thread_bundle_;
333 base::ScopedTempDir temp_user_data_dir_;
335 std::string startup_channel_id_;
336 scoped_ptr<IPC::ChannelProxy> startup_channel_;
338 #if defined(OS_MACOSX)
339 base::ScopedTempDir temp_dir_;
340 base::FilePath executable_path_, bundle_path_;
341 scoped_ptr<MockLaunchd> mock_launchd_;
342 scoped_ptr<Launchd::ScopedInstance> scoped_launchd_instance_;
343 #endif
345 private:
346 class WindowedChannelConnectionObserver {
347 public:
348 WindowedChannelConnectionObserver()
349 : seen_(false),
350 running_(false) { }
352 void Wait() {
353 if (seen_)
354 return;
355 running_ = true;
356 content::RunMessageLoop();
359 void Notify() {
360 seen_ = true;
361 if (running_)
362 base::MessageLoopForUI::current()->Quit();
365 private:
366 bool seen_;
367 bool running_;
370 WindowedChannelConnectionObserver observer_;
373 CloudPrintProxyPolicyStartupTest::CloudPrintProxyPolicyStartupTest()
374 : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {
377 CloudPrintProxyPolicyStartupTest::~CloudPrintProxyPolicyStartupTest() {
380 void CloudPrintProxyPolicyStartupTest::SetUp() {
381 TestingBrowserProcess::CreateInstance();
382 #if defined(OS_MACOSX)
383 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
384 EXPECT_TRUE(MockLaunchd::MakeABundle(temp_dir_.path(),
385 "CloudPrintProxyTest",
386 &bundle_path_,
387 &executable_path_));
388 mock_launchd_.reset(new MockLaunchd(executable_path_,
389 base::MessageLoopForUI::current(),
390 true, false));
391 scoped_launchd_instance_.reset(
392 new Launchd::ScopedInstance(mock_launchd_.get()));
393 #endif
395 // Ensure test does not use the standard profile directory. This is copied
396 // from InProcessBrowserTest::SetUp(). These tests require a more complex
397 // process startup so they are unable to just inherit from
398 // InProcessBrowserTest.
399 CommandLine* command_line = CommandLine::ForCurrentProcess();
400 base::FilePath user_data_dir =
401 command_line->GetSwitchValuePath(switches::kUserDataDir);
402 if (user_data_dir.empty()) {
403 ASSERT_TRUE(temp_user_data_dir_.CreateUniqueTempDir() &&
404 temp_user_data_dir_.IsValid())
405 << "Could not create temporary user data directory \""
406 << temp_user_data_dir_.path().value() << "\".";
408 user_data_dir = temp_user_data_dir_.path();
409 command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
411 ASSERT_TRUE(test_launcher_utils::OverrideUserDataDir(user_data_dir));
414 void CloudPrintProxyPolicyStartupTest::TearDown() {
415 TestingBrowserProcess::DeleteInstance();
418 base::ProcessHandle CloudPrintProxyPolicyStartupTest::Launch(
419 const std::string& name) {
420 EXPECT_FALSE(CheckServiceProcessReady());
422 startup_channel_id_ =
423 base::StringPrintf("%d.%p.%d",
424 base::GetCurrentProcId(), this,
425 base::RandInt(0, std::numeric_limits<int>::max()));
426 startup_channel_.reset(new IPC::ChannelProxy(
427 startup_channel_id_, IPC::Channel::MODE_SERVER,
428 this, IOMessageLoopProxy()));
430 #if defined(OS_POSIX)
431 base::FileHandleMappingVector ipc_file_list;
432 ipc_file_list.push_back(std::make_pair(
433 startup_channel_->TakeClientFileDescriptor(),
434 kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor));
435 base::ProcessHandle handle = SpawnChild(name, ipc_file_list, false);
436 #else
437 base::ProcessHandle handle = SpawnChild(name, false);
438 #endif
439 EXPECT_TRUE(handle);
440 return handle;
443 void CloudPrintProxyPolicyStartupTest::WaitForConnect() {
444 observer_.Wait();
445 EXPECT_TRUE(CheckServiceProcessReady());
446 EXPECT_TRUE(base::MessageLoopProxy::current().get());
447 ServiceProcessControl::GetInstance()->SetChannel(
448 new IPC::ChannelProxy(GetServiceProcessChannel(),
449 IPC::Channel::MODE_NAMED_CLIENT,
450 ServiceProcessControl::GetInstance(),
451 IOMessageLoopProxy()));
454 bool CloudPrintProxyPolicyStartupTest::Send(IPC::Message* message) {
455 return ServiceProcessControl::GetInstance()->Send(message);
458 void CloudPrintProxyPolicyStartupTest::ShutdownAndWaitForExitWithTimeout(
459 base::ProcessHandle handle) {
460 ASSERT_TRUE(Send(new ServiceMsg_Shutdown()));
462 int exit_code = -100;
463 bool exited =
464 base::WaitForExitCodeWithTimeout(handle, &exit_code,
465 TestTimeouts::action_timeout());
466 EXPECT_TRUE(exited);
467 EXPECT_EQ(exit_code, 0);
468 base::CloseProcessHandle(handle);
471 void CloudPrintProxyPolicyStartupTest::OnChannelConnected(int32 peer_pid) {
472 observer_.Notify();
475 CommandLine CloudPrintProxyPolicyStartupTest::MakeCmdLine(
476 const std::string& procname,
477 bool debug_on_start) {
478 CommandLine cl = MultiProcessTest::MakeCmdLine(procname, debug_on_start);
479 cl.AppendSwitchASCII(switches::kProcessChannelID, startup_channel_id_);
480 #if defined(OS_MACOSX)
481 cl.AppendSwitchASCII(kTestExecutablePath, executable_path_.value());
482 #endif
483 return cl;
486 TEST_F(CloudPrintProxyPolicyStartupTest, StartAndShutdown) {
487 TestingBrowserProcess* browser_process =
488 TestingBrowserProcess::GetGlobal();
489 TestingProfileManager profile_manager(browser_process);
490 ASSERT_TRUE(profile_manager.SetUp());
492 // Must be created after the TestingProfileManager since that creates the
493 // LocalState for the BrowserProcess. Must be created before profiles are
494 // constructed.
495 chrome::TestingIOThreadState testing_io_thread_state;
497 base::ProcessHandle handle =
498 Launch("CloudPrintMockService_StartEnabledWaitForQuit");
499 WaitForConnect();
500 ShutdownAndWaitForExitWithTimeout(handle);
501 content::RunAllPendingInMessageLoop();
504 BrowserContextKeyedService* CloudPrintProxyServiceFactoryForPolicyTest(
505 content::BrowserContext* profile) {
506 CloudPrintProxyService* service =
507 new CloudPrintProxyService(static_cast<Profile*>(profile));
508 service->Initialize();
509 return service;
512 TEST_F(CloudPrintProxyPolicyStartupTest, StartBrowserWithoutPolicy) {
513 base::ProcessHandle handle =
514 Launch("CloudPrintMockService_StartEnabledWaitForQuit");
516 // Setup the Browser Process with a full IOThread::Globals.
517 TestingBrowserProcess* browser_process =
518 TestingBrowserProcess::GetGlobal();
520 TestingProfileManager profile_manager(browser_process);
521 ASSERT_TRUE(profile_manager.SetUp());
523 // Must be created after the TestingProfileManager since that creates the
524 // LocalState for the BrowserProcess. Must be created before profiles are
525 // constructed.
526 chrome::TestingIOThreadState testing_io_thread_state;
528 TestingProfile* profile =
529 profile_manager.CreateTestingProfile("StartBrowserWithoutPolicy");
530 CloudPrintProxyServiceFactory::GetInstance()->
531 SetTestingFactory(profile, CloudPrintProxyServiceFactoryForPolicyTest);
533 TestingPrefServiceSyncable* prefs = profile->GetTestingPrefService();
534 prefs->SetUserPref(prefs::kCloudPrintEmail,
535 base::Value::CreateStringValue(
536 MockServiceIPCServer::EnabledUserId()));
538 CommandLine command_line(CommandLine::NO_PROGRAM);
539 command_line.AppendSwitch(switches::kCheckCloudPrintConnectorPolicy);
540 test_launcher_utils::PrepareBrowserCommandLineForTests(&command_line);
542 WaitForConnect();
543 base::RunLoop run_loop;
544 base::MessageLoop::current()->PostDelayedTask(
545 FROM_HERE,
546 run_loop.QuitClosure(),
547 TestTimeouts::action_timeout());
549 bool should_run_loop = LaunchBrowser(command_line, profile);
550 EXPECT_FALSE(should_run_loop);
551 if (should_run_loop)
552 run_loop.Run();
554 EXPECT_EQ(MockServiceIPCServer::EnabledUserId(),
555 prefs->GetString(prefs::kCloudPrintEmail));
557 ShutdownAndWaitForExitWithTimeout(handle);
558 content::RunAllPendingInMessageLoop();
559 profile_manager.DeleteTestingProfile("StartBrowserWithoutPolicy");
562 TEST_F(CloudPrintProxyPolicyStartupTest, StartBrowserWithPolicy) {
563 base::ProcessHandle handle =
564 Launch("CloudPrintMockService_StartEnabledExpectDisabled");
566 TestingBrowserProcess* browser_process =
567 TestingBrowserProcess::GetGlobal();
568 TestingProfileManager profile_manager(browser_process);
569 ASSERT_TRUE(profile_manager.SetUp());
571 // Must be created after the TestingProfileManager since that creates the
572 // LocalState for the BrowserProcess. Must be created before profiles are
573 // constructed.
574 chrome::TestingIOThreadState testing_io_thread_state;
576 TestingProfile* profile =
577 profile_manager.CreateTestingProfile("StartBrowserWithPolicy");
578 CloudPrintProxyServiceFactory::GetInstance()->
579 SetTestingFactory(profile, CloudPrintProxyServiceFactoryForPolicyTest);
581 TestingPrefServiceSyncable* prefs = profile->GetTestingPrefService();
582 prefs->SetUserPref(prefs::kCloudPrintEmail,
583 base::Value::CreateStringValue(
584 MockServiceIPCServer::EnabledUserId()));
585 prefs->SetManagedPref(prefs::kCloudPrintProxyEnabled,
586 base::Value::CreateBooleanValue(false));
588 CommandLine command_line(CommandLine::NO_PROGRAM);
589 command_line.AppendSwitch(switches::kCheckCloudPrintConnectorPolicy);
590 test_launcher_utils::PrepareBrowserCommandLineForTests(&command_line);
592 WaitForConnect();
593 base::RunLoop run_loop;
594 base::MessageLoop::current()->PostDelayedTask(
595 FROM_HERE,
596 run_loop.QuitClosure(),
597 TestTimeouts::action_timeout());
599 bool should_run_loop = LaunchBrowser(command_line, profile);
601 // No expectations on run_loop being true here; that would be a race
602 // condition.
603 if (should_run_loop)
604 run_loop.Run();
606 EXPECT_EQ("", prefs->GetString(prefs::kCloudPrintEmail));
608 ShutdownAndWaitForExitWithTimeout(handle);
609 content::RunAllPendingInMessageLoop();
610 profile_manager.DeleteTestingProfile("StartBrowserWithPolicy");