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 virtual void SetUp() {
24 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
27 // The temporary directory used to contain the test operations.
28 base::ScopedTempDir temp_dir_
;
31 // Simple function to dump some text into a new file.
32 void CreateTextFile(const std::wstring
& filename
,
33 const std::wstring
& contents
) {
35 file
.open(filename
.c_str());
36 ASSERT_TRUE(file
.is_open());
41 const wchar_t text_content_1
[] = L
"delete me";
45 // Delete a tree without key path. Everything should be deleted.
46 TEST_F(DeleteTreeWorkItemTest
, DeleteTreeNoKeyPath
) {
47 // Create tree to be deleted.
48 base::FilePath
dir_name_delete(temp_dir_
.path());
49 dir_name_delete
= dir_name_delete
.AppendASCII("to_be_delete");
50 base::CreateDirectory(dir_name_delete
);
51 ASSERT_TRUE(base::PathExists(dir_name_delete
));
53 base::FilePath
dir_name_delete_1(dir_name_delete
);
54 dir_name_delete_1
= dir_name_delete_1
.AppendASCII("1");
55 base::CreateDirectory(dir_name_delete_1
);
56 ASSERT_TRUE(base::PathExists(dir_name_delete_1
));
58 base::FilePath
dir_name_delete_2(dir_name_delete
);
59 dir_name_delete_2
= dir_name_delete_2
.AppendASCII("2");
60 base::CreateDirectory(dir_name_delete_2
);
61 ASSERT_TRUE(base::PathExists(dir_name_delete_2
));
63 base::FilePath
file_name_delete_1(dir_name_delete_1
);
64 file_name_delete_1
= file_name_delete_1
.AppendASCII("File_1.txt");
65 CreateTextFile(file_name_delete_1
.value(), text_content_1
);
66 ASSERT_TRUE(base::PathExists(file_name_delete_1
));
68 base::FilePath
file_name_delete_2(dir_name_delete_2
);
69 file_name_delete_2
= file_name_delete_2
.AppendASCII("File_2.txt");
70 CreateTextFile(file_name_delete_2
.value(), text_content_1
);
71 ASSERT_TRUE(base::PathExists(file_name_delete_2
));
74 base::ScopedTempDir temp_dir
;
75 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
77 std::vector
<base::FilePath
> key_files
;
78 scoped_ptr
<DeleteTreeWorkItem
> work_item(
79 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete
, temp_dir
.path(),
81 EXPECT_TRUE(work_item
->Do());
83 // everything should be gone
84 EXPECT_FALSE(base::PathExists(file_name_delete_1
));
85 EXPECT_FALSE(base::PathExists(file_name_delete_2
));
86 EXPECT_FALSE(base::PathExists(dir_name_delete
));
88 work_item
->Rollback();
89 // everything should come back
90 EXPECT_TRUE(base::PathExists(file_name_delete_1
));
91 EXPECT_TRUE(base::PathExists(file_name_delete_2
));
92 EXPECT_TRUE(base::PathExists(dir_name_delete
));
96 // Delete a tree with keypath but not in use. Everything should be gone.
97 // Rollback should bring back everything
98 TEST_F(DeleteTreeWorkItemTest
, DeleteTree
) {
99 // Create tree to be deleted
100 base::FilePath
dir_name_delete(temp_dir_
.path());
101 dir_name_delete
= dir_name_delete
.AppendASCII("to_be_delete");
102 base::CreateDirectory(dir_name_delete
);
103 ASSERT_TRUE(base::PathExists(dir_name_delete
));
105 base::FilePath
dir_name_delete_1(dir_name_delete
);
106 dir_name_delete_1
= dir_name_delete_1
.AppendASCII("1");
107 base::CreateDirectory(dir_name_delete_1
);
108 ASSERT_TRUE(base::PathExists(dir_name_delete_1
));
110 base::FilePath
dir_name_delete_2(dir_name_delete
);
111 dir_name_delete_2
= dir_name_delete_2
.AppendASCII("2");
112 base::CreateDirectory(dir_name_delete_2
);
113 ASSERT_TRUE(base::PathExists(dir_name_delete_2
));
115 base::FilePath
file_name_delete_1(dir_name_delete_1
);
116 file_name_delete_1
= file_name_delete_1
.AppendASCII("File_1.txt");
117 CreateTextFile(file_name_delete_1
.value(), text_content_1
);
118 ASSERT_TRUE(base::PathExists(file_name_delete_1
));
120 base::FilePath
file_name_delete_2(dir_name_delete_2
);
121 file_name_delete_2
= file_name_delete_2
.AppendASCII("File_2.txt");
122 CreateTextFile(file_name_delete_2
.value(), text_content_1
);
123 ASSERT_TRUE(base::PathExists(file_name_delete_2
));
126 base::ScopedTempDir temp_dir
;
127 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
129 std::vector
<base::FilePath
> key_files(1, file_name_delete_1
);
130 scoped_ptr
<DeleteTreeWorkItem
> work_item(
131 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete
, temp_dir
.path(),
133 EXPECT_TRUE(work_item
->Do());
135 // everything should be gone
136 EXPECT_FALSE(base::PathExists(file_name_delete_1
));
137 EXPECT_FALSE(base::PathExists(file_name_delete_2
));
138 EXPECT_FALSE(base::PathExists(dir_name_delete
));
140 work_item
->Rollback();
141 // everything should come back
142 EXPECT_TRUE(base::PathExists(file_name_delete_1
));
143 EXPECT_TRUE(base::PathExists(file_name_delete_2
));
144 EXPECT_TRUE(base::PathExists(dir_name_delete
));
147 // Delete a tree with key_path in use. Everything should still be there.
148 TEST_F(DeleteTreeWorkItemTest
, DeleteTreeInUse
) {
149 // Create tree to be deleted
150 base::FilePath
dir_name_delete(temp_dir_
.path());
151 dir_name_delete
= dir_name_delete
.AppendASCII("to_be_delete");
152 base::CreateDirectory(dir_name_delete
);
153 ASSERT_TRUE(base::PathExists(dir_name_delete
));
155 base::FilePath
dir_name_delete_1(dir_name_delete
);
156 dir_name_delete_1
= dir_name_delete_1
.AppendASCII("1");
157 base::CreateDirectory(dir_name_delete_1
);
158 ASSERT_TRUE(base::PathExists(dir_name_delete_1
));
160 base::FilePath
dir_name_delete_2(dir_name_delete
);
161 dir_name_delete_2
= dir_name_delete_2
.AppendASCII("2");
162 base::CreateDirectory(dir_name_delete_2
);
163 ASSERT_TRUE(base::PathExists(dir_name_delete_2
));
165 base::FilePath
file_name_delete_1(dir_name_delete_1
);
166 file_name_delete_1
= file_name_delete_1
.AppendASCII("File_1.txt");
167 CreateTextFile(file_name_delete_1
.value(), text_content_1
);
168 ASSERT_TRUE(base::PathExists(file_name_delete_1
));
170 base::FilePath
file_name_delete_2(dir_name_delete_2
);
171 file_name_delete_2
= file_name_delete_2
.AppendASCII("File_2.txt");
172 CreateTextFile(file_name_delete_2
.value(), text_content_1
);
173 ASSERT_TRUE(base::PathExists(file_name_delete_2
));
175 // Create a key path file.
176 base::FilePath
key_path(dir_name_delete
);
177 key_path
= key_path
.AppendASCII("key_file.exe");
179 wchar_t exe_full_path_str
[MAX_PATH
];
180 ::GetModuleFileNameW(NULL
, exe_full_path_str
, MAX_PATH
);
181 base::FilePath
exe_full_path(exe_full_path_str
);
183 base::CopyFile(exe_full_path
, key_path
);
184 ASSERT_TRUE(base::PathExists(key_path
));
186 VLOG(1) << "copy ourself from " << exe_full_path
.value()
187 << " to " << key_path
.value();
189 // Run the key path file to keep it in use.
190 STARTUPINFOW si
= {sizeof(si
)};
191 PROCESS_INFORMATION pi
= {0};
192 base::FilePath::StringType writable_key_path
= key_path
.value();
194 ::CreateProcessW(NULL
, &writable_key_path
[0],
195 NULL
, NULL
, FALSE
, CREATE_NO_WINDOW
| CREATE_SUSPENDED
,
196 NULL
, NULL
, &si
, &pi
));
200 base::ScopedTempDir temp_dir
;
201 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
203 std::vector
<base::FilePath
> key_paths(1, key_path
);
204 scoped_ptr
<DeleteTreeWorkItem
> work_item(
205 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete
, temp_dir
.path(),
208 // delete should fail as file in use.
209 EXPECT_FALSE(work_item
->Do());
212 // verify everything is still there.
213 EXPECT_TRUE(base::PathExists(key_path
));
214 EXPECT_TRUE(base::PathExists(file_name_delete_1
));
215 EXPECT_TRUE(base::PathExists(file_name_delete_2
));
217 TerminateProcess(pi
.hProcess
, 0);
218 // make sure the handle is closed.
219 WaitForSingleObject(pi
.hProcess
, INFINITE
);