OLD | NEW |
---|---|
(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 | |
30 namespace { | |
31 | |
32 class MockInstallerState : public InstallerState { | |
33 public: | |
34 explicit MockInstallerState(const base::FilePath& target_path) | |
35 : InstallerState(InstallerState::USER_LEVEL) { | |
36 target_path_ = target_path; | |
37 } | |
38 | |
39 private: | |
40 DISALLOW_COPY_AND_ASSIGN(MockInstallerState); | |
41 }; | |
42 | |
43 const base::char16 kVersionA[] = L"47.0.0.0"; | |
44 const base::char16 kVersionB[] = L"48.0.0.0"; | |
45 | |
46 class DeleteOldVersionsTest : public testing::Test { | |
47 protected: | |
48 DeleteOldVersionsTest() = default; | |
49 | |
50 bool DeleteOldVersions() { | |
grt (UTC plus 2)
2016/02/29 21:43:18
void?
fdoray
2016/03/02 18:44:56
Done.
| |
51 MockInstallerState installer_state(install_dir()); | |
52 scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | |
53 AddDeleteOldVersionsWorkItem(installer_state, work_item_list.get()); | |
54 work_item_list->Do(); | |
55 } | |
56 | |
57 bool CreateInstallDir() { return install_dir_.CreateUniqueTempDir(); } | |
58 | |
59 // Creates an executable with |name| and |version| in |install_dir_|. | |
60 bool CreateExecutable(const base::string16& name, | |
61 const base::string16& version) { | |
62 base::FilePath current_exe_path; | |
63 return base::PathService::Get(base::FILE_EXE, ¤t_exe_path) && | |
64 upgrade_test::GenerateSpecificPEFileVersion( | |
65 current_exe_path, install_dir().Append(name), | |
66 base::Version(base::UTF16ToUTF8(version))); | |
67 } | |
68 | |
69 // Creates a version directory named |name| in |install_dir_|. | |
70 bool CreateVersionDirectory(const base::string16& name) { | |
71 static const char kDummyContent[] = "dummy"; | |
72 const base::FilePath version_dir_path(install_dir().Append(name)); | |
73 | |
74 return base::CreateDirectory(install_dir().Append(name)) && | |
75 base::CreateDirectory(version_dir_path.Append(L"Installer")) && | |
76 base::WriteFile(version_dir_path.Append(L"chrome.dll"), | |
77 kDummyContent, sizeof(kDummyContent)) && | |
78 base::WriteFile(version_dir_path.Append(L"nacl64.exe"), | |
79 kDummyContent, sizeof(kDummyContent)) && | |
80 base::WriteFile(version_dir_path.Append(L"icudtl.dat"), | |
81 kDummyContent, sizeof(kDummyContent)) && | |
82 base::WriteFile(version_dir_path.Append(L"Installer\\setup.exe"), | |
83 kDummyContent, sizeof(kDummyContent)); | |
84 } | |
85 | |
86 // Returns the relative paths of all files and directories in |install_dir_|. | |
87 using FilePathSet = std::set<base::FilePath>; | |
88 FilePathSet GetInstallDirContent() const { | |
89 std::set<base::FilePath> content; | |
90 base::FileEnumerator file_enumerator( | |
91 install_dir(), true, | |
92 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | |
93 for (base::FilePath path = file_enumerator.Next(); !path.empty(); | |
94 path = file_enumerator.Next()) { | |
95 DCHECK(base::StartsWith(path.value(), install_dir().value(), | |
96 base::CompareCase::SENSITIVE)); | |
97 content.insert(base::FilePath( | |
98 path.value().substr(install_dir().value().size() + 1))); | |
99 } | |
100 return content; | |
101 } | |
102 | |
103 // Adds to |file_path_set| all files and directories that are expected to be | |
104 // found in the version directory |version| before any attempt to delete it. | |
105 void AddVersionFiles(const base::string16& version, | |
106 FilePathSet* file_path_set) { | |
107 file_path_set->insert(base::FilePath(version)); | |
108 file_path_set->insert(base::FilePath(version).Append(L"chrome.dll")); | |
109 file_path_set->insert(base::FilePath(version).Append(L"nacl64.exe")); | |
110 file_path_set->insert(base::FilePath(version).Append(L"icudtl.dat")); | |
111 file_path_set->insert(base::FilePath(version).Append(L"Installer")); | |
112 file_path_set->insert( | |
113 base::FilePath(version).Append(L"Installer\\setup.exe")); | |
114 } | |
115 | |
116 base::FilePath install_dir() const { return install_dir_.path(); } | |
117 | |
118 private: | |
119 base::ScopedTempDir install_dir_; | |
120 | |
121 DISALLOW_COPY_AND_ASSIGN(DeleteOldVersionsTest); | |
122 }; | |
123 | |
124 } // namespace | |
125 | |
126 // An old executable without a matching directory should be deleted. | |
127 TEST_F(DeleteOldVersionsTest, DeleteOldExecutableWithoutMatchingDirectory) { | |
128 ASSERT_TRUE(CreateInstallDir()); | |
129 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA)); | |
130 | |
131 DeleteOldVersions(); | |
132 EXPECT_TRUE(GetInstallDirContent().empty()); | |
133 } | |
134 | |
135 // chrome.exe and new_chrome.exe should never be deleted. | |
136 TEST_F(DeleteOldVersionsTest, DeleteNewExecutablesWithoutMatchingDirectory) { | |
137 ASSERT_TRUE(CreateInstallDir()); | |
138 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionA)); | |
139 ASSERT_TRUE(CreateExecutable(installer::kChromeNewExe, kVersionB)); | |
140 | |
141 DeleteOldVersions(); | |
142 FilePathSet expected_install_dir_content; | |
143 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe)); | |
144 expected_install_dir_content.insert(base::FilePath(installer::kChromeNewExe)); | |
145 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent()); | |
146 } | |
147 | |
148 // A directory without a matching executable should be deleted. | |
149 TEST_F(DeleteOldVersionsTest, DeleteDirectoryWithoutMatchingExecutable) { | |
150 ASSERT_TRUE(CreateInstallDir()); | |
151 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
152 | |
153 DeleteOldVersions(); | |
154 EXPECT_TRUE(GetInstallDirContent().empty()); | |
155 } | |
156 | |
157 // A pair of matching old executable/version directory that is not in use should | |
158 // be deleted. | |
159 TEST_F(DeleteOldVersionsTest, DeleteOldExecutableWithMatchingDirectory) { | |
160 ASSERT_TRUE(CreateInstallDir()); | |
161 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA)); | |
162 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
163 | |
164 DeleteOldVersions(); | |
165 EXPECT_TRUE(GetInstallDirContent().empty()); | |
166 } | |
167 | |
168 // chrome.exe, new_chrome.exe and their matching version directories should | |
169 // never be deleted. | |
170 TEST_F(DeleteOldVersionsTest, DeleteNewExecutablesWithMatchingDirectory) { | |
171 ASSERT_TRUE(CreateInstallDir()); | |
172 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionA)); | |
173 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
174 ASSERT_TRUE(CreateExecutable(installer::kChromeNewExe, kVersionB)); | |
175 ASSERT_TRUE(CreateVersionDirectory(kVersionB)); | |
176 | |
177 DeleteOldVersions(); | |
178 | |
179 FilePathSet expected_install_dir_content; | |
180 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe)); | |
181 AddVersionFiles(kVersionA, &expected_install_dir_content); | |
182 expected_install_dir_content.insert(base::FilePath(installer::kChromeNewExe)); | |
183 AddVersionFiles(kVersionB, &expected_install_dir_content); | |
184 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent()); | |
185 } | |
186 | |
187 // chrome.exe, new_chrome.exe and their matching version directories should | |
188 // never be deleted, even when files named old_chrome*.exe have the same | |
189 // versions as chrome.exe/new_chrome.exe. The old_chrome*.exe files, however, | |
190 // should be deleted. | |
191 TEST_F(DeleteOldVersionsTest, | |
192 DeleteNewExecutablesWithMatchingDirectoryAndOldExecutables) { | |
193 ASSERT_TRUE(CreateInstallDir()); | |
194 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionA)); | |
195 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
196 ASSERT_TRUE(CreateExecutable(installer::kChromeNewExe, kVersionB)); | |
197 ASSERT_TRUE(CreateVersionDirectory(kVersionB)); | |
198 ASSERT_TRUE(CreateExecutable(L"old_chrome.exe", kVersionA)); | |
199 ASSERT_TRUE(CreateExecutable(L"old_chrome2.exe", kVersionB)); | |
200 | |
201 DeleteOldVersions(); | |
202 | |
203 FilePathSet expected_install_dir_content; | |
204 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe)); | |
205 AddVersionFiles(kVersionA, &expected_install_dir_content); | |
206 expected_install_dir_content.insert(base::FilePath(installer::kChromeNewExe)); | |
207 AddVersionFiles(kVersionB, &expected_install_dir_content); | |
208 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent()); | |
209 } | |
210 | |
211 // No file should be deleted for a given version if the executable is in use. | |
212 TEST_F(DeleteOldVersionsTest, DeleteVersionWithExecutableInUse) { | |
213 ASSERT_TRUE(CreateInstallDir()); | |
214 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA)); | |
215 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
216 | |
217 base::File file_in_use(install_dir().Append(installer::kChromeOldExe), | |
218 base::File::FLAG_OPEN | base::File::FLAG_READ); | |
219 ASSERT_TRUE(file_in_use.IsValid()); | |
220 | |
221 DeleteOldVersions(); | |
222 | |
223 FilePathSet expected_install_dir_content; | |
224 expected_install_dir_content.insert(base::FilePath(installer::kChromeOldExe)); | |
225 AddVersionFiles(kVersionA, &expected_install_dir_content); | |
226 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent()); | |
227 } | |
228 | |
229 // No file should be deleted for a given version if a .dll file in the version | |
230 // directory is in use. | |
231 TEST_F(DeleteOldVersionsTest, DeleteVersionWithVersionDirectoryDllInUse) { | |
232 ASSERT_TRUE(CreateInstallDir()); | |
233 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA)); | |
234 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
235 | |
236 base::File file_in_use(install_dir().Append(kVersionA).Append(L"chrome.dll"), | |
237 base::File::FLAG_OPEN | base::File::FLAG_READ); | |
238 ASSERT_TRUE(file_in_use.IsValid()); | |
239 | |
240 DeleteOldVersions(); | |
241 | |
242 FilePathSet expected_install_dir_content; | |
243 expected_install_dir_content.insert(base::FilePath(installer::kChromeOldExe)); | |
244 AddVersionFiles(kVersionA, &expected_install_dir_content); | |
245 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent()); | |
246 } | |
247 | |
248 // No file should be deleted for a given version if a .exe file in the version | |
249 // directory is in use. | |
250 TEST_F(DeleteOldVersionsTest, DeleteVersionWithVersionDirectoryExeInUse) { | |
251 ASSERT_TRUE(CreateInstallDir()); | |
252 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA)); | |
253 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
254 | |
255 base::File file_in_use( | |
256 install_dir().Append(kVersionA).Append(L"Installer\\setup.exe"), | |
257 base::File::FLAG_OPEN | base::File::FLAG_READ); | |
258 ASSERT_TRUE(file_in_use.IsValid()); | |
259 | |
260 DeleteOldVersions(); | |
261 | |
262 FilePathSet expected_install_dir_content; | |
263 expected_install_dir_content.insert(base::FilePath(installer::kChromeOldExe)); | |
264 AddVersionFiles(kVersionA, &expected_install_dir_content); | |
265 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent()); | |
266 } | |
267 | |
268 // If an installation directory contains a file named chrome.exe with a matching | |
269 // directory v1 and a file name old_chrome.exe with a matching directory v2, | |
270 // old_chrome.exe and v2 should be deleted but chrome.exe and v1 shouldn't. | |
271 TEST_F(DeleteOldVersionsTest, TypicalAfterRenameState) { | |
272 ASSERT_TRUE(CreateInstallDir()); | |
273 ASSERT_TRUE(CreateExecutable(installer::kChromeOldExe, kVersionA)); | |
274 ASSERT_TRUE(CreateVersionDirectory(kVersionA)); | |
275 ASSERT_TRUE(CreateExecutable(installer::kChromeExe, kVersionB)); | |
276 ASSERT_TRUE(CreateVersionDirectory(kVersionB)); | |
277 | |
278 DeleteOldVersions(); | |
279 | |
280 FilePathSet expected_install_dir_content; | |
281 expected_install_dir_content.insert(base::FilePath(installer::kChromeExe)); | |
282 AddVersionFiles(kVersionB, &expected_install_dir_content); | |
283 EXPECT_EQ(expected_install_dir_content, GetInstallDirContent()); | |
284 } | |
285 | |
286 } // namespace installer | |
OLD | NEW |