1 // Copyright (c) 2011 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.
9 #include "base/base_paths.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string_util.h"
15 #include "chrome/installer/util/delete_tree_work_item.h"
16 #include "chrome/installer/util/work_item.h"
17 #include "testing/gtest/include/gtest/gtest.h"
21 class DeleteTreeWorkItemTest
: public testing::Test
{
23 void SetUp() override
{ ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir()); }
25 // The temporary directory used to contain the test operations.
26 base::ScopedTempDir temp_dir_
;
29 // Simple function to dump some text into a new file.
30 void CreateTextFile(const std::wstring
& filename
,
31 const std::wstring
& contents
) {
33 file
.open(filename
.c_str());
34 ASSERT_TRUE(file
.is_open());
39 const wchar_t text_content_1
[] = L
"delete me";
43 // Delete a tree without key path. Everything should be deleted.
44 TEST_F(DeleteTreeWorkItemTest
, DeleteTreeNoKeyPath
) {
45 // Create tree to be deleted.
46 base::FilePath
dir_name_delete(temp_dir_
.path());
47 dir_name_delete
= dir_name_delete
.AppendASCII("to_be_delete");
48 base::CreateDirectory(dir_name_delete
);
49 ASSERT_TRUE(base::PathExists(dir_name_delete
));
51 base::FilePath
dir_name_delete_1(dir_name_delete
);
52 dir_name_delete_1
= dir_name_delete_1
.AppendASCII("1");
53 base::CreateDirectory(dir_name_delete_1
);
54 ASSERT_TRUE(base::PathExists(dir_name_delete_1
));
56 base::FilePath
dir_name_delete_2(dir_name_delete
);
57 dir_name_delete_2
= dir_name_delete_2
.AppendASCII("2");
58 base::CreateDirectory(dir_name_delete_2
);
59 ASSERT_TRUE(base::PathExists(dir_name_delete_2
));
61 base::FilePath
file_name_delete_1(dir_name_delete_1
);
62 file_name_delete_1
= file_name_delete_1
.AppendASCII("File_1.txt");
63 CreateTextFile(file_name_delete_1
.value(), text_content_1
);
64 ASSERT_TRUE(base::PathExists(file_name_delete_1
));
66 base::FilePath
file_name_delete_2(dir_name_delete_2
);
67 file_name_delete_2
= file_name_delete_2
.AppendASCII("File_2.txt");
68 CreateTextFile(file_name_delete_2
.value(), text_content_1
);
69 ASSERT_TRUE(base::PathExists(file_name_delete_2
));
72 base::ScopedTempDir temp_dir
;
73 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
75 std::vector
<base::FilePath
> key_files
;
76 scoped_ptr
<DeleteTreeWorkItem
> work_item(
77 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete
, temp_dir
.path(),
79 EXPECT_TRUE(work_item
->Do());
81 // everything should be gone
82 EXPECT_FALSE(base::PathExists(file_name_delete_1
));
83 EXPECT_FALSE(base::PathExists(file_name_delete_2
));
84 EXPECT_FALSE(base::PathExists(dir_name_delete
));
86 work_item
->Rollback();
87 // everything should come back
88 EXPECT_TRUE(base::PathExists(file_name_delete_1
));
89 EXPECT_TRUE(base::PathExists(file_name_delete_2
));
90 EXPECT_TRUE(base::PathExists(dir_name_delete
));
94 // Delete a tree with keypath but not in use. Everything should be gone.
95 // Rollback should bring back everything
96 TEST_F(DeleteTreeWorkItemTest
, DeleteTree
) {
97 // Create tree to be deleted
98 base::FilePath
dir_name_delete(temp_dir_
.path());
99 dir_name_delete
= dir_name_delete
.AppendASCII("to_be_delete");
100 base::CreateDirectory(dir_name_delete
);
101 ASSERT_TRUE(base::PathExists(dir_name_delete
));
103 base::FilePath
dir_name_delete_1(dir_name_delete
);
104 dir_name_delete_1
= dir_name_delete_1
.AppendASCII("1");
105 base::CreateDirectory(dir_name_delete_1
);
106 ASSERT_TRUE(base::PathExists(dir_name_delete_1
));
108 base::FilePath
dir_name_delete_2(dir_name_delete
);
109 dir_name_delete_2
= dir_name_delete_2
.AppendASCII("2");
110 base::CreateDirectory(dir_name_delete_2
);
111 ASSERT_TRUE(base::PathExists(dir_name_delete_2
));
113 base::FilePath
file_name_delete_1(dir_name_delete_1
);
114 file_name_delete_1
= file_name_delete_1
.AppendASCII("File_1.txt");
115 CreateTextFile(file_name_delete_1
.value(), text_content_1
);
116 ASSERT_TRUE(base::PathExists(file_name_delete_1
));
118 base::FilePath
file_name_delete_2(dir_name_delete_2
);
119 file_name_delete_2
= file_name_delete_2
.AppendASCII("File_2.txt");
120 CreateTextFile(file_name_delete_2
.value(), text_content_1
);
121 ASSERT_TRUE(base::PathExists(file_name_delete_2
));
124 base::ScopedTempDir temp_dir
;
125 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
127 std::vector
<base::FilePath
> key_files(1, file_name_delete_1
);
128 scoped_ptr
<DeleteTreeWorkItem
> work_item(
129 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete
, temp_dir
.path(),
131 EXPECT_TRUE(work_item
->Do());
133 // everything should be gone
134 EXPECT_FALSE(base::PathExists(file_name_delete_1
));
135 EXPECT_FALSE(base::PathExists(file_name_delete_2
));
136 EXPECT_FALSE(base::PathExists(dir_name_delete
));
138 work_item
->Rollback();
139 // everything should come back
140 EXPECT_TRUE(base::PathExists(file_name_delete_1
));
141 EXPECT_TRUE(base::PathExists(file_name_delete_2
));
142 EXPECT_TRUE(base::PathExists(dir_name_delete
));
145 // Delete a tree with key_path in use. Everything should still be there.
146 TEST_F(DeleteTreeWorkItemTest
, DeleteTreeInUse
) {
147 // Create tree to be deleted
148 base::FilePath
dir_name_delete(temp_dir_
.path());
149 dir_name_delete
= dir_name_delete
.AppendASCII("to_be_delete");
150 base::CreateDirectory(dir_name_delete
);
151 ASSERT_TRUE(base::PathExists(dir_name_delete
));
153 base::FilePath
dir_name_delete_1(dir_name_delete
);
154 dir_name_delete_1
= dir_name_delete_1
.AppendASCII("1");
155 base::CreateDirectory(dir_name_delete_1
);
156 ASSERT_TRUE(base::PathExists(dir_name_delete_1
));
158 base::FilePath
dir_name_delete_2(dir_name_delete
);
159 dir_name_delete_2
= dir_name_delete_2
.AppendASCII("2");
160 base::CreateDirectory(dir_name_delete_2
);
161 ASSERT_TRUE(base::PathExists(dir_name_delete_2
));
163 base::FilePath
file_name_delete_1(dir_name_delete_1
);
164 file_name_delete_1
= file_name_delete_1
.AppendASCII("File_1.txt");
165 CreateTextFile(file_name_delete_1
.value(), text_content_1
);
166 ASSERT_TRUE(base::PathExists(file_name_delete_1
));
168 base::FilePath
file_name_delete_2(dir_name_delete_2
);
169 file_name_delete_2
= file_name_delete_2
.AppendASCII("File_2.txt");
170 CreateTextFile(file_name_delete_2
.value(), text_content_1
);
171 ASSERT_TRUE(base::PathExists(file_name_delete_2
));
173 // Create a key path file.
174 base::FilePath
key_path(dir_name_delete
);
175 key_path
= key_path
.AppendASCII("key_file.exe");
177 wchar_t exe_full_path_str
[MAX_PATH
];
178 ::GetModuleFileNameW(NULL
, exe_full_path_str
, MAX_PATH
);
179 base::FilePath
exe_full_path(exe_full_path_str
);
181 base::CopyFile(exe_full_path
, key_path
);
182 ASSERT_TRUE(base::PathExists(key_path
));
184 VLOG(1) << "copy ourself from " << exe_full_path
.value()
185 << " to " << key_path
.value();
187 // Run the key path file to keep it in use.
188 STARTUPINFOW si
= {sizeof(si
)};
189 PROCESS_INFORMATION pi
= {0};
190 base::FilePath::StringType writable_key_path
= key_path
.value();
192 ::CreateProcessW(NULL
, &writable_key_path
[0],
193 NULL
, NULL
, FALSE
, CREATE_NO_WINDOW
| CREATE_SUSPENDED
,
194 NULL
, NULL
, &si
, &pi
));
198 base::ScopedTempDir temp_dir
;
199 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
201 std::vector
<base::FilePath
> key_paths(1, key_path
);
202 scoped_ptr
<DeleteTreeWorkItem
> work_item(
203 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete
, temp_dir
.path(),
206 // delete should fail as file in use.
207 EXPECT_FALSE(work_item
->Do());
210 // verify everything is still there.
211 EXPECT_TRUE(base::PathExists(key_path
));
212 EXPECT_TRUE(base::PathExists(file_name_delete_1
));
213 EXPECT_TRUE(base::PathExists(file_name_delete_2
));
215 TerminateProcess(pi
.hProcess
, 0);
216 // make sure the handle is closed.
217 WaitForSingleObject(pi
.hProcess
, INFINITE
);