OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/process_singleton.h" | 5 #include "chrome/browser/process_singleton.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <signal.h> | 8 #include <signal.h> |
9 #include <sys/types.h> | 9 #include <sys/types.h> |
10 #include <sys/un.h> | 10 #include <sys/un.h> |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 ASSERT_GT(len, 0); | 153 ASSERT_GT(len, 0); |
154 std::string cookie(buf, len); | 154 std::string cookie(buf, len); |
155 | 155 |
156 base::FilePath remote_cookie_path = socket_target_path.DirName(). | 156 base::FilePath remote_cookie_path = socket_target_path.DirName(). |
157 Append(chrome::kSingletonCookieFilename); | 157 Append(chrome::kSingletonCookieFilename); |
158 len = readlink(remote_cookie_path.value().c_str(), buf, PATH_MAX); | 158 len = readlink(remote_cookie_path.value().c_str(), buf, PATH_MAX); |
159 ASSERT_GT(len, 0); | 159 ASSERT_GT(len, 0); |
160 EXPECT_EQ(cookie, std::string(buf, len)); | 160 EXPECT_EQ(cookie, std::string(buf, len)); |
161 } | 161 } |
162 | 162 |
163 ProcessSingleton::NotifyResult NotifyOtherProcess( | 163 ProcessSingleton::NotifyResult NotifyOtherProcess(bool override_kill) { |
164 bool override_kill, | |
165 base::TimeDelta timeout) { | |
166 scoped_ptr<TestableProcessSingleton> process_singleton( | 164 scoped_ptr<TestableProcessSingleton> process_singleton( |
167 CreateProcessSingleton()); | 165 CreateProcessSingleton()); |
168 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); | 166 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); |
169 command_line.AppendArg("about:blank"); | 167 command_line.AppendArg("about:blank"); |
170 if (override_kill) { | 168 if (override_kill) { |
171 process_singleton->OverrideCurrentPidForTesting( | 169 process_singleton->OverrideCurrentPidForTesting( |
172 base::GetCurrentProcId() + 1); | 170 base::GetCurrentProcId() + 1); |
173 process_singleton->OverrideKillCallbackForTesting( | 171 process_singleton->OverrideKillCallbackForTesting( |
174 base::Bind(&ProcessSingletonPosixTest::KillCallback, | 172 base::Bind(&ProcessSingletonPosixTest::KillCallback, |
175 base::Unretained(this))); | 173 base::Unretained(this))); |
176 } | 174 } |
177 | 175 |
178 return process_singleton->NotifyOtherProcessWithTimeout( | 176 return process_singleton->NotifyOtherProcessWithTimeout( |
179 command_line, timeout.InSeconds(), true); | 177 command_line, kRetryAttempts, timeout(), true); |
180 } | 178 } |
181 | 179 |
182 // A helper method to call ProcessSingleton::NotifyOtherProcessOrCreate(). | 180 // A helper method to call ProcessSingleton::NotifyOtherProcessOrCreate(). |
183 ProcessSingleton::NotifyResult NotifyOtherProcessOrCreate( | 181 ProcessSingleton::NotifyResult NotifyOtherProcessOrCreate( |
184 const std::string& url, | 182 const std::string& url) { |
185 base::TimeDelta timeout) { | |
186 scoped_ptr<TestableProcessSingleton> process_singleton( | 183 scoped_ptr<TestableProcessSingleton> process_singleton( |
187 CreateProcessSingleton()); | 184 CreateProcessSingleton()); |
188 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); | 185 CommandLine command_line(CommandLine::ForCurrentProcess()->GetProgram()); |
189 command_line.AppendArg(url); | 186 command_line.AppendArg(url); |
190 return process_singleton->NotifyOtherProcessWithTimeoutOrCreate( | 187 return process_singleton->NotifyOtherProcessWithTimeoutOrCreate( |
191 command_line, timeout.InSeconds()); | 188 command_line, kRetryAttempts, timeout()); |
192 } | 189 } |
193 | 190 |
194 void CheckNotified() { | 191 void CheckNotified() { |
195 ASSERT_TRUE(process_singleton_on_thread_ != NULL); | 192 ASSERT_TRUE(process_singleton_on_thread_ != NULL); |
196 ASSERT_EQ(1u, process_singleton_on_thread_->callback_command_lines_.size()); | 193 ASSERT_EQ(1u, process_singleton_on_thread_->callback_command_lines_.size()); |
197 bool found = false; | 194 bool found = false; |
198 for (size_t i = 0; | 195 for (size_t i = 0; |
199 i < process_singleton_on_thread_->callback_command_lines_[0].size(); | 196 i < process_singleton_on_thread_->callback_command_lines_[0].size(); |
200 ++i) { | 197 ++i) { |
201 if (process_singleton_on_thread_->callback_command_lines_[0][i] == | 198 if (process_singleton_on_thread_->callback_command_lines_[0][i] == |
(...skipping 23 matching lines...) Expand all Loading... |
225 signal_event_.Signal(); | 222 signal_event_.Signal(); |
226 } | 223 } |
227 | 224 |
228 base::FilePath user_data_path_; | 225 base::FilePath user_data_path_; |
229 base::FilePath lock_path_; | 226 base::FilePath lock_path_; |
230 base::FilePath socket_path_; | 227 base::FilePath socket_path_; |
231 base::FilePath cookie_path_; | 228 base::FilePath cookie_path_; |
232 int kill_callbacks_; | 229 int kill_callbacks_; |
233 | 230 |
234 private: | 231 private: |
| 232 static const int kRetryAttempts = 2; |
| 233 |
| 234 base::TimeDelta timeout() const { |
| 235 return TestTimeouts::tiny_timeout() * kRetryAttempts; |
| 236 } |
| 237 |
235 void CreateProcessSingletonInternal() { | 238 void CreateProcessSingletonInternal() { |
236 ASSERT_TRUE(!process_singleton_on_thread_); | 239 ASSERT_TRUE(!process_singleton_on_thread_); |
237 process_singleton_on_thread_ = CreateProcessSingleton(); | 240 process_singleton_on_thread_ = CreateProcessSingleton(); |
238 ASSERT_EQ(ProcessSingleton::PROCESS_NONE, | 241 ASSERT_EQ(ProcessSingleton::PROCESS_NONE, |
239 process_singleton_on_thread_->NotifyOtherProcessOrCreate()); | 242 process_singleton_on_thread_->NotifyOtherProcessOrCreate()); |
240 } | 243 } |
241 | 244 |
242 void DestructProcessSingleton() { | 245 void DestructProcessSingleton() { |
243 ASSERT_TRUE(process_singleton_on_thread_); | 246 ASSERT_TRUE(process_singleton_on_thread_); |
244 delete process_singleton_on_thread_; | 247 delete process_singleton_on_thread_; |
(...skipping 19 matching lines...) Expand all Loading... |
264 // If this test flakes, use http://crbug.com/74554. | 267 // If this test flakes, use http://crbug.com/74554. |
265 TEST_F(ProcessSingletonPosixTest, CheckSocketFile) { | 268 TEST_F(ProcessSingletonPosixTest, CheckSocketFile) { |
266 CreateProcessSingletonOnThread(); | 269 CreateProcessSingletonOnThread(); |
267 VerifyFiles(); | 270 VerifyFiles(); |
268 } | 271 } |
269 | 272 |
270 // TODO(james.su@gmail.com): port following tests to Windows. | 273 // TODO(james.su@gmail.com): port following tests to Windows. |
271 // Test success case of NotifyOtherProcess(). | 274 // Test success case of NotifyOtherProcess(). |
272 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessSuccess) { | 275 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessSuccess) { |
273 CreateProcessSingletonOnThread(); | 276 CreateProcessSingletonOnThread(); |
274 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, | 277 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, NotifyOtherProcess(true)); |
275 NotifyOtherProcess(true, TestTimeouts::action_timeout())); | |
276 CheckNotified(); | 278 CheckNotified(); |
277 } | 279 } |
278 | 280 |
279 // Test failure case of NotifyOtherProcess(). | 281 // Test failure case of NotifyOtherProcess(). |
280 // Disabled, http://crbug.com/407065 . | 282 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessFailure) { |
281 TEST_F(ProcessSingletonPosixTest, DISABLED_NotifyOtherProcessFailure) { | |
282 CreateProcessSingletonOnThread(); | 283 CreateProcessSingletonOnThread(); |
283 | 284 |
284 BlockWorkerThread(); | 285 BlockWorkerThread(); |
285 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, | 286 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, NotifyOtherProcess(true)); |
286 NotifyOtherProcess(true, TestTimeouts::action_timeout())); | |
287 | |
288 ASSERT_EQ(1, kill_callbacks_); | 287 ASSERT_EQ(1, kill_callbacks_); |
289 UnblockWorkerThread(); | 288 UnblockWorkerThread(); |
290 } | 289 } |
291 | 290 |
292 // Test that we don't kill ourselves by accident if a lockfile with the same pid | 291 // Test that we don't kill ourselves by accident if a lockfile with the same pid |
293 // happens to exist. | 292 // happens to exist. |
294 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessNoSuicide) { | 293 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessNoSuicide) { |
295 CreateProcessSingletonOnThread(); | 294 CreateProcessSingletonOnThread(); |
296 // Replace lockfile with one containing our own pid. | 295 // Replace lockfile with one containing our own pid. |
297 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 296 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
298 std::string symlink_content = base::StringPrintf( | 297 std::string symlink_content = base::StringPrintf( |
299 "%s%c%u", | 298 "%s%c%u", |
300 net::GetHostName().c_str(), | 299 net::GetHostName().c_str(), |
301 '-', | 300 '-', |
302 base::GetCurrentProcId()); | 301 base::GetCurrentProcId()); |
303 EXPECT_EQ(0, symlink(symlink_content.c_str(), lock_path_.value().c_str())); | 302 EXPECT_EQ(0, symlink(symlink_content.c_str(), lock_path_.value().c_str())); |
304 | 303 |
305 // Remove socket so that we will not be able to notify the existing browser. | 304 // Remove socket so that we will not be able to notify the existing browser. |
306 EXPECT_EQ(0, unlink(socket_path_.value().c_str())); | 305 EXPECT_EQ(0, unlink(socket_path_.value().c_str())); |
307 | 306 |
308 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, | 307 EXPECT_EQ(ProcessSingleton::PROCESS_NONE, NotifyOtherProcess(false)); |
309 NotifyOtherProcess(false, TestTimeouts::action_timeout())); | |
310 // If we've gotten to this point without killing ourself, the test succeeded. | 308 // If we've gotten to this point without killing ourself, the test succeeded. |
311 } | 309 } |
312 | 310 |
313 // Test that we can still notify a process on the same host even after the | 311 // Test that we can still notify a process on the same host even after the |
314 // hostname changed. | 312 // hostname changed. |
315 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessHostChanged) { | 313 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessHostChanged) { |
316 CreateProcessSingletonOnThread(); | 314 CreateProcessSingletonOnThread(); |
317 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 315 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
318 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 316 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
319 | 317 |
320 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, | 318 EXPECT_EQ(ProcessSingleton::PROCESS_NOTIFIED, NotifyOtherProcess(false)); |
321 NotifyOtherProcess(false, TestTimeouts::action_timeout())); | |
322 CheckNotified(); | 319 CheckNotified(); |
323 } | 320 } |
324 | 321 |
325 // Test that we fail when lock says process is on another host and we can't | 322 // Test that we fail when lock says process is on another host and we can't |
326 // notify it over the socket. | 323 // notify it over the socket. |
327 // Disabled, http://crbug.com/407065 . | 324 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessDifferingHost) { |
328 TEST_F(ProcessSingletonPosixTest, DISABLED_NotifyOtherProcessDifferingHost) { | |
329 CreateProcessSingletonOnThread(); | 325 CreateProcessSingletonOnThread(); |
330 | 326 |
331 BlockWorkerThread(); | 327 BlockWorkerThread(); |
332 | 328 |
333 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 329 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
334 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 330 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
335 | 331 |
336 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, | 332 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, NotifyOtherProcess(false)); |
337 NotifyOtherProcess(false, TestTimeouts::action_timeout())); | |
338 | 333 |
339 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); | 334 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); |
340 | 335 |
341 UnblockWorkerThread(); | 336 UnblockWorkerThread(); |
342 } | 337 } |
343 | 338 |
344 // Test that we fail when lock says process is on another host and we can't | 339 // Test that we fail when lock says process is on another host and we can't |
345 // notify it over the socket. | 340 // notify it over the socket. |
346 // Disabled, http://crbug.com/407065 . | 341 TEST_F(ProcessSingletonPosixTest, NotifyOtherProcessOrCreate_DifferingHost) { |
347 TEST_F(ProcessSingletonPosixTest, | |
348 DISABLED_NotifyOtherProcessOrCreate_DifferingHost) { | |
349 CreateProcessSingletonOnThread(); | 342 CreateProcessSingletonOnThread(); |
350 | 343 |
351 BlockWorkerThread(); | 344 BlockWorkerThread(); |
352 | 345 |
353 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 346 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
354 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 347 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
355 | 348 |
356 std::string url("about:blank"); | 349 std::string url("about:blank"); |
357 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, | 350 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, NotifyOtherProcessOrCreate(url)); |
358 NotifyOtherProcessOrCreate(url, TestTimeouts::action_timeout())); | |
359 | 351 |
360 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); | 352 ASSERT_EQ(0, unlink(lock_path_.value().c_str())); |
361 | 353 |
362 UnblockWorkerThread(); | 354 UnblockWorkerThread(); |
363 } | 355 } |
364 | 356 |
365 // Test that Create fails when another browser is using the profile directory. | 357 // Test that Create fails when another browser is using the profile directory. |
366 TEST_F(ProcessSingletonPosixTest, CreateFailsWithExistingBrowser) { | 358 TEST_F(ProcessSingletonPosixTest, CreateFailsWithExistingBrowser) { |
367 CreateProcessSingletonOnThread(); | 359 CreateProcessSingletonOnThread(); |
368 | 360 |
(...skipping 30 matching lines...) Expand all Loading... |
399 CreateProcessSingletonOnThread(); | 391 CreateProcessSingletonOnThread(); |
400 // Change the cookie. | 392 // Change the cookie. |
401 EXPECT_EQ(0, unlink(cookie_path_.value().c_str())); | 393 EXPECT_EQ(0, unlink(cookie_path_.value().c_str())); |
402 EXPECT_EQ(0, symlink("INCORRECTCOOKIE", cookie_path_.value().c_str())); | 394 EXPECT_EQ(0, symlink("INCORRECTCOOKIE", cookie_path_.value().c_str())); |
403 | 395 |
404 // Also change the hostname, so the remote does not retry. | 396 // Also change the hostname, so the remote does not retry. |
405 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); | 397 EXPECT_EQ(0, unlink(lock_path_.value().c_str())); |
406 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); | 398 EXPECT_EQ(0, symlink("FAKEFOOHOST-1234", lock_path_.value().c_str())); |
407 | 399 |
408 std::string url("about:blank"); | 400 std::string url("about:blank"); |
409 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, | 401 EXPECT_EQ(ProcessSingleton::PROFILE_IN_USE, NotifyOtherProcessOrCreate(url)); |
410 NotifyOtherProcessOrCreate(url, TestTimeouts::action_timeout())); | |
411 } | 402 } |
412 | 403 |
413 #if defined(OS_MACOSX) | 404 #if defined(OS_MACOSX) |
414 // Test that if there is an existing lock file, and we could not flock() | 405 // Test that if there is an existing lock file, and we could not flock() |
415 // it, then exit. | 406 // it, then exit. |
416 TEST_F(ProcessSingletonPosixTest, CreateRespectsOldMacLock) { | 407 TEST_F(ProcessSingletonPosixTest, CreateRespectsOldMacLock) { |
417 scoped_ptr<TestableProcessSingleton> process_singleton( | 408 scoped_ptr<TestableProcessSingleton> process_singleton( |
418 CreateProcessSingleton()); | 409 CreateProcessSingleton()); |
419 base::ScopedFD lock_fd(HANDLE_EINTR( | 410 base::ScopedFD lock_fd(HANDLE_EINTR( |
420 open(lock_path_.value().c_str(), O_RDWR | O_CREAT | O_EXLOCK, 0644))); | 411 open(lock_path_.value().c_str(), O_RDWR | O_CREAT | O_EXLOCK, 0644))); |
421 ASSERT_TRUE(lock_fd.is_valid()); | 412 ASSERT_TRUE(lock_fd.is_valid()); |
422 EXPECT_FALSE(process_singleton->Create()); | 413 EXPECT_FALSE(process_singleton->Create()); |
423 base::File::Info info; | 414 base::File::Info info; |
424 EXPECT_TRUE(base::GetFileInfo(lock_path_, &info)); | 415 EXPECT_TRUE(base::GetFileInfo(lock_path_, &info)); |
425 EXPECT_FALSE(info.is_directory); | 416 EXPECT_FALSE(info.is_directory); |
426 EXPECT_FALSE(info.is_symbolic_link); | 417 EXPECT_FALSE(info.is_symbolic_link); |
427 } | 418 } |
428 | 419 |
429 // Test that if there is an existing lock file, and it's not locked, we replace | 420 // Test that if there is an existing lock file, and it's not locked, we replace |
430 // it. | 421 // it. |
431 TEST_F(ProcessSingletonPosixTest, CreateReplacesOldMacLock) { | 422 TEST_F(ProcessSingletonPosixTest, CreateReplacesOldMacLock) { |
432 scoped_ptr<TestableProcessSingleton> process_singleton( | 423 scoped_ptr<TestableProcessSingleton> process_singleton( |
433 CreateProcessSingleton()); | 424 CreateProcessSingleton()); |
434 EXPECT_EQ(0, base::WriteFile(lock_path_, "", 0)); | 425 EXPECT_EQ(0, base::WriteFile(lock_path_, "", 0)); |
435 EXPECT_TRUE(process_singleton->Create()); | 426 EXPECT_TRUE(process_singleton->Create()); |
436 VerifyFiles(); | 427 VerifyFiles(); |
437 } | 428 } |
438 #endif // defined(OS_MACOSX) | 429 #endif // defined(OS_MACOSX) |
OLD | NEW |