Commit c7fa28c6 authored by Lei Zhang's avatar Lei Zhang Committed by Commit Bot

Add a test for the Cloud Print service's interaction with WM_QUIT.

BUG=860827

Change-Id: I403f2b4ada07242cc035ebb12ec1d1f6145ac42d
Reviewed-on: https://chromium-review.googlesource.com/1249838Reviewed-by: default avatarGabriel Charette <gab@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/master@{#594850}
parent 94d82d59
...@@ -206,6 +206,7 @@ void ServiceProcessControl::Disconnect() { ...@@ -206,6 +206,7 @@ void ServiceProcessControl::Disconnect() {
void ServiceProcessControl::OnProcessLaunched() { void ServiceProcessControl::OnProcessLaunched() {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (launcher_->launched()) { if (launcher_->launched()) {
saved_pid_ = launcher_->saved_pid();
UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents", UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceEvents",
SERVICE_EVENT_LAUNCHED, SERVICE_EVENT_MAX); SERVICE_EVENT_LAUNCHED, SERVICE_EVENT_MAX);
// After we have successfully created the service process we try to connect // After we have successfully created the service process we try to connect
...@@ -382,6 +383,7 @@ void ServiceProcessControl::Launcher::DoRun() { ...@@ -382,6 +383,7 @@ void ServiceProcessControl::Launcher::DoRun() {
#endif #endif
process_ = base::LaunchProcess(*cmd_line_, options); process_ = base::LaunchProcess(*cmd_line_, options);
if (process_.IsValid()) { if (process_.IsValid()) {
saved_pid_ = process_.Pid();
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO}, base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
base::Bind(&Launcher::DoDetectLaunched, this)); base::Bind(&Launcher::DoDetectLaunched, this));
} else { } else {
......
...@@ -113,6 +113,8 @@ class ServiceProcessControl : public UpgradeObserver { ...@@ -113,6 +113,8 @@ class ServiceProcessControl : public UpgradeObserver {
return remote_interfaces_; return remote_interfaces_;
} }
base::ProcessId GetLaunchedPidForTesting() const { return saved_pid_; }
private: private:
// This class is responsible for launching the service process on the // This class is responsible for launching the service process on the
// PROCESS_LAUNCHER thread. // PROCESS_LAUNCHER thread.
...@@ -126,6 +128,7 @@ class ServiceProcessControl : public UpgradeObserver { ...@@ -126,6 +128,7 @@ class ServiceProcessControl : public UpgradeObserver {
void Run(const base::Closure& task); void Run(const base::Closure& task);
bool launched() const { return launched_; } bool launched() const { return launched_; }
base::ProcessId saved_pid() const { return saved_pid_; }
private: private:
friend class base::RefCountedThreadSafe<ServiceProcessControl::Launcher>; friend class base::RefCountedThreadSafe<ServiceProcessControl::Launcher>;
...@@ -142,6 +145,10 @@ class ServiceProcessControl : public UpgradeObserver { ...@@ -142,6 +145,10 @@ class ServiceProcessControl : public UpgradeObserver {
bool launched_; bool launched_;
uint32_t retry_count_; uint32_t retry_count_;
base::Process process_; base::Process process_;
// Used to save the process id for |process_| upon successful launch.
// Only used for testing.
base::ProcessId saved_pid_;
}; };
friend class MockServiceProcessControl; friend class MockServiceProcessControl;
...@@ -204,6 +211,9 @@ class ServiceProcessControl : public UpgradeObserver { ...@@ -204,6 +211,9 @@ class ServiceProcessControl : public UpgradeObserver {
// If true changes to UpgradeObserver are applied, if false they are ignored. // If true changes to UpgradeObserver are applied, if false they are ignored.
bool apply_changes_from_upgrade_observer_; bool apply_changes_from_upgrade_observer_;
// Same as |Launcher::saved_pid_|.
base::ProcessId saved_pid_;
base::WeakPtrFactory<ServiceProcessControl> weak_factory_; base::WeakPtrFactory<ServiceProcessControl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ServiceProcessControl); DISALLOW_COPY_AND_ASSIGN(ServiceProcessControl);
......
...@@ -32,6 +32,13 @@ ...@@ -32,6 +32,13 @@
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#if defined(OS_WIN)
#include <Tlhelp32.h>
#include <windows.h>
#include "base/threading/platform_thread.h"
#endif
class ServiceProcessControlBrowserTest class ServiceProcessControlBrowserTest
: public InProcessBrowserTest { : public InProcessBrowserTest {
public: public:
...@@ -439,3 +446,66 @@ IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_Histograms) { ...@@ -439,3 +446,66 @@ IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_Histograms) {
EXPECT_CALL(*this, MockHistogramsCallback()).Times(1); EXPECT_CALL(*this, MockHistogramsCallback()).Times(1);
run_loop.Run(); run_loop.Run();
} }
#if defined(OS_WIN)
// Test for https://crbug.com/860827 to make sure it is possible to stop the
// Cloud Print service with WM_QUIT.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, StopViaWmQuit) {
LaunchServiceProcessControlAndWait();
// Make sure we are connected to the service process.
ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
cloud_print::mojom::CloudPrintPtr cloud_print_proxy;
ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
&cloud_print_proxy);
base::RunLoop run_loop;
cloud_print_proxy->GetCloudPrintProxyInfo(
base::BindOnce([](base::OnceClosure done, bool, const std::string&,
const std::string&) { std::move(done).Run(); },
run_loop.QuitClosure()));
run_loop.Run();
base::ProcessId pid =
ServiceProcessControl::GetInstance()->GetLaunchedPidForTesting();
base::Process process = base::Process::Open(pid);
ASSERT_TRUE(process.IsValid());
// Find the first thread associated with |pid|.
base::PlatformThreadId tid = 0;
{
HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
ASSERT_NE(INVALID_HANDLE_VALUE, snapshot);
THREADENTRY32 thread_entry = {0};
thread_entry.dwSize = sizeof(THREADENTRY32);
BOOL result = ::Thread32First(snapshot, &thread_entry);
while (result) {
if (thread_entry.th32OwnerProcessID == pid) {
tid = thread_entry.th32ThreadID;
break;
}
result = Thread32Next(snapshot, &thread_entry);
}
}
ASSERT_NE(base::kInvalidThreadId, tid);
// And then shutdown the service process via WM_QUIT.
ASSERT_TRUE(::PostThreadMessage(tid, WM_QUIT, 0, 0));
// And wait for it to stop running.
constexpr int kRetries = 5;
for (int retry = 0; retry < kRetries; ++retry) {
if (!process.IsRunning()) {
// |process| stopped running. Test is done.
return;
}
// |process| did not stop running. Wait.
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
}
// |process| still did not stop running after |kRetries|.
FAIL();
}
#endif // defined(OS_WIN)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment