Index: rlz/lib/rlz_lib_test.cc |
diff --git a/rlz/lib/rlz_lib_test.cc b/rlz/lib/rlz_lib_test.cc |
index 0f8cb4c21c4379114ae43d4c45abb42b3a485366..118f48cb8cdc1292e12b5e0b4400fef1f6a9f599 100644 |
--- a/rlz/lib/rlz_lib_test.cc |
+++ b/rlz/lib/rlz_lib_test.cc |
@@ -13,6 +13,7 @@ |
// The "GGLA" brand is used to test the normal code flow of the code, and the |
// "TEST" brand is used to test the supplementary brand code code flow. |
+#include "base/eintr_wrapper.h" |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
#include "testing/gmock/include/gmock/gmock.h" |
@@ -795,7 +796,9 @@ class ReadonlyRlzDirectoryTest : public RlzLibTestNoMachineState { |
void ReadonlyRlzDirectoryTest::SetUp() { |
RlzLibTestNoMachineState::SetUp(); |
// Make the rlz directory non-writeable. |
- chmod(temp_dir_.path().value().c_str(), 0500); |
+ int chmod_result = chmod(temp_dir_.path().value().c_str(), 0500); |
+ ASSERT_EQ(0, chmod_result); |
+ |
} |
TEST_F(ReadonlyRlzDirectoryTest, WriteFails) { |
@@ -821,4 +824,51 @@ TEST_F(ReadonlyRlzDirectoryTest, SupplementaryBrandingDoesNotCrash) { |
EXPECT_FALSE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL)); |
} |
+ |
+// Regression test for http://crbug.com/141108 |
+TEST_F(RlzLibTest, ConcurrentStoreAccessWithProcessExitsWhileLockHeld) { |
+ // See the comment at the top of WriteFails. |
+ if (!rlz_lib::SupplementaryBranding::GetBrand().empty()) |
+ return; |
+ |
+ std::vector<pid_t> pids; |
+ for (int i = 0; i < 10; ++i) { |
+ pid_t pid = fork(); |
+ ASSERT_NE(-1, pid); |
+ if (pid == 0) { |
+ // Child. |
+ { |
+ // SupplementaryBranding is a RAII object for the rlz lock. |
+ rlz_lib::SupplementaryBranding branding("TEST"); |
+ |
+ // Simulate a crash while holding the lock in some of the children. |
+ if (i > 0 && i % 3 == 0) |
+ _exit(0); |
+ |
+ // Note: Since this is in a forked child, a failing expectation won't |
+ // make the test fail. It does however cause lots of "check failed" |
+ // error output. The parent process will then check the exit code |
+ // below to make the test fail. |
+ bool success = rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
+ rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL); |
+ EXPECT_TRUE(success); |
+ _exit(success ? 0 : 1); |
+ } |
+ _exit(0); |
+ } else { |
+ // Parent. |
+ pids.push_back(pid); |
+ } |
+ } |
+ |
+ int status; |
+ for (size_t i = 0; i < pids.size(); ++i) { |
+ if (HANDLE_EINTR(waitpid(pids[i], &status, 0)) != -1) |
+ EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0); |
+ } |
+ |
+ // No child should have the lock at this point, not even the crashed ones. |
+ EXPECT_TRUE(rlz_lib::RecordProductEvent(rlz_lib::TOOLBAR_NOTIFIER, |
+ rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL)); |
+} |
#endif |