Home | History | Annotate | Download | only in util
      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   file_util::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   file_util::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   file_util::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   file_util::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   file_util::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   file_util::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   file_util::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   file_util::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   file_util::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