Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Side by Side Diff: chrome/installer/setup/setup_singleton_unittest.cc

Issue 2292293002: Add installer::SetupSingleton. (Closed)
Patch Set: self-review Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "chrome/installer/setup/setup_singleton.h"
6
7 #include <windows.h>
8
9 #include <string>
10 #include <vector>
11
12 #include "base/command_line.h"
13 #include "base/files/file.h"
14 #include "base/files/file_path.h"
15 #include "base/files/scoped_temp_dir.h"
16 #include "base/strings/string16.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/test/multiprocess_test.h"
19 #include "base/test/test_timeouts.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/time/time.h"
22 #include "chrome/installer/util/installation_state.h"
23 #include "chrome/installer/util/installer_state.h"
24 #include "chrome/installer/util/master_preferences.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "testing/multiprocess_func_list.h"
27
28 namespace installer {
29
30 namespace {
31
32 constexpr char kInstallDirSwitch[] = "install-dir";
33 constexpr base::char16 kSentinelFileName[] = L"sentinel.txt";
grt (UTC plus 2) 2016/09/06 20:22:11 constexpr base::FilePath::CharType kSentinelFileNa
fdoray 2016/09/06 20:49:54 Done.
34 constexpr base::char16 kTestProcessReadyEventName[] =
35 L"Local\\ChromeSetupSingletonTestProcessReady";
36
37 enum ErrorCode {
38 SUCCESS,
39 SETUP_SINGLETON_ACQUISITION_FAILED,
40 SENTINEL_FILE_CREATE_ERROR,
41 WAIT_RETURNED_FALSE,
42 };
43
44 base::CommandLine GetDummyCommandLine() {
45 return base::CommandLine(base::FilePath(FILE_PATH_LITERAL("dummy.exe")));
46 }
47
48 base::string16 HashFilePath(const base::FilePath& path) {
49 return base::SizeTToString16(
50 std::hash<base::FilePath::StringType>()(path.value()));
grt (UTC plus 2) 2016/09/06 20:22:11 #include <functional>
fdoray 2016/09/06 20:49:54 Done.
51 }
52
53 ErrorCode CreateAndDeleteSentinelFile(const base::FilePath& install_dir) {
54 const base::FilePath sentinel_file_path =
55 install_dir.Append(kSentinelFileName);
56
57 base::File file(sentinel_file_path, base::File::FLAG_CREATE |
58 base::File::FLAG_WRITE |
59 base::File::FLAG_DELETE_ON_CLOSE);
60 if (!file.IsValid())
61 return SENTINEL_FILE_CREATE_ERROR;
62
63 base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
64 return SUCCESS;
65 }
66
67 MULTIPROCESS_TEST_MAIN(SetupSingletonTestExclusiveAccessProcessMain) {
68 base::CommandLine* const command_line =
69 base::CommandLine::ForCurrentProcess();
70 const base::FilePath install_dir =
71 command_line->GetSwitchValuePath(kInstallDirSwitch);
72
73 InstallationState original_state;
74 InstallerState installer_state;
75 installer_state.set_target_path_for_testing(install_dir);
76
77 // Acquire the exclusive right to modify the Chrome installation.
78 std::unique_ptr<SetupSingleton> setup_singleton(SetupSingleton::Acquire(
79 GetDummyCommandLine(), MasterPreferences::ForCurrentProcess(),
80 &original_state, &installer_state));
81 if (!setup_singleton)
82 return SETUP_SINGLETON_ACQUISITION_FAILED;
83
84 // Create a sentinel file and delete it after a few milliseconds. This will
85 // fail if the sentinel file already exists (which shouldn't be the case since
86 // we are in the scope of a SetupSingleton).
87 return CreateAndDeleteSentinelFile(install_dir);
88 }
89
90 MULTIPROCESS_TEST_MAIN(SetupSingletonTestWaitForInterruptProcessMain) {
91 base::CommandLine* const command_line =
92 base::CommandLine::ForCurrentProcess();
93 const base::FilePath install_dir =
94 command_line->GetSwitchValuePath(kInstallDirSwitch);
95
96 InstallationState original_state;
97 InstallerState installer_state;
98 installer_state.set_target_path_for_testing(install_dir);
99
100 // Acquire the exclusive right to modify the Chrome installation.
101 std::unique_ptr<SetupSingleton> setup_singleton(SetupSingleton::Acquire(
102 GetDummyCommandLine(), MasterPreferences::ForCurrentProcess(),
103 &original_state, &installer_state));
104 if (!setup_singleton)
105 return SETUP_SINGLETON_ACQUISITION_FAILED;
106
107 // Signal an event to indicate that this process has acquired the
108 // SetupSingleton.
109 base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
110 nullptr, FALSE, FALSE,
111 (kTestProcessReadyEventName + HashFilePath(install_dir)).c_str())));
112 ready_event.Signal();
113
114 // Wait indefinitely. This should only return when another SetupSingleton is
115 // instantiated for |install_dir|.
116 if (!setup_singleton->WaitForInterrupt(base::TimeDelta::Max()))
117 return WAIT_RETURNED_FALSE;
118
119 // Create a sentinel file and delete it after a few milliseconds. This will
120 // fail if the sentinel file already exists (which shouldn't be the case since
121 // we are in the scope of a SetupSingleton).
122 return CreateAndDeleteSentinelFile(install_dir);
123 }
124
125 class SetupSingletonTest : public base::MultiProcessTest {
126 public:
127 SetupSingletonTest() = default;
128
129 void SetUp() override { ASSERT_TRUE(install_dir_.CreateUniqueTempDir()); }
130
131 base::CommandLine MakeCmdLine(const std::string& procname) override {
132 base::CommandLine command_line =
133 base::MultiProcessTest::MakeCmdLine(procname);
134 command_line.AppendSwitchPath(kInstallDirSwitch, install_dir_path());
135 return command_line;
136 }
137
138 base::Process SpawnChildProcess(const std::string& process_name) {
139 base::LaunchOptions options;
140 options.start_hidden = true;
141 return SpawnChildWithOptions(process_name, options);
142 }
143
144 const base::FilePath& install_dir_path() const { return install_dir_.path(); }
145
146 private:
147 base::ScopedTempDir install_dir_;
148
149 DISALLOW_COPY_AND_ASSIGN(SetupSingletonTest);
150 };
151
152 } // namespace
153
154 // Verify that a single SetupSingleton can be active at a time for a given
155 // Chrome installation.
156 TEST_F(SetupSingletonTest, ExclusiveAccess) {
157 constexpr int kNumProcesses = 10;
158
159 std::vector<base::Process> processes;
160 for (int i = 0; i < kNumProcesses; ++i) {
161 processes.push_back(
162 SpawnChildProcess("SetupSingletonTestExclusiveAccessProcessMain"));
163 }
164
165 for (base::Process& process : processes) {
166 int exit_code = 0;
167 EXPECT_TRUE(process.WaitForExit(&exit_code));
168 EXPECT_EQ(SUCCESS, exit_code);
169 }
170 }
171
172 // Verify that WaitForInterrupt() returns false when its delay expires before
173 TEST_F(SetupSingletonTest, WaitForInterruptNoInterrupt) {
174 InstallationState original_state;
175 InstallerState installer_state;
176 installer_state.set_target_path_for_testing(install_dir_path());
177 std::unique_ptr<SetupSingleton> setup_singleton(SetupSingleton::Acquire(
178 GetDummyCommandLine(), MasterPreferences::ForCurrentProcess(),
179 &original_state, &installer_state));
180 ASSERT_TRUE(setup_singleton);
181
182 EXPECT_FALSE(setup_singleton->WaitForInterrupt(TestTimeouts::tiny_timeout()));
183 }
184
185 // Verify that WaitForInterrupt() returns true immediately when another process
186 // tries to acquire a SetupSingleton.
187 TEST_F(SetupSingletonTest, WaitForInterruptWithInterrupt) {
188 base::Process wait_process =
189 SpawnChildProcess("SetupSingletonTestWaitForInterruptProcessMain");
190
191 // Wait until the other process acquires the SetupSingleton.
192 base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
193 nullptr, FALSE, FALSE,
194 (kTestProcessReadyEventName + HashFilePath(install_dir_path()))
195 .c_str())));
196 ready_event.Wait();
197
198 // Acquire the SetupSingleton.
199 InstallationState original_state;
200 InstallerState installer_state;
201 installer_state.set_target_path_for_testing(install_dir_path());
202 std::unique_ptr<SetupSingleton> setup_singleton(SetupSingleton::Acquire(
203 GetDummyCommandLine(), MasterPreferences::ForCurrentProcess(),
204 &original_state, &installer_state));
205 ASSERT_TRUE(setup_singleton);
206
207 // Create a sentinel file and delete it after a few milliseconds. This will
208 // fail if the sentinel file already exists (which shouldn't be the case since
209 // we are in the scope of a SetupSingleton).
210 EXPECT_EQ(SUCCESS, CreateAndDeleteSentinelFile(install_dir_path()));
211
212 // Join |wait_process|.
213 int exit_code = 0;
214 EXPECT_TRUE(wait_process.WaitForExit(&exit_code));
215 EXPECT_EQ(SUCCESS, exit_code);
216 }
217
218 } // namespace installer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698