1// Copyright (c) 2012 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 "base/threading/platform_thread.h"
17#include "chrome/installer/util/copy_tree_work_item.h"
18#include "chrome/installer/util/work_item.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace {
22  class CopyTreeWorkItemTest : public testing::Test {
23   protected:
24    virtual void SetUp() {
25      ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
26      ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
27    }
28
29    virtual void TearDown() {
30      logging::CloseLogFile();
31    }
32
33    // the path to temporary directory used to contain the test operations
34    base::ScopedTempDir test_dir_;
35    base::ScopedTempDir temp_dir_;
36  };
37
38  // Simple function to dump some text into a new file.
39  void CreateTextFile(const std::wstring& filename,
40                      const std::wstring& contents) {
41    std::ofstream file;
42    file.open(filename.c_str());
43    ASSERT_TRUE(file.is_open());
44    file << contents;
45    file.close();
46  }
47
48  bool IsFileInUse(const base::FilePath& path) {
49    if (!base::PathExists(path))
50      return false;
51
52    HANDLE handle = ::CreateFile(path.value().c_str(), FILE_ALL_ACCESS,
53                                 NULL, NULL, OPEN_EXISTING, NULL, NULL);
54    if (handle  == INVALID_HANDLE_VALUE)
55      return true;
56
57    CloseHandle(handle);
58    return false;
59  }
60
61  // Simple function to read text from a file.
62  std::wstring ReadTextFile(const std::wstring& filename) {
63    WCHAR contents[64];
64    std::wifstream file;
65    file.open(filename.c_str());
66    EXPECT_TRUE(file.is_open());
67    file.getline(contents, 64);
68    file.close();
69    return std::wstring(contents);
70  }
71
72  wchar_t text_content_1[] = L"Gooooooooooooooooooooogle";
73  wchar_t text_content_2[] = L"Overwrite Me";
74};
75
76// Copy one file from source to destination.
77TEST_F(CopyTreeWorkItemTest, CopyFile) {
78  // Create source file
79  base::FilePath file_name_from(test_dir_.path());
80  file_name_from = file_name_from.AppendASCII("File_From.txt");
81  CreateTextFile(file_name_from.value(), text_content_1);
82  ASSERT_TRUE(base::PathExists(file_name_from));
83
84  // Create destination path
85  base::FilePath dir_name_to(test_dir_.path());
86  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
87  base::CreateDirectory(dir_name_to);
88  ASSERT_TRUE(base::PathExists(dir_name_to));
89
90  base::FilePath file_name_to(dir_name_to);
91  file_name_to = file_name_to.AppendASCII("File_To.txt");
92
93  // test Do()
94  scoped_ptr<CopyTreeWorkItem> work_item(
95      WorkItem::CreateCopyTreeWorkItem(file_name_from,
96                                       file_name_to,
97                                       temp_dir_.path(),
98                                       WorkItem::ALWAYS,
99                                       base::FilePath()));
100
101  EXPECT_TRUE(work_item->Do());
102
103  EXPECT_TRUE(base::PathExists(file_name_from));
104  EXPECT_TRUE(base::PathExists(file_name_to));
105  EXPECT_TRUE(base::ContentsEqual(file_name_from, file_name_to));
106
107  // test rollback()
108  work_item->Rollback();
109
110  EXPECT_FALSE(base::PathExists(file_name_to));
111  EXPECT_TRUE(base::PathExists(file_name_from));
112}
113
114// Copy one file, overwriting the existing one in destination.
115// Test with always_overwrite being true or false. The file is overwritten
116// regardless since the content at destination file is different from source.
117TEST_F(CopyTreeWorkItemTest, CopyFileOverwrite) {
118  // Create source file
119  base::FilePath file_name_from(test_dir_.path());
120  file_name_from = file_name_from.AppendASCII("File_From.txt");
121  CreateTextFile(file_name_from.value(), text_content_1);
122  ASSERT_TRUE(base::PathExists(file_name_from));
123
124  // Create destination file
125  base::FilePath dir_name_to(test_dir_.path());
126  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
127  base::CreateDirectory(dir_name_to);
128  ASSERT_TRUE(base::PathExists(dir_name_to));
129
130  base::FilePath file_name_to(dir_name_to);
131  file_name_to = file_name_to.AppendASCII("File_To.txt");
132  CreateTextFile(file_name_to.value(), text_content_2);
133  ASSERT_TRUE(base::PathExists(file_name_to));
134
135  // test Do() with always_overwrite being true.
136  scoped_ptr<CopyTreeWorkItem> work_item(
137      WorkItem::CreateCopyTreeWorkItem(file_name_from,
138                                       file_name_to,
139                                       temp_dir_.path(),
140                                       WorkItem::ALWAYS,
141                                       base::FilePath()));
142
143  EXPECT_TRUE(work_item->Do());
144
145  EXPECT_TRUE(base::PathExists(file_name_from));
146  EXPECT_TRUE(base::PathExists(file_name_to));
147  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
148  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
149
150  // test rollback()
151  work_item->Rollback();
152
153  EXPECT_TRUE(base::PathExists(file_name_from));
154  EXPECT_TRUE(base::PathExists(file_name_to));
155  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
156  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_2));
157
158  // test Do() with always_overwrite being false.
159  // the file is still overwritten since the content is different.
160  work_item.reset(
161      WorkItem::CreateCopyTreeWorkItem(file_name_from,
162                                       file_name_to,
163                                       temp_dir_.path(),
164                                       WorkItem::IF_DIFFERENT,
165                                       base::FilePath()));
166
167  EXPECT_TRUE(work_item->Do());
168
169  EXPECT_TRUE(base::PathExists(file_name_from));
170  EXPECT_TRUE(base::PathExists(file_name_to));
171  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
172  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
173
174  // test rollback()
175  work_item->Rollback();
176
177  EXPECT_TRUE(base::PathExists(file_name_from));
178  EXPECT_TRUE(base::PathExists(file_name_to));
179  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
180  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_2));
181}
182
183// Copy one file, with the existing one in destination having the same
184// content.
185// If always_overwrite being true, the file is overwritten.
186// If always_overwrite being false, the file is unchanged.
187TEST_F(CopyTreeWorkItemTest, CopyFileSameContent) {
188  // Create source file
189  base::FilePath file_name_from(test_dir_.path());
190  file_name_from = file_name_from.AppendASCII("File_From.txt");
191  CreateTextFile(file_name_from.value(), text_content_1);
192  ASSERT_TRUE(base::PathExists(file_name_from));
193
194  // Create destination file
195  base::FilePath dir_name_to(test_dir_.path());
196  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
197  base::CreateDirectory(dir_name_to);
198  ASSERT_TRUE(base::PathExists(dir_name_to));
199
200  base::FilePath file_name_to(dir_name_to);
201  file_name_to = file_name_to.AppendASCII("File_To.txt");
202  CreateTextFile(file_name_to.value(), text_content_1);
203  ASSERT_TRUE(base::PathExists(file_name_to));
204
205  // test Do() with always_overwrite being true.
206  scoped_ptr<CopyTreeWorkItem> work_item(
207      WorkItem::CreateCopyTreeWorkItem(file_name_from,
208                                       file_name_to,
209                                       temp_dir_.path(),
210                                       WorkItem::ALWAYS,
211                                       base::FilePath()));
212
213  EXPECT_TRUE(work_item->Do());
214
215  // Get the path of backup file
216  base::FilePath backup_file(work_item->backup_path_.path());
217  EXPECT_FALSE(backup_file.empty());
218  backup_file = backup_file.AppendASCII("File_To.txt");
219
220  EXPECT_TRUE(base::PathExists(file_name_from));
221  EXPECT_TRUE(base::PathExists(file_name_to));
222  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
223  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
224  // we verify the file is overwritten by checking the existence of backup
225  // file.
226  EXPECT_TRUE(base::PathExists(backup_file));
227  EXPECT_EQ(0, ReadTextFile(backup_file.value()).compare(text_content_1));
228
229  // test rollback()
230  work_item->Rollback();
231
232  EXPECT_TRUE(base::PathExists(file_name_from));
233  EXPECT_TRUE(base::PathExists(file_name_to));
234  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
235  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
236  // the backup file should be gone after rollback
237  EXPECT_FALSE(base::PathExists(backup_file));
238
239  // test Do() with always_overwrite being false. nothing should change.
240  work_item.reset(
241      WorkItem::CreateCopyTreeWorkItem(file_name_from,
242                                       file_name_to,
243                                       temp_dir_.path(),
244                                       WorkItem::IF_DIFFERENT,
245                                       base::FilePath()));
246
247  EXPECT_TRUE(work_item->Do());
248
249  EXPECT_TRUE(base::PathExists(file_name_from));
250  EXPECT_TRUE(base::PathExists(file_name_to));
251  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
252  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
253  // we verify the file is not overwritten by checking that the backup
254  // file does not exist.
255  EXPECT_FALSE(base::PathExists(backup_file));
256
257  // test rollback(). nothing should happen here.
258  work_item->Rollback();
259
260  EXPECT_TRUE(base::PathExists(file_name_from));
261  EXPECT_TRUE(base::PathExists(file_name_to));
262  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
263  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
264  EXPECT_FALSE(base::PathExists(backup_file));
265}
266
267// Copy one file and without rollback. Verify all temporary files are deleted.
268TEST_F(CopyTreeWorkItemTest, CopyFileAndCleanup) {
269  // Create source file
270  base::FilePath file_name_from(test_dir_.path());
271  file_name_from = file_name_from.AppendASCII("File_From.txt");
272  CreateTextFile(file_name_from.value(), text_content_1);
273  ASSERT_TRUE(base::PathExists(file_name_from));
274
275  // Create destination file
276  base::FilePath dir_name_to(test_dir_.path());
277  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
278  base::CreateDirectory(dir_name_to);
279  ASSERT_TRUE(base::PathExists(dir_name_to));
280
281  base::FilePath file_name_to(dir_name_to);
282  file_name_to = file_name_to.AppendASCII("File_To.txt");
283  CreateTextFile(file_name_to.value(), text_content_2);
284  ASSERT_TRUE(base::PathExists(file_name_to));
285
286  base::FilePath backup_file;
287
288  {
289    // test Do().
290    scoped_ptr<CopyTreeWorkItem> work_item(
291        WorkItem::CreateCopyTreeWorkItem(file_name_from,
292                                         file_name_to,
293                                         temp_dir_.path(),
294                                         WorkItem::IF_DIFFERENT,
295                                         base::FilePath()));
296
297    EXPECT_TRUE(work_item->Do());
298
299    // Get the path of backup file
300    backup_file = work_item->backup_path_.path();
301    EXPECT_FALSE(backup_file.empty());
302    backup_file = backup_file.AppendASCII("File_To.txt");
303
304    EXPECT_TRUE(base::PathExists(file_name_from));
305    EXPECT_TRUE(base::PathExists(file_name_to));
306    EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
307    EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
308    // verify the file is moved to backup place.
309    EXPECT_TRUE(base::PathExists(backup_file));
310    EXPECT_EQ(0, ReadTextFile(backup_file.value()).compare(text_content_2));
311  }
312
313  // verify the backup file is cleaned up as well.
314  EXPECT_FALSE(base::PathExists(backup_file));
315}
316
317// Copy one file, with the existing one in destination being used with
318// overwrite option as IF_DIFFERENT. This destination-file-in-use should
319// be moved to backup location after Do() and moved back after Rollback().
320TEST_F(CopyTreeWorkItemTest, CopyFileInUse) {
321  // Create source file
322  base::FilePath file_name_from(test_dir_.path());
323  file_name_from = file_name_from.AppendASCII("File_From");
324  CreateTextFile(file_name_from.value(), text_content_1);
325  ASSERT_TRUE(base::PathExists(file_name_from));
326
327  // Create an executable in destination path by copying ourself to it.
328  wchar_t exe_full_path_str[MAX_PATH];
329  ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH);
330  base::FilePath exe_full_path(exe_full_path_str);
331
332  base::FilePath dir_name_to(test_dir_.path());
333  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
334  base::CreateDirectory(dir_name_to);
335  ASSERT_TRUE(base::PathExists(dir_name_to));
336
337  base::FilePath file_name_to(dir_name_to);
338  file_name_to = file_name_to.AppendASCII("File_To");
339  base::CopyFile(exe_full_path, file_name_to);
340  ASSERT_TRUE(base::PathExists(file_name_to));
341
342  VLOG(1) << "copy ourself from " << exe_full_path.value()
343          << " to " << file_name_to.value();
344
345  // Run the executable in destination path
346  STARTUPINFOW si = {sizeof(si)};
347  PROCESS_INFORMATION pi = {0};
348  ASSERT_TRUE(
349      ::CreateProcess(NULL, const_cast<wchar_t*>(file_name_to.value().c_str()),
350                       NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
351                       NULL, NULL, &si, &pi));
352
353  // test Do().
354  scoped_ptr<CopyTreeWorkItem> work_item(
355      WorkItem::CreateCopyTreeWorkItem(file_name_from,
356                                       file_name_to,
357                                       temp_dir_.path(),
358                                       WorkItem::IF_DIFFERENT,
359                                       base::FilePath()));
360
361  EXPECT_TRUE(work_item->Do());
362
363  // Get the path of backup file
364  base::FilePath backup_file(work_item->backup_path_.path());
365  EXPECT_FALSE(backup_file.empty());
366  backup_file = backup_file.AppendASCII("File_To");
367
368  EXPECT_TRUE(base::PathExists(file_name_from));
369  EXPECT_TRUE(base::PathExists(file_name_to));
370  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
371  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
372  // verify the file in used is moved to backup place.
373  EXPECT_TRUE(base::PathExists(backup_file));
374  EXPECT_TRUE(base::ContentsEqual(exe_full_path, backup_file));
375
376  // test rollback()
377  work_item->Rollback();
378
379  EXPECT_TRUE(base::PathExists(file_name_from));
380  EXPECT_TRUE(base::PathExists(file_name_to));
381  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
382  EXPECT_TRUE(base::ContentsEqual(exe_full_path, file_name_to));
383  // the backup file should be gone after rollback
384  EXPECT_FALSE(base::PathExists(backup_file));
385
386  TerminateProcess(pi.hProcess, 0);
387  // make sure the handle is closed.
388  EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0);
389  CloseHandle(pi.hProcess);
390  CloseHandle(pi.hThread);
391}
392
393// Test overwrite option NEW_NAME_IF_IN_USE:
394// 1. If destination file is in use, the source should be copied with the
395//    new name after Do() and this new name file should be deleted
396//    after rollback.
397// 2. If destination file is not in use, the source should be copied in the
398//    destination folder after Do() and should be rolled back after Rollback().
399TEST_F(CopyTreeWorkItemTest, NewNameAndCopyTest) {
400  // Create source file
401  base::FilePath file_name_from(test_dir_.path());
402  file_name_from = file_name_from.AppendASCII("File_From");
403  CreateTextFile(file_name_from.value(), text_content_1);
404  ASSERT_TRUE(base::PathExists(file_name_from));
405
406  // Create an executable in destination path by copying ourself to it.
407  wchar_t exe_full_path_str[MAX_PATH];
408  ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH);
409  base::FilePath exe_full_path(exe_full_path_str);
410
411  base::FilePath dir_name_to(test_dir_.path());
412  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
413  base::CreateDirectory(dir_name_to);
414  ASSERT_TRUE(base::PathExists(dir_name_to));
415
416  base::FilePath file_name_to(dir_name_to), alternate_to(dir_name_to);
417  file_name_to = file_name_to.AppendASCII("File_To");
418  alternate_to = alternate_to.AppendASCII("Alternate_To");
419  base::CopyFile(exe_full_path, file_name_to);
420  ASSERT_TRUE(base::PathExists(file_name_to));
421
422  VLOG(1) << "copy ourself from " << exe_full_path.value()
423          << " to " << file_name_to.value();
424
425  // Run the executable in destination path
426  STARTUPINFOW si = {sizeof(si)};
427  PROCESS_INFORMATION pi = {0};
428  ASSERT_TRUE(
429      ::CreateProcess(NULL, const_cast<wchar_t*>(file_name_to.value().c_str()),
430                       NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
431                       NULL, NULL, &si, &pi));
432
433  // test Do().
434  scoped_ptr<CopyTreeWorkItem> work_item(
435      WorkItem::CreateCopyTreeWorkItem(file_name_from,
436                                       file_name_to,
437                                       temp_dir_.path(),
438                                       WorkItem::NEW_NAME_IF_IN_USE,
439                                       alternate_to));
440
441  EXPECT_TRUE(work_item->Do());
442
443  EXPECT_TRUE(base::PathExists(file_name_from));
444  EXPECT_TRUE(base::PathExists(file_name_to));
445  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
446  EXPECT_TRUE(base::ContentsEqual(exe_full_path, file_name_to));
447  // verify that the backup path does not exist
448  EXPECT_TRUE(work_item->backup_path_.path().empty());
449  EXPECT_TRUE(base::ContentsEqual(file_name_from, alternate_to));
450
451  // test rollback()
452  work_item->Rollback();
453
454  EXPECT_TRUE(base::PathExists(file_name_from));
455  EXPECT_TRUE(base::PathExists(file_name_to));
456  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
457  EXPECT_TRUE(base::ContentsEqual(exe_full_path, file_name_to));
458  EXPECT_TRUE(work_item->backup_path_.path().empty());
459  // the alternate file should be gone after rollback
460  EXPECT_FALSE(base::PathExists(alternate_to));
461
462  TerminateProcess(pi.hProcess, 0);
463  // make sure the handle is closed.
464  EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0);
465  CloseHandle(pi.hProcess);
466  CloseHandle(pi.hThread);
467
468  // Now the process has terminated, lets try overwriting the file again
469  work_item.reset(WorkItem::CreateCopyTreeWorkItem(
470      file_name_from, file_name_to,
471      temp_dir_.path(), WorkItem::NEW_NAME_IF_IN_USE,
472      alternate_to));
473  if (IsFileInUse(file_name_to))
474    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
475  // If file is still in use, the rest of the test will fail.
476  ASSERT_FALSE(IsFileInUse(file_name_to));
477  EXPECT_TRUE(work_item->Do());
478
479  // Get the path of backup file
480  base::FilePath backup_file(work_item->backup_path_.path());
481  EXPECT_FALSE(backup_file.empty());
482  backup_file = backup_file.AppendASCII("File_To");
483
484  EXPECT_TRUE(base::PathExists(file_name_from));
485  EXPECT_TRUE(base::PathExists(file_name_to));
486  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
487  EXPECT_TRUE(base::ContentsEqual(file_name_from, file_name_to));
488  // verify that the backup path does exist
489  EXPECT_TRUE(base::PathExists(backup_file));
490  EXPECT_FALSE(base::PathExists(alternate_to));
491
492  // test rollback()
493  work_item->Rollback();
494
495  EXPECT_TRUE(base::PathExists(file_name_from));
496  EXPECT_TRUE(base::PathExists(file_name_to));
497  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
498  EXPECT_TRUE(base::ContentsEqual(exe_full_path, file_name_to));
499  // the backup file should be gone after rollback
500  EXPECT_FALSE(base::PathExists(backup_file));
501  EXPECT_FALSE(base::PathExists(alternate_to));
502}
503
504// Test overwrite option IF_NOT_PRESENT:
505// 1. If destination file/directory exist, the source should not be copied
506// 2. If destination file/directory do not exist, the source should be copied
507//    in the destination folder after Do() and should be rolled back after
508//    Rollback().
509// Flaky, http://crbug.com/59785.
510TEST_F(CopyTreeWorkItemTest, DISABLED_IfNotPresentTest) {
511  // Create source file
512  base::FilePath file_name_from(test_dir_.path());
513  file_name_from = file_name_from.AppendASCII("File_From");
514  CreateTextFile(file_name_from.value(), text_content_1);
515  ASSERT_TRUE(base::PathExists(file_name_from));
516
517  // Create an executable in destination path by copying ourself to it.
518  wchar_t exe_full_path_str[MAX_PATH];
519  ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH);
520  base::FilePath exe_full_path(exe_full_path_str);
521
522  base::FilePath dir_name_to(test_dir_.path());
523  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
524  base::CreateDirectory(dir_name_to);
525  ASSERT_TRUE(base::PathExists(dir_name_to));
526  base::FilePath file_name_to(dir_name_to);
527  file_name_to = file_name_to.AppendASCII("File_To");
528  base::CopyFile(exe_full_path, file_name_to);
529  ASSERT_TRUE(base::PathExists(file_name_to));
530
531  // Get the path of backup file
532  base::FilePath backup_file(temp_dir_.path());
533  backup_file = backup_file.AppendASCII("File_To");
534
535  // test Do().
536  scoped_ptr<CopyTreeWorkItem> work_item(
537      WorkItem::CreateCopyTreeWorkItem(
538          file_name_from,
539          file_name_to, temp_dir_.path(),
540          WorkItem::IF_NOT_PRESENT,
541          base::FilePath()));
542  EXPECT_TRUE(work_item->Do());
543
544  // verify that the source, destination have not changed and backup path
545  // does not exist
546  EXPECT_TRUE(base::PathExists(file_name_from));
547  EXPECT_TRUE(base::PathExists(file_name_to));
548  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
549  EXPECT_TRUE(base::ContentsEqual(exe_full_path, file_name_to));
550  EXPECT_FALSE(base::PathExists(backup_file));
551
552  // test rollback()
553  work_item->Rollback();
554
555  // verify that the source, destination have not changed and backup path
556  // does not exist after rollback also
557  EXPECT_TRUE(base::PathExists(file_name_from));
558  EXPECT_TRUE(base::PathExists(file_name_to));
559  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
560  EXPECT_TRUE(base::ContentsEqual(exe_full_path, file_name_to));
561  EXPECT_FALSE(base::PathExists(backup_file));
562
563  // Now delete the destination and try copying the file again.
564  base::DeleteFile(file_name_to, true);
565  work_item.reset(WorkItem::CreateCopyTreeWorkItem(
566      file_name_from, file_name_to,
567      temp_dir_.path(), WorkItem::IF_NOT_PRESENT,
568      base::FilePath()));
569  EXPECT_TRUE(work_item->Do());
570
571  // verify that the source, destination are the same and backup path
572  // does not exist
573  EXPECT_TRUE(base::PathExists(file_name_from));
574  EXPECT_TRUE(base::PathExists(file_name_to));
575  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
576  EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
577  EXPECT_FALSE(base::PathExists(backup_file));
578
579  // test rollback()
580  work_item->Rollback();
581
582  // verify that the destination does not exist anymore
583  EXPECT_TRUE(base::PathExists(file_name_from));
584  EXPECT_FALSE(base::PathExists(file_name_to));
585  EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
586  EXPECT_FALSE(base::PathExists(backup_file));
587}
588
589// Copy one file without rollback. The existing one in destination is in use.
590// Verify it is moved to backup location and stays there.
591// Flaky, http://crbug.com/59783.
592TEST_F(CopyTreeWorkItemTest, DISABLED_CopyFileInUseAndCleanup) {
593  // Create source file
594  base::FilePath file_name_from(test_dir_.path());
595  file_name_from = file_name_from.AppendASCII("File_From");
596  CreateTextFile(file_name_from.value(), text_content_1);
597  ASSERT_TRUE(base::PathExists(file_name_from));
598
599  // Create an executable in destination path by copying ourself to it.
600  wchar_t exe_full_path_str[MAX_PATH];
601  ::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH);
602  base::FilePath exe_full_path(exe_full_path_str);
603
604  base::FilePath dir_name_to(test_dir_.path());
605  dir_name_to = dir_name_to.AppendASCII("Copy_To_Subdir");
606  base::CreateDirectory(dir_name_to);
607  ASSERT_TRUE(base::PathExists(dir_name_to));
608
609  base::FilePath file_name_to(dir_name_to);
610  file_name_to = file_name_to.AppendASCII("File_To");
611  base::CopyFile(exe_full_path, file_name_to);
612  ASSERT_TRUE(base::PathExists(file_name_to));
613
614  VLOG(1) << "copy ourself from " << exe_full_path.value()
615          << " to " << file_name_to.value();
616
617  // Run the executable in destination path
618  STARTUPINFOW si = {sizeof(si)};
619  PROCESS_INFORMATION pi = {0};
620  ASSERT_TRUE(
621      ::CreateProcess(NULL, const_cast<wchar_t*>(file_name_to.value().c_str()),
622                       NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_SUSPENDED,
623                       NULL, NULL, &si, &pi));
624
625  base::FilePath backup_file;
626
627  // test Do().
628  {
629    scoped_ptr<CopyTreeWorkItem> work_item(
630        WorkItem::CreateCopyTreeWorkItem(file_name_from,
631                                         file_name_to,
632                                         temp_dir_.path(),
633                                         WorkItem::IF_DIFFERENT,
634                                         base::FilePath()));
635
636    EXPECT_TRUE(work_item->Do());
637
638    // Get the path of backup file
639    backup_file = work_item->backup_path_.path();
640    EXPECT_FALSE(backup_file.empty());
641    backup_file = backup_file.AppendASCII("File_To");
642
643    EXPECT_TRUE(base::PathExists(file_name_from));
644    EXPECT_TRUE(base::PathExists(file_name_to));
645    EXPECT_EQ(0, ReadTextFile(file_name_from.value()).compare(text_content_1));
646    EXPECT_EQ(0, ReadTextFile(file_name_to.value()).compare(text_content_1));
647    // verify the file in used is moved to backup place.
648    EXPECT_TRUE(base::PathExists(backup_file));
649    EXPECT_TRUE(base::ContentsEqual(exe_full_path, backup_file));
650  }
651
652  // verify the file in used should be still at the backup place.
653  EXPECT_TRUE(base::PathExists(backup_file));
654  EXPECT_TRUE(base::ContentsEqual(exe_full_path, backup_file));
655
656  TerminateProcess(pi.hProcess, 0);
657  // make sure the handle is closed.
658  EXPECT_TRUE(WaitForSingleObject(pi.hProcess, 10000) == WAIT_OBJECT_0);
659  CloseHandle(pi.hProcess);
660  CloseHandle(pi.hThread);
661}
662
663// Copy a tree from source to destination.
664// Flaky, http://crbug.com/59784.
665TEST_F(CopyTreeWorkItemTest, DISABLED_CopyTree) {
666  // Create source tree
667  base::FilePath dir_name_from(test_dir_.path());
668  dir_name_from = dir_name_from.AppendASCII("from");
669  base::CreateDirectory(dir_name_from);
670  ASSERT_TRUE(base::PathExists(dir_name_from));
671
672  base::FilePath dir_name_from_1(dir_name_from);
673  dir_name_from_1 = dir_name_from_1.AppendASCII("1");
674  base::CreateDirectory(dir_name_from_1);
675  ASSERT_TRUE(base::PathExists(dir_name_from_1));
676
677  base::FilePath dir_name_from_2(dir_name_from);
678  dir_name_from_2 = dir_name_from_2.AppendASCII("2");
679  base::CreateDirectory(dir_name_from_2);
680  ASSERT_TRUE(base::PathExists(dir_name_from_2));
681
682  base::FilePath file_name_from_1(dir_name_from_1);
683  file_name_from_1 = file_name_from_1.AppendASCII("File_1.txt");
684  CreateTextFile(file_name_from_1.value(), text_content_1);
685  ASSERT_TRUE(base::PathExists(file_name_from_1));
686
687  base::FilePath file_name_from_2(dir_name_from_2);
688  file_name_from_2 = file_name_from_2.AppendASCII("File_2.txt");
689  CreateTextFile(file_name_from_2.value(), text_content_1);
690  ASSERT_TRUE(base::PathExists(file_name_from_2));
691
692  base::FilePath dir_name_to(test_dir_.path());
693  dir_name_to = dir_name_to.AppendASCII("to");
694
695  // test Do()
696  {
697    scoped_ptr<CopyTreeWorkItem> work_item(
698        WorkItem::CreateCopyTreeWorkItem(dir_name_from,
699                                         dir_name_to,
700                                         temp_dir_.path(),
701                                         WorkItem::ALWAYS,
702                                         base::FilePath()));
703
704    EXPECT_TRUE(work_item->Do());
705  }
706
707  base::FilePath file_name_to_1(dir_name_to);
708  file_name_to_1 = file_name_to_1.AppendASCII("1");
709  file_name_to_1 = file_name_to_1.AppendASCII("File_1.txt");
710  EXPECT_TRUE(base::PathExists(file_name_to_1));
711  VLOG(1) << "compare " << file_name_from_1.value()
712          << " and " << file_name_to_1.value();
713  EXPECT_TRUE(base::ContentsEqual(file_name_from_1, file_name_to_1));
714
715  base::FilePath file_name_to_2(dir_name_to);
716  file_name_to_2 = file_name_to_2.AppendASCII("2");
717  file_name_to_2 = file_name_to_2.AppendASCII("File_2.txt");
718  EXPECT_TRUE(base::PathExists(file_name_to_2));
719  VLOG(1) << "compare " << file_name_from_2.value()
720          << " and " << file_name_to_2.value();
721  EXPECT_TRUE(base::ContentsEqual(file_name_from_2, file_name_to_2));
722}
723