Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / process_singleton_mac_unittest.cc
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.
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <sys/file.h>
8
9 #include "chrome/browser/process_singleton.h"
10
11 #include "base/file_util.h"
12 #include "base/files/scoped_file.h"
13 #include "base/path_service.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "chrome/common/chrome_constants.h"
16 #include "chrome/common/chrome_paths.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "testing/platform_test.h"
19
20 namespace {
21
22 class ProcessSingletonMacTest : public PlatformTest {
23  public:
24   virtual void SetUp() {
25     PlatformTest::SetUp();
26
27     // Put the lock in a temporary directory.  Doesn't need to be a
28     // full profile to test this code.
29     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
30     lock_path_ = temp_dir_.path().Append(chrome::kSingletonLockFilename);
31   }
32
33   virtual void TearDown() {
34     PlatformTest::TearDown();
35
36     // Verify that the lock was released.
37     EXPECT_FALSE(IsLocked());
38   }
39
40   // Return |true| if the file exists and is locked.  Forces a failure
41   // in the containing test in case of error condition.
42   bool IsLocked() {
43     base::ScopedFD fd(HANDLE_EINTR(open(lock_path_.value().c_str(), O_RDONLY)));
44     if (!fd.is_valid()) {
45       EXPECT_EQ(ENOENT, errno) << "Unexpected error opening lockfile.";
46       return false;
47     }
48
49     int rc = HANDLE_EINTR(flock(fd.get(), LOCK_EX|LOCK_NB));
50
51     // Got the lock, so it wasn't already locked.  Close releases.
52     if (rc != -1)
53       return false;
54
55     // Someone else has the lock.
56     if (errno == EWOULDBLOCK)
57       return true;
58
59     EXPECT_EQ(EWOULDBLOCK, errno) << "Unexpected error acquiring lock.";
60     return false;
61   }
62
63   base::ScopedTempDir temp_dir_;
64   base::FilePath lock_path_;
65 };
66
67 // Test that the base case doesn't blow up.
68 TEST_F(ProcessSingletonMacTest, Basic) {
69   ProcessSingleton ps(temp_dir_.path(),
70                       ProcessSingleton::NotificationCallback());
71   EXPECT_FALSE(IsLocked());
72   EXPECT_TRUE(ps.Create());
73   EXPECT_TRUE(IsLocked());
74   ps.Cleanup();
75   EXPECT_FALSE(IsLocked());
76 }
77
78 // The destructor should release the lock.
79 TEST_F(ProcessSingletonMacTest, DestructorReleases) {
80   EXPECT_FALSE(IsLocked());
81   {
82     ProcessSingleton ps(temp_dir_.path(),
83                         ProcessSingleton::NotificationCallback());
84     EXPECT_TRUE(ps.Create());
85     EXPECT_TRUE(IsLocked());
86   }
87   EXPECT_FALSE(IsLocked());
88 }
89
90 // Multiple singletons should interlock appropriately.
91 TEST_F(ProcessSingletonMacTest, Interlock) {
92   ProcessSingleton ps1(temp_dir_.path(),
93                        ProcessSingleton::NotificationCallback());
94   ProcessSingleton ps2(temp_dir_.path(),
95                        ProcessSingleton::NotificationCallback());
96
97   // Windows and Linux use a command-line flag to suppress this, but
98   // it is on a sub-process so the scope is contained.  Rather than
99   // add additional API to process_singleton.h in an #ifdef, just tell
100   // the reader what to expect and move on.
101   LOG(ERROR) << "Expect two failures to obtain the lock.";
102
103   // When |ps1| has the lock, |ps2| cannot get it.
104   EXPECT_FALSE(IsLocked());
105   EXPECT_TRUE(ps1.Create());
106   EXPECT_TRUE(IsLocked());
107   EXPECT_FALSE(ps2.Create());
108   ps1.Cleanup();
109
110   // And when |ps2| has the lock, |ps1| cannot get it.
111   EXPECT_FALSE(IsLocked());
112   EXPECT_TRUE(ps2.Create());
113   EXPECT_TRUE(IsLocked());
114   EXPECT_FALSE(ps1.Create());
115   ps2.Cleanup();
116   EXPECT_FALSE(IsLocked());
117 }
118
119 // Like |Interlock| test, but via |NotifyOtherProcessOrCreate()|.
120 TEST_F(ProcessSingletonMacTest, NotifyOtherProcessOrCreate) {
121   ProcessSingleton ps1(temp_dir_.path(),
122                        ProcessSingleton::NotificationCallback());
123   ProcessSingleton ps2(temp_dir_.path(),
124                        ProcessSingleton::NotificationCallback());
125
126   // Windows and Linux use a command-line flag to suppress this, but
127   // it is on a sub-process so the scope is contained.  Rather than
128   // add additional API to process_singleton.h in an #ifdef, just tell
129   // the reader what to expect and move on.
130   LOG(ERROR) << "Expect two failures to obtain the lock.";
131
132   // When |ps1| has the lock, |ps2| cannot get it.
133   EXPECT_FALSE(IsLocked());
134   EXPECT_EQ(
135       ProcessSingleton::PROCESS_NONE,
136       ps1.NotifyOtherProcessOrCreate());
137   EXPECT_TRUE(IsLocked());
138   EXPECT_EQ(
139       ProcessSingleton::PROFILE_IN_USE,
140       ps2.NotifyOtherProcessOrCreate());
141   ps1.Cleanup();
142
143   // And when |ps2| has the lock, |ps1| cannot get it.
144   EXPECT_FALSE(IsLocked());
145   EXPECT_EQ(
146       ProcessSingleton::PROCESS_NONE,
147       ps2.NotifyOtherProcessOrCreate());
148   EXPECT_TRUE(IsLocked());
149   EXPECT_EQ(
150       ProcessSingleton::PROFILE_IN_USE,
151       ps1.NotifyOtherProcessOrCreate());
152   ps2.Cleanup();
153   EXPECT_FALSE(IsLocked());
154 }
155
156 // TODO(shess): Test that the lock is released when the process dies.
157 // DEATH_TEST?  I don't know.  If the code to communicate between
158 // browser processes is ever written, this all would need to be tested
159 // more like the other platforms, in which case it would be easy.
160
161 }  // namespace