delete_tree_work_item_unittest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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(file_util::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(file_util::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(file_util::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(file_util::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(file_util::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(file_util::PathExists(file_name_delete_1)); 86 EXPECT_FALSE(file_util::PathExists(file_name_delete_2)); 87 EXPECT_FALSE(file_util::PathExists(dir_name_delete)); 88 89 work_item->Rollback(); 90 // everything should come back 91 EXPECT_TRUE(file_util::PathExists(file_name_delete_1)); 92 EXPECT_TRUE(file_util::PathExists(file_name_delete_2)); 93 EXPECT_TRUE(file_util::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(file_util::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(file_util::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(file_util::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(file_util::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(file_util::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(file_util::PathExists(file_name_delete_1)); 138 EXPECT_FALSE(file_util::PathExists(file_name_delete_2)); 139 EXPECT_FALSE(file_util::PathExists(dir_name_delete)); 140 141 work_item->Rollback(); 142 // everything should come back 143 EXPECT_TRUE(file_util::PathExists(file_name_delete_1)); 144 EXPECT_TRUE(file_util::PathExists(file_name_delete_2)); 145 EXPECT_TRUE(file_util::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(file_util::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(file_util::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(file_util::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(file_util::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(file_util::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 file_util::CopyFile(exe_full_path, key_path); 185 ASSERT_TRUE(file_util::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(file_util::PathExists(key_path)); 214 EXPECT_TRUE(file_util::PathExists(file_name_delete_1)); 215 EXPECT_TRUE(file_util::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