delete_tree_work_item_unittest.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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/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"
19
20namespace {
21  class DeleteTreeWorkItemTest : public testing::Test {
22   protected:
23    virtual void SetUp() {
24      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
25    }
26
27    // The temporary directory used to contain the test operations.
28    base::ScopedTempDir temp_dir_;
29  };
30
31  // Simple function to dump some text into a new file.
32  void CreateTextFile(const std::wstring& filename,
33                      const std::wstring& contents) {
34    std::ofstream file;
35    file.open(filename.c_str());
36    ASSERT_TRUE(file.is_open());
37    file << contents;
38    file.close();
39  }
40
41  wchar_t text_content_1[] = L"delete me";
42  wchar_t text_content_2[] = L"delete me as well";
43};
44
45// Delete a tree without key path. Everything should be deleted.
46TEST_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));
52
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));
57
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));
62
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));
67
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));
72
73  // Test Do().
74  base::ScopedTempDir temp_dir;
75  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
76
77  std::vector<base::FilePath> key_files;
78  scoped_ptr<DeleteTreeWorkItem> work_item(
79      WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
80                                         key_files));
81  EXPECT_TRUE(work_item->Do());
82
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));
87
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));
93}
94
95
96// Delete a tree with keypath but not in use. Everything should be gone.
97// Rollback should bring back everything
98TEST_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));
104
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));
109
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));
114
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));
119
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));
124
125  // test Do()
126  base::ScopedTempDir temp_dir;
127  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
128
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(),
132                                         key_files));
133  EXPECT_TRUE(work_item->Do());
134
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));
139
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));
145}
146
147// Delete a tree with key_path in use. Everything should still be there.
148TEST_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));
154
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));
159
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));
164
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));
169
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));
174
175  // Create a key path file.
176  base::FilePath key_path(dir_name_delete);
177  key_path = key_path.AppendASCII("key_file.exe");
178
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);
182
183  base::CopyFile(exe_full_path, key_path);
184  ASSERT_TRUE(base::PathExists(key_path));
185
186  VLOG(1) << "copy ourself from " << exe_full_path.value()
187          << " to " << key_path.value();
188
189  // Run the key path file to keep it in use.
190  STARTUPINFOW si = {sizeof(si)};
191  PROCESS_INFORMATION pi = {0};
192  ASSERT_TRUE(
193      ::CreateProcessW(NULL, const_cast<wchar_t*>(key_path.value().c_str()),
194                       NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
195                       NULL, NULL, &si, &pi));
196
197  // test Do().
198  {
199    base::ScopedTempDir temp_dir;
200    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
201
202    std::vector<base::FilePath> key_paths(1, key_path);
203    scoped_ptr<DeleteTreeWorkItem> work_item(
204        WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
205                                           key_paths));
206
207    // delete should fail as file in use.
208    EXPECT_FALSE(work_item->Do());
209  }
210
211  // verify everything is still there.
212  EXPECT_TRUE(base::PathExists(key_path));
213  EXPECT_TRUE(base::PathExists(file_name_delete_1));
214  EXPECT_TRUE(base::PathExists(file_name_delete_2));
215
216  TerminateProcess(pi.hProcess, 0);
217  // make sure the handle is closed.
218  WaitForSingleObject(pi.hProcess, INFINITE);
219}
220