delete_tree_work_item_unittest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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.
4
5#include <windows.h>
6
7#include <fstream>
8
9#include "base/base_paths.h"
10#include "base/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/process_util.h"
16#include "base/strings/string_util.h"
17#include "chrome/installer/util/delete_tree_work_item.h"
18#include "chrome/installer/util/work_item.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace {
22  class DeleteTreeWorkItemTest : public testing::Test {
23   protected:
24    virtual void SetUp() {
25      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
26    }
27
28    // The temporary directory used to contain the test operations.
29    base::ScopedTempDir temp_dir_;
30  };
31
32  // Simple function to dump some text into a new file.
33  void CreateTextFile(const std::wstring& filename,
34                      const std::wstring& contents) {
35    std::ofstream file;
36    file.open(filename.c_str());
37    ASSERT_TRUE(file.is_open());
38    file << contents;
39    file.close();
40  }
41
42  wchar_t text_content_1[] = L"delete me";
43  wchar_t text_content_2[] = L"delete me as well";
44};
45
46// Delete a tree without key path. Everything should be deleted.
47TEST_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  file_util::CreateDirectory(dir_name_delete);
52  ASSERT_TRUE(base::PathExists(dir_name_delete));
53
54  base::FilePath dir_name_delete_1(dir_name_delete);
55  dir_name_delete_1 = dir_name_delete_1.AppendASCII("1");
56  file_util::CreateDirectory(dir_name_delete_1);
57  ASSERT_TRUE(base::PathExists(dir_name_delete_1));
58
59  base::FilePath dir_name_delete_2(dir_name_delete);
60  dir_name_delete_2 = dir_name_delete_2.AppendASCII("2");
61  file_util::CreateDirectory(dir_name_delete_2);
62  ASSERT_TRUE(base::PathExists(dir_name_delete_2));
63
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));
68
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));
73
74  // Test Do().
75  base::ScopedTempDir temp_dir;
76  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
77
78  std::vector<base::FilePath> key_files;
79  scoped_ptr<DeleteTreeWorkItem> work_item(
80      WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
81                                         key_files));
82  EXPECT_TRUE(work_item->Do());
83
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));
88
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));
94}
95
96
97// Delete a tree with keypath but not in use. Everything should be gone.
98// Rollback should bring back everything
99TEST_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  file_util::CreateDirectory(dir_name_delete);
104  ASSERT_TRUE(base::PathExists(dir_name_delete));
105
106  base::FilePath dir_name_delete_1(dir_name_delete);
107  dir_name_delete_1 = dir_name_delete_1.AppendASCII("1");
108  file_util::CreateDirectory(dir_name_delete_1);
109  ASSERT_TRUE(base::PathExists(dir_name_delete_1));
110
111  base::FilePath dir_name_delete_2(dir_name_delete);
112  dir_name_delete_2 = dir_name_delete_2.AppendASCII("2");
113  file_util::CreateDirectory(dir_name_delete_2);
114  ASSERT_TRUE(base::PathExists(dir_name_delete_2));
115
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));
120
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));
125
126  // test Do()
127  base::ScopedTempDir temp_dir;
128  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
129
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(),
133                                         key_files));
134  EXPECT_TRUE(work_item->Do());
135
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));
140
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));
146}
147
148// Delete a tree with key_path in use. Everything should still be there.
149TEST_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  file_util::CreateDirectory(dir_name_delete);
154  ASSERT_TRUE(base::PathExists(dir_name_delete));
155
156  base::FilePath dir_name_delete_1(dir_name_delete);
157  dir_name_delete_1 = dir_name_delete_1.AppendASCII("1");
158  file_util::CreateDirectory(dir_name_delete_1);
159  ASSERT_TRUE(base::PathExists(dir_name_delete_1));
160
161  base::FilePath dir_name_delete_2(dir_name_delete);
162  dir_name_delete_2 = dir_name_delete_2.AppendASCII("2");
163  file_util::CreateDirectory(dir_name_delete_2);
164  ASSERT_TRUE(base::PathExists(dir_name_delete_2));
165
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));
170
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));
175
176  // Create a key path file.
177  base::FilePath key_path(dir_name_delete);
178  key_path = key_path.AppendASCII("key_file.exe");
179
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);
183
184  base::CopyFile(exe_full_path, key_path);
185  ASSERT_TRUE(base::PathExists(key_path));
186
187  VLOG(1) << "copy ourself from " << exe_full_path.value()
188          << " to " << key_path.value();
189
190  // Run the key path file to keep it in use.
191  STARTUPINFOW si = {sizeof(si)};
192  PROCESS_INFORMATION pi = {0};
193  ASSERT_TRUE(
194      ::CreateProcessW(NULL, const_cast<wchar_t*>(key_path.value().c_str()),
195                       NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
196                       NULL, NULL, &si, &pi));
197
198  // test Do().
199  {
200    base::ScopedTempDir temp_dir;
201    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
202
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(),
206                                           key_paths));
207
208    // delete should fail as file in use.
209    EXPECT_FALSE(work_item->Do());
210  }
211
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));
216
217  TerminateProcess(pi.hProcess, 0);
218  // make sure the handle is closed.
219  WaitForSingleObject(pi.hProcess, INFINITE);
220}
221