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/path_service.h"
15 #include "base/strings/string_util.h"
16 #include "chrome/installer/util/delete_tree_work_item.h"
17 #include "chrome/installer/util/work_item.h"
18 #include "testing/gtest/include/gtest/gtest.h"
22 class DeleteTreeWorkItemTest : public testing::Test {
24 virtual void SetUp() {
25 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
28 // The temporary directory used to contain the test operations.
29 base::ScopedTempDir temp_dir_;
32 // Simple function to dump some text into a new file.
33 void CreateTextFile(const std::wstring& filename,
34 const std::wstring& contents) {
36 file.open(filename.c_str());
37 ASSERT_TRUE(file.is_open());
42 const wchar_t text_content_1[] = L"delete me";
46 // Delete a tree without key path. Everything should be deleted.
47 TEST_F(DeleteTreeWorkItemTest, DeleteTreeNoKeyPath) {
48 // Create tree to be deleted.
49 base::FilePath dir_name_delete(temp_dir_.path());
50 dir_name_delete = dir_name_delete.AppendASCII("to_be_delete");
51 base::CreateDirectory(dir_name_delete);
52 ASSERT_TRUE(base::PathExists(dir_name_delete));
54 base::FilePath dir_name_delete_1(dir_name_delete);
55 dir_name_delete_1 = dir_name_delete_1.AppendASCII("1");
56 base::CreateDirectory(dir_name_delete_1);
57 ASSERT_TRUE(base::PathExists(dir_name_delete_1));
59 base::FilePath dir_name_delete_2(dir_name_delete);
60 dir_name_delete_2 = dir_name_delete_2.AppendASCII("2");
61 base::CreateDirectory(dir_name_delete_2);
62 ASSERT_TRUE(base::PathExists(dir_name_delete_2));
64 base::FilePath file_name_delete_1(dir_name_delete_1);
65 file_name_delete_1 = file_name_delete_1.AppendASCII("File_1.txt");
66 CreateTextFile(file_name_delete_1.value(), text_content_1);
67 ASSERT_TRUE(base::PathExists(file_name_delete_1));
69 base::FilePath file_name_delete_2(dir_name_delete_2);
70 file_name_delete_2 = file_name_delete_2.AppendASCII("File_2.txt");
71 CreateTextFile(file_name_delete_2.value(), text_content_1);
72 ASSERT_TRUE(base::PathExists(file_name_delete_2));
75 base::ScopedTempDir temp_dir;
76 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
78 std::vector<base::FilePath> key_files;
79 scoped_ptr<DeleteTreeWorkItem> work_item(
80 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
82 EXPECT_TRUE(work_item->Do());
84 // everything should be gone
85 EXPECT_FALSE(base::PathExists(file_name_delete_1));
86 EXPECT_FALSE(base::PathExists(file_name_delete_2));
87 EXPECT_FALSE(base::PathExists(dir_name_delete));
89 work_item->Rollback();
90 // everything should come back
91 EXPECT_TRUE(base::PathExists(file_name_delete_1));
92 EXPECT_TRUE(base::PathExists(file_name_delete_2));
93 EXPECT_TRUE(base::PathExists(dir_name_delete));
97 // Delete a tree with keypath but not in use. Everything should be gone.
98 // Rollback should bring back everything
99 TEST_F(DeleteTreeWorkItemTest, DeleteTree) {
100 // Create tree to be deleted
101 base::FilePath dir_name_delete(temp_dir_.path());
102 dir_name_delete = dir_name_delete.AppendASCII("to_be_delete");
103 base::CreateDirectory(dir_name_delete);
104 ASSERT_TRUE(base::PathExists(dir_name_delete));
106 base::FilePath dir_name_delete_1(dir_name_delete);
107 dir_name_delete_1 = dir_name_delete_1.AppendASCII("1");
108 base::CreateDirectory(dir_name_delete_1);
109 ASSERT_TRUE(base::PathExists(dir_name_delete_1));
111 base::FilePath dir_name_delete_2(dir_name_delete);
112 dir_name_delete_2 = dir_name_delete_2.AppendASCII("2");
113 base::CreateDirectory(dir_name_delete_2);
114 ASSERT_TRUE(base::PathExists(dir_name_delete_2));
116 base::FilePath file_name_delete_1(dir_name_delete_1);
117 file_name_delete_1 = file_name_delete_1.AppendASCII("File_1.txt");
118 CreateTextFile(file_name_delete_1.value(), text_content_1);
119 ASSERT_TRUE(base::PathExists(file_name_delete_1));
121 base::FilePath file_name_delete_2(dir_name_delete_2);
122 file_name_delete_2 = file_name_delete_2.AppendASCII("File_2.txt");
123 CreateTextFile(file_name_delete_2.value(), text_content_1);
124 ASSERT_TRUE(base::PathExists(file_name_delete_2));
127 base::ScopedTempDir temp_dir;
128 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
130 std::vector<base::FilePath> key_files(1, file_name_delete_1);
131 scoped_ptr<DeleteTreeWorkItem> work_item(
132 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
134 EXPECT_TRUE(work_item->Do());
136 // everything should be gone
137 EXPECT_FALSE(base::PathExists(file_name_delete_1));
138 EXPECT_FALSE(base::PathExists(file_name_delete_2));
139 EXPECT_FALSE(base::PathExists(dir_name_delete));
141 work_item->Rollback();
142 // everything should come back
143 EXPECT_TRUE(base::PathExists(file_name_delete_1));
144 EXPECT_TRUE(base::PathExists(file_name_delete_2));
145 EXPECT_TRUE(base::PathExists(dir_name_delete));
148 // Delete a tree with key_path in use. Everything should still be there.
149 TEST_F(DeleteTreeWorkItemTest, DeleteTreeInUse) {
150 // Create tree to be deleted
151 base::FilePath dir_name_delete(temp_dir_.path());
152 dir_name_delete = dir_name_delete.AppendASCII("to_be_delete");
153 base::CreateDirectory(dir_name_delete);
154 ASSERT_TRUE(base::PathExists(dir_name_delete));
156 base::FilePath dir_name_delete_1(dir_name_delete);
157 dir_name_delete_1 = dir_name_delete_1.AppendASCII("1");
158 base::CreateDirectory(dir_name_delete_1);
159 ASSERT_TRUE(base::PathExists(dir_name_delete_1));
161 base::FilePath dir_name_delete_2(dir_name_delete);
162 dir_name_delete_2 = dir_name_delete_2.AppendASCII("2");
163 base::CreateDirectory(dir_name_delete_2);
164 ASSERT_TRUE(base::PathExists(dir_name_delete_2));
166 base::FilePath file_name_delete_1(dir_name_delete_1);
167 file_name_delete_1 = file_name_delete_1.AppendASCII("File_1.txt");
168 CreateTextFile(file_name_delete_1.value(), text_content_1);
169 ASSERT_TRUE(base::PathExists(file_name_delete_1));
171 base::FilePath file_name_delete_2(dir_name_delete_2);
172 file_name_delete_2 = file_name_delete_2.AppendASCII("File_2.txt");
173 CreateTextFile(file_name_delete_2.value(), text_content_1);
174 ASSERT_TRUE(base::PathExists(file_name_delete_2));
176 // Create a key path file.
177 base::FilePath key_path(dir_name_delete);
178 key_path = key_path.AppendASCII("key_file.exe");
180 wchar_t exe_full_path_str[MAX_PATH];
181 ::GetModuleFileNameW(NULL, exe_full_path_str, MAX_PATH);
182 base::FilePath exe_full_path(exe_full_path_str);
184 base::CopyFile(exe_full_path, key_path);
185 ASSERT_TRUE(base::PathExists(key_path));
187 VLOG(1) << "copy ourself from " << exe_full_path.value()
188 << " to " << key_path.value();
190 // Run the key path file to keep it in use.
191 STARTUPINFOW si = {sizeof(si)};
192 PROCESS_INFORMATION pi = {0};
193 base::FilePath::StringType writable_key_path = key_path.value();
195 ::CreateProcessW(NULL, &writable_key_path[0],
196 NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
197 NULL, NULL, &si, &pi));
201 base::ScopedTempDir temp_dir;
202 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
204 std::vector<base::FilePath> key_paths(1, key_path);
205 scoped_ptr<DeleteTreeWorkItem> work_item(
206 WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
209 // delete should fail as file in use.
210 EXPECT_FALSE(work_item->Do());
213 // verify everything is still there.
214 EXPECT_TRUE(base::PathExists(key_path));
215 EXPECT_TRUE(base::PathExists(file_name_delete_1));
216 EXPECT_TRUE(base::PathExists(file_name_delete_2));
218 TerminateProcess(pi.hProcess, 0);
219 // make sure the handle is closed.
220 WaitForSingleObject(pi.hProcess, INFINITE);