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 20 namespace { 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. 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)); 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 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)); 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. 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)); 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