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

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

Issue 2292293002: Add installer::SetupSingleton. (Closed)
Patch Set: 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>
grt (UTC plus 2) 2016/08/31 12:03:48 nit: 'w'
fdoray 2016/08/31 19:14:21 Done.
grt (UTC plus 2) 2016/09/01 12:05:39 try harder. :-)
8
9 #include <string>
10 #include <vector>
11
12 #include "base/base_switches.h"
13 #include "base/command_line.h"
14 #include "base/files/file.h"
15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
17 #include "base/files/scoped_temp_dir.h"
18 #include "base/process/launch.h"
19 #include "base/strings/string16.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/time/time.h"
22 #include "chrome/installer/util/installer_state.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "testing/multiprocess_func_list.h"
25
26 namespace installer {
27
28 namespace {
29
30 constexpr char kInstallDirSwitch[] = "install-dir";
31 constexpr char kSystemLevelSwitch[] = "system-level";
32 constexpr base::char16 kSentinelFileName[] = L"sentinel.txt";
33 constexpr base::char16 kTestProcessReadyEventName[] =
34 L"Local\\ChromeSetupSingletonTestProcessReady";
35 constexpr int kWaitDurationMs = 50;
grt (UTC plus 2) 2016/08/31 12:03:48 can you get rid of this and use something in base/
fdoray 2016/08/31 19:14:22 Done.
36
37 enum ErrorCodes {
38 SUCCESS,
39 SENTINEL_FILE_CREATE_ERROR,
40 SENTINEL_FILE_DELETE_ERROR,
41 WAIT_RETURNED_FALSE,
42 };
43
44 base::string16 ReplaceBackslashes(const base::string16& path) {
45 base::string16 path_without_backslashes(path);
46 std::replace(path_without_backslashes.begin(), path_without_backslashes.end(),
grt (UTC plus 2) 2016/08/31 12:03:48 #include <algorithm>
fdoray 2016/08/31 19:14:21 N/A
47 L'\\', L'/');
48 return path_without_backslashes;
49 }
50
51 int CreateAndDeleteSentinelFile(const base::FilePath& install_dir) {
52 const base::FilePath sentinel_file_path =
53 install_dir.Append(kSentinelFileName);
54
55 base::File file(sentinel_file_path,
grt (UTC plus 2) 2016/08/31 12:03:48 nit: no need to keep this in a local var. you can
fdoray 2016/08/31 19:14:21 Done.
56 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
57 if (!file.IsValid())
58 return SENTINEL_FILE_CREATE_ERROR;
59 file.Close();
60
61 base::PlatformThread::Sleep(
62 base::TimeDelta::FromMilliseconds(kWaitDurationMs));
63
64 if (!base::DeleteFile(sentinel_file_path, false))
65 return SENTINEL_FILE_DELETE_ERROR;
66
67 return SUCCESS;
68 }
69
70 MULTIPROCESS_TEST_MAIN(SetupSingletonTestExclusiveAccessProcessMain) {
71 base::CommandLine* const command_line =
72 base::CommandLine::ForCurrentProcess();
73
74 // Acquire the exclusive right to modify the Chrome installation.
75 const base::FilePath install_dir =
76 command_line->GetSwitchValuePath(kInstallDirSwitch);
77 SetupSingleton setup_singleton(install_dir,
78 command_line->HasSwitch(kSystemLevelSwitch));
79
80 // Create a sentinel file and delete it after a few milliseconds. This will
81 // fail it the sentinel file already exists (which shouldn't be the case since
grt (UTC plus 2) 2016/08/31 12:03:48 it -> if
fdoray 2016/08/31 19:14:21 Done.
82 // we are in the scope of a SetupSingleton).
83 return CreateAndDeleteSentinelFile(install_dir);
84 }
85
86 MULTIPROCESS_TEST_MAIN(SetupSingletonTestWaitOtherSetupSingletonProcessMain) {
87 base::CommandLine* const command_line =
88 base::CommandLine::ForCurrentProcess();
89
90 // Acquire the exclusive right to modify the Chrome installation.
91 const base::FilePath install_dir =
92 command_line->GetSwitchValuePath(kInstallDirSwitch);
93 SetupSingleton setup_singleton(install_dir,
94 command_line->HasSwitch(kSystemLevelSwitch));
95
96 // Signal an event to indicate that this process has acquired the
97 // SetupSingleton.
98 base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
99 nullptr, FALSE, FALSE,
100 (kTestProcessReadyEventName + ReplaceBackslashes(install_dir.value()))
101 .c_str())));
102 ready_event.Signal();
103
104 // Wait indefinitely. This should only return when another SetupSingleton is
105 // instantiated for |install_dir|.
106 if (!setup_singleton.Wait(base::TimeDelta::Max()))
107 return WAIT_RETURNED_FALSE;
108
109 // Create a sentinel file and delete it after a few milliseconds. This will
110 // fail it the sentinel file already exists (which shouldn't be the case since
111 // we are in the scope of a SetupSingleton).
112 return CreateAndDeleteSentinelFile(install_dir);
113 }
114
115 class SetupSingletonTest
116 : public testing::TestWithParam<InstallerState::Level> {
117 public:
118 SetupSingletonTest() = default;
119
120 void SetUp() override { ASSERT_TRUE(install_dir_.CreateUniqueTempDir()); }
121
122 base::Process SpawnChildProcess(const std::string& process_name) {
123 base::CommandLine command_line = *base::CommandLine::ForCurrentProcess();
124 command_line.SetProgram(
125 base::MakeAbsoluteFilePath(command_line.GetProgram()));
126 command_line.AppendSwitchASCII(::switches::kTestChildProcess, process_name);
127 command_line.AppendSwitchPath(kInstallDirSwitch, install_dir_.path());
128 if (GetParam() == InstallerState::SYSTEM_LEVEL)
129 command_line.AppendSwitch(kSystemLevelSwitch);
130 base::LaunchOptions options;
131 options.start_hidden = true;
132 return LaunchProcess(command_line, options);
133 }
134
135 const base::FilePath& install_dir_path() const { return install_dir_.path(); }
136
137 private:
138 base::ScopedTempDir install_dir_;
139
140 DISALLOW_COPY_AND_ASSIGN(SetupSingletonTest);
141 };
142
143 } // namespace
144
145 INSTANTIATE_TEST_CASE_P(InstallLevel,
146 SetupSingletonTest,
147 ::testing::Values(InstallerState::SYSTEM_LEVEL,
grt (UTC plus 2) 2016/08/31 12:03:48 i find that the logs (especially failures) are eas
fdoray 2016/08/31 19:14:21 N/A
148 InstallerState::USER_LEVEL));
149
150 // Verify that a single SetupSingleton can be active at a time for a given
151 // Chrome installation.
152 TEST_P(SetupSingletonTest, ExclusiveAccess) {
153 constexpr size_t kNumProcesses = 10;
grt (UTC plus 2) 2016/08/31 12:03:48 nit: use int for this
fdoray 2016/08/31 19:14:21 Done.
154
155 std::vector<base::Process> processes;
156 for (size_t i = 0; i < kNumProcesses; ++i) {
157 processes.push_back(
158 SpawnChildProcess("SetupSingletonTestExclusiveAccessProcessMain"));
159 }
160
161 for (base::Process& process : processes) {
162 int exit_code = 0;
163 EXPECT_TRUE(process.WaitForExit(&exit_code));
164 EXPECT_EQ(SUCCESS, exit_code);
165 }
166 }
167
168 // Verify that Wait() returns false when its delay expires.
169 TEST_P(SetupSingletonTest, WaitNoOtherSetupSingleton) {
170 SetupSingleton setup_singleton(install_dir_path(),
171 GetParam() == InstallerState::SYSTEM_LEVEL);
172 EXPECT_FALSE(
173 setup_singleton.Wait(base::TimeDelta::FromMilliseconds(kWaitDurationMs)));
174 }
175
176 // Verify that Wait() returns true immediately when another SetupSingleton is
177 // instantiated.
178 TEST_P(SetupSingletonTest, WaitOtherSetupSingleton) {
179 base::Process wait_process =
180 SpawnChildProcess("SetupSingletonTestWaitOtherSetupSingletonProcessMain");
181
182 // Wait until the other process acquires the SetupSingleton.
183 base::WaitableEvent ready_event(base::win::ScopedHandle(::CreateEvent(
184 nullptr, FALSE, FALSE, (kTestProcessReadyEventName +
185 ReplaceBackslashes(install_dir_path().value()))
186 .c_str())));
187 ready_event.Wait();
188
189 // Acquire the SetupSingleton.
190 SetupSingleton setup_singleton(install_dir_path(),
191 GetParam() == InstallerState::SYSTEM_LEVEL);
192
193 // Create a sentinel file and delete it after a few milliseconds. This will
194 // fail it the sentinel file already exists (which shouldn't be the case since
195 // we are in the scope of a SetupSingleton).
196 EXPECT_EQ(SUCCESS, CreateAndDeleteSentinelFile(install_dir_path()));
197
198 // Join |wait_process|.
199 int exit_code = 0;
200 EXPECT_TRUE(wait_process.WaitForExit(&exit_code));
201 EXPECT_EQ(SUCCESS, exit_code);
202 }
203
204 } // namespace installer
OLDNEW
« chrome/installer/setup/setup_singleton.cc ('K') | « chrome/installer/setup/setup_singleton.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698