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

Side by Side Diff: chrome/installer/util/delete_old_versions_unittest.cc

Issue 1666363002: Delete old files after an update. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: self-review Created 4 years, 9 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/util/delete_old_versions.h"
6
7 #include <set>
8
9 #include "base/files/file.h"
10 #include "base/files/file_enumerator.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/path_service.h"
17 #include "base/strings/string16.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "base/version.h"
21 #include "chrome/installer/test/alternate_version_generator.h"
22 #include "chrome/installer/util/installer_state.h"
23 #include "chrome/installer/util/util_constants.h"
24 #include "chrome/installer/util/work_item.h"
25 #include "chrome/installer/util/work_item_list.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace installer {
29 namespace {
grt (UTC plus 2) 2016/02/25 19:25:40 nit: blank line between these
fdoray 2016/02/26 17:00:05 Done.
30
31 class MockInstallerState : public InstallerState {
32 public:
33 explicit MockInstallerState(const base::FilePath& target_path)
34 : InstallerState(InstallerState::USER_LEVEL) {
35 target_path_ = target_path;
36 }
37
38 private:
39 DISALLOW_COPY_AND_ASSIGN(MockInstallerState);
40 };
41
42 const base::char16 kVersionA[] = L"47.0.0.0";
43 const base::char16 kVersionB[] = L"48.0.0.0";
44
45 class DeleteOldVersionsTest : public testing::Test {
46 protected:
47 DeleteOldVersionsTest() = default;
48
49 bool DeleteOldVersions() {
50 MockInstallerState installer_state(install_dir());
51 scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
52 AddDeleteOldVersionsWorkItem(installer_state, work_item_list.get());
53 return work_item_list->Do();
54 }
55
56 bool CreateInstallDir() { return install_dir_.CreateUniqueTempDir(); }
57
58 // Creates an executable with |name| and |version| in |install_dir_|.
59 bool CreateExecutable(const base::string16& name,
60 const base::string16& version) {
61 base::FilePath current_exe_path;
62 return base::PathService::Get(base::FILE_EXE, &current_exe_path) &&
63 upgrade_test::GenerateSpecificPEFileVersion(
64 current_exe_path, install_dir().Append(name),
65 base::Version(base::UTF16ToUTF8(version)));
66 }
67
68 // Creates a version directory named |name| in |install_dir_|.
69 bool CreateVersionDirectory(const base::string16& name) {
70 static const char kDummyContent[] = "dummy";
71 const base::FilePath version_dir_path(install_dir().Append(name));
72
73 return base::CreateDirectory(install_dir().Append(name)) &&
74 base::CreateDirectory(version_dir_path.Append(L"Installer")) &&
75 base::WriteFile(version_dir_path.Append(L"chrome.dll"),
76 kDummyContent, sizeof(kDummyContent)) &&
77 base::WriteFile(version_dir_path.Append(L"nacl64.exe"),
78 kDummyContent, sizeof(kDummyContent)) &&
79 base::WriteFile(version_dir_path.Append(L"icudtl.dat"),
80 kDummyContent, sizeof(kDummyContent)) &&
81 base::WriteFile(version_dir_path.Append(L"Installer\\setup.exe"),
82 kDummyContent, sizeof(kDummyContent));
83 }
84
85 // Returns the relative paths of all files and directories in |install_dir_|.
86 using FilePathSet = std::set<base::FilePath>;
87 FilePathSet GetInstallDirContent() const {
88 std::set<base::FilePath> content;
89 base::FileEnumerator file_enumerator(
90 install_dir(), true,
91 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
92 for (base::FilePath path = file_enumerator.Next(); !path.empty();
93 path = file_enumerator.Next()) {
94 DCHECK(base::StartsWith(path.value(), install_dir().value(),
95 base::CompareCase::SENSITIVE));
96 content.insert(base::FilePath(
97 path.value().substr(install_dir().value().size() + 1)));
98 }
99 return content;
100 }
101
102 // Adds to |file_path_set| all files and directories that are expected to be
103 // found in the version directory |version| before any attempt to delete it.
104 void AddVersionFiles(const base::string16& version,
105 FilePathSet* file_path_set) {
106 file_path_set->insert(base::FilePath(version));
107 file_path_set->insert(base::FilePath(version).Append(L"chrome.dll"));
108 file_path_set->insert(base::FilePath(version).Append(L"nacl64.exe"));
109 file_path_set->insert(base::FilePath(version).Append(L"icudtl.dat"));
110 file_path_set->insert(base::FilePath(version).Append(L"Installer"));
111 file_path_set->insert(
112 base::FilePath(version).Append(L"Installer\\setup.exe"));
113 }
114
115 base::FilePath install_dir() const { return install_dir_.path(); }
116
117 private:
118 base::ScopedTempDir install_dir_;
119
120 DISALLOW_COPY_AND_ASSIGN(DeleteOldVersionsTest);
121 };
122
123 } // namespace
124
125 // DeleteOldVersions() should return true when there is nothing to delete.
126 TEST_F(DeleteOldVersionsTest, DeleteEmptyInstallDir) {
127 ASSERT_TRUE(CreateInstallDir());
128 EXPECT_TRUE(DeleteOldVersions());
129 }
130
131 // An old executable without a matching directory should be deleted.
132 TEST_F(DeleteOldVersionsTest, DeleteOldExecutableWithoutMatchingDirectory) {
133 ASSERT_TRUE(CreateInstallDir());
134 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
135
136 EXPECT_TRUE(DeleteOldVersions());
137 EXPECT_TRUE(GetInstallDirContent().empty());
138 }
139
140 // DeleteOldVersions() should return false when it fails to delete an old
141 // executable that is in use.
142 TEST_F(DeleteOldVersionsTest,
143 DeleteInUseOldExecutableWithoutMatchingDirectory) {
144 ASSERT_TRUE(CreateInstallDir());
145 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
146
147 base::File file_in_use(install_dir().Append(installer::kChromeOldExe),
148 base::File::FLAG_OPEN | base::File::FLAG_READ);
149 ASSERT_TRUE(file_in_use.IsValid());
150
151 EXPECT_FALSE(DeleteOldVersions());
152 }
153
154 // chrome.exe and new_chrome.exe should never be deleted.
155 TEST_F(DeleteOldVersionsTest, DeleteNewExecutablesWithoutMatchingDirectory) {
156 ASSERT_TRUE(CreateInstallDir());
157 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionA));
158 ASSERT_TRUE(CreateExecutable(installer::kChromeNewExe, kVersionB));
159
160 EXPECT_TRUE(DeleteOldVersions());
161 FilePathSet expected_install_dir_content;
162 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe));
163 expected_install_dir_content.insert(base::FilePath(installer::kChromeNewExe));
164 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent());
165 }
166
167 // A directory without a matching executable should be deleted.
168 TEST_F(DeleteOldVersionsTest, DeleteDirectoryWithoutMatchingExecutable) {
169 ASSERT_TRUE(CreateInstallDir());
170 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
171
172 EXPECT_TRUE(DeleteOldVersions());
173 EXPECT_TRUE(GetInstallDirContent().empty());
174 }
175
176 // DeleteOldVersions() should return false when it fails to delete a file that
177 // is in use in a version directory.
178 TEST_F(DeleteOldVersionsTest, DeleteInUseDirectoryWithoutMatchingExecutable) {
179 ASSERT_TRUE(CreateInstallDir());
180 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
181
182 base::File file_in_use(install_dir().Append(kVersionA).Append(L"icudtl.dat"),
183 base::File::FLAG_OPEN | base::File::FLAG_READ);
184 ASSERT_TRUE(file_in_use.IsValid());
185
186 EXPECT_FALSE(DeleteOldVersions());
187 }
188
189 // A pair of matching old executable/version directory that is not in use should
190 // be deleted.
191 TEST_F(DeleteOldVersionsTest, DeleteOldExecutableWithMatchingDirectory) {
192 ASSERT_TRUE(CreateInstallDir());
193 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
194 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
195
196 EXPECT_TRUE(DeleteOldVersions());
197 EXPECT_TRUE(GetInstallDirContent().empty());
198 }
199
200 // chrome.exe, new_chrome.exe and their matching version directories should
201 // never be deleted.
202 TEST_F(DeleteOldVersionsTest, DeleteNewExecutablesWithMatchingDirectory) {
203 ASSERT_TRUE(CreateInstallDir());
204 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionA));
205 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
206 ASSERT_TRUE(CreateExecutable(installer::kChromeNewExe, kVersionB));
207 ASSERT_TRUE(CreateVersionDirectory(kVersionB));
208
209 EXPECT_TRUE(DeleteOldVersions());
210
211 FilePathSet expected_install_dir_content;
212 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe));
213 AddVersionFiles(kVersionA, &expected_install_dir_content);
214 expected_install_dir_content.insert(base::FilePath(installer::kChromeNewExe));
215 AddVersionFiles(kVersionB, &expected_install_dir_content);
216 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent());
217 }
218
219 // chrome.exe, new_chrome.exe and their matching version directories should
220 // never be deleted, even when files named old_chrome*.exe have the same
221 // versions as chrome.exe/new_chrome.exe. The old_chrome*.exe files, however,
222 // should be deleted.
223 TEST_F(DeleteOldVersionsTest,
224 DeleteNewExecutablesWithMatchingDirectoryAndOldExecutables) {
225 ASSERT_TRUE(CreateInstallDir());
226 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionA));
227 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
228 ASSERT_TRUE(CreateExecutable(installer::kChromeNewExe, kVersionB));
229 ASSERT_TRUE(CreateVersionDirectory(kVersionB));
230 ASSERT_TRUE(CreateExecutable(L"old_chrome.exe", kVersionA));
231 ASSERT_TRUE(CreateExecutable(L"old_chrome2.exe", kVersionB));
232
233 EXPECT_TRUE(DeleteOldVersions());
234
235 FilePathSet expected_install_dir_content;
236 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe));
237 AddVersionFiles(kVersionA, &expected_install_dir_content);
238 expected_install_dir_content.insert(base::FilePath(installer::kChromeNewExe));
239 AddVersionFiles(kVersionB, &expected_install_dir_content);
240 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent());
241 }
242
243 // No file should be deleted for a given version if the executable is in use.
244 TEST_F(DeleteOldVersionsTest, DeleteVersionWithExecutableInUse) {
245 ASSERT_TRUE(CreateInstallDir());
246 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
247 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
248
249 base::File file_in_use(install_dir().Append(installer::kChromeOldExe),
250 base::File::FLAG_OPEN | base::File::FLAG_READ);
251 ASSERT_TRUE(file_in_use.IsValid());
252
253 EXPECT_FALSE(DeleteOldVersions());
254
255 FilePathSet expected_install_dir_content;
256 expected_install_dir_content.insert(base::FilePath(installer::kChromeOldExe));
257 AddVersionFiles(kVersionA, &expected_install_dir_content);
258 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent());
259 }
260
261 // No file should be deleted for a given version if a .dll file in the version
262 // directory is in use.
263 TEST_F(DeleteOldVersionsTest, DeleteVersionWithVersionDirectoryDllInUse) {
264 ASSERT_TRUE(CreateInstallDir());
265 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
266 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
267
268 base::File file_in_use(install_dir().Append(kVersionA).Append(L"chrome.dll"),
269 base::File::FLAG_OPEN | base::File::FLAG_READ);
270 ASSERT_TRUE(file_in_use.IsValid());
271
272 EXPECT_FALSE(DeleteOldVersions());
273
274 FilePathSet expected_install_dir_content;
275 expected_install_dir_content.insert(base::FilePath(installer::kChromeOldExe));
276 AddVersionFiles(kVersionA, &expected_install_dir_content);
277 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent());
278 }
279
280 // No file should be deleted for a given version if a .exe file in the version
281 // directory is in use.
282 TEST_F(DeleteOldVersionsTest, DeleteVersionWithVersionDirectoryExeInUse) {
283 ASSERT_TRUE(CreateInstallDir());
284 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
285 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
286
287 base::File file_in_use(
288 install_dir().Append(kVersionA).Append(L"Installer\\setup.exe"),
289 base::File::FLAG_OPEN | base::File::FLAG_READ);
290 ASSERT_TRUE(file_in_use.IsValid());
291
292 EXPECT_FALSE(DeleteOldVersions());
293
294 FilePathSet expected_install_dir_content;
295 expected_install_dir_content.insert(base::FilePath(installer::kChromeOldExe));
296 AddVersionFiles(kVersionA, &expected_install_dir_content);
297 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent());
298 }
299
300 // DeleteOldVersions() should return false when it tries to delete all the files
301 // of a version but one of them can't be deleted because it is in use.
302 TEST_F(DeleteOldVersionsTest, DeleteVersionWithUnimportantFileInUse) {
303 ASSERT_TRUE(CreateInstallDir());
304 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
305 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
306
307 base::File file_in_use(install_dir().Append(kVersionA).Append(L"icudtl.dat"),
308 base::File::FLAG_OPEN | base::File::FLAG_READ);
309 ASSERT_TRUE(file_in_use.IsValid());
310
311 EXPECT_FALSE(DeleteOldVersions());
312 }
313
314 // If an installation directory contains a file named chrome.exe with a matching
315 // directory v1 and a file name old_chrome.exe with a matching directory v2,
316 // old_chrome.exe and v2 should be deleted but chrome.exe and v1 shouldn't.
317 TEST_F(DeleteOldVersionsTest, TypicalAfterRenameState) {
318 ASSERT_TRUE(CreateInstallDir());
319 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA));
320 ASSERT_TRUE(CreateVersionDirectory(kVersionA));
321 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionB));
322 ASSERT_TRUE(CreateVersionDirectory(kVersionB));
323
324 EXPECT_TRUE(DeleteOldVersions());
325
326 FilePathSet expected_install_dir_content;
327 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe));
328 AddVersionFiles(kVersionB, &expected_install_dir_content);
329 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent());
330 }
331
332 } // namespace installer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698