1 // Copyright 2013 The Chromium Authors 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 "base/test/test_file_util.h" 6 7 #include <vector> 8 9 #include "base/files/file_path.h" 10 #include "base/files/file_util.h" 11 #include "base/test/test_timeouts.h" 12 #include "base/threading/platform_thread.h" 13 #include "base/threading/thread_restrictions.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace base { 17 18 namespace { 19 20 constexpr FilePath::CharType kDirPrefix[] = 21 FILE_PATH_LITERAL("test_scoped_temp_dir"); 22 23 // Deletes all registered file paths upon test completion. There can only be 24 // one instance at a time. 25 class PathDeleterOnTestEnd : public testing::EmptyTestEventListener { 26 public: PathDeleterOnTestEnd()27 PathDeleterOnTestEnd() { 28 DCHECK(!instance_); 29 instance_ = this; 30 } 31 ~PathDeleterOnTestEnd()32 ~PathDeleterOnTestEnd() override { 33 DCHECK_EQ(instance_, this); 34 instance_ = nullptr; 35 } 36 37 PathDeleterOnTestEnd(const PathDeleterOnTestEnd&) = delete; 38 PathDeleterOnTestEnd& operator=(const PathDeleterOnTestEnd&) = delete; 39 GetInstance()40 static PathDeleterOnTestEnd* GetInstance() { return instance_; } 41 DeletePathRecursivelyUponTestEnd(const FilePath & path)42 void DeletePathRecursivelyUponTestEnd(const FilePath& path) { 43 file_paths_to_delete_.push_back(path); 44 } 45 46 // EmptyTestEventListener overrides. OnTestEnd(const testing::TestInfo & test_info)47 void OnTestEnd(const testing::TestInfo& test_info) override { 48 if (file_paths_to_delete_.empty()) { 49 // Nothing to delete since the last test ended. 50 return; 51 } 52 53 ScopedAllowBlockingForTesting allow_blocking; 54 for (const FilePath& file_path : file_paths_to_delete_) { 55 if (!DieFileDie(file_path, /*recurse=*/true)) { 56 ADD_FAILURE() << "Failed to delete temporary directory for testing: " 57 << file_path; 58 } 59 } 60 file_paths_to_delete_.clear(); 61 } 62 63 private: 64 static PathDeleterOnTestEnd* instance_; 65 std::vector<FilePath> file_paths_to_delete_; 66 }; 67 68 // static 69 PathDeleterOnTestEnd* PathDeleterOnTestEnd::instance_ = nullptr; 70 71 } // namespace 72 EvictFileFromSystemCacheWithRetry(const FilePath & path)73bool EvictFileFromSystemCacheWithRetry(const FilePath& path) { 74 const int kCycles = 10; 75 const TimeDelta kDelay = TestTimeouts::action_timeout() / kCycles; 76 for (int i = 0; i < kCycles; i++) { 77 if (EvictFileFromSystemCache(path)) 78 return true; 79 PlatformThread::Sleep(kDelay); 80 } 81 return false; 82 } 83 GetTempDirForTesting()84FilePath GetTempDirForTesting() { 85 FilePath path; 86 CHECK(GetTempDir(&path)); 87 return path; 88 } 89 CreateUniqueTempDirectoryScopedToTest()90FilePath CreateUniqueTempDirectoryScopedToTest() { 91 ScopedAllowBlockingForTesting allow_blocking; 92 FilePath path; 93 if (!CreateNewTempDirectory(kDirPrefix, &path)) { 94 ADD_FAILURE() << "Failed to create unique temporary directory for testing."; 95 return FilePath(); 96 } 97 98 if (!PathDeleterOnTestEnd::GetInstance()) { 99 // Append() transfers ownership of the listener. This means 100 // PathDeleterOnTestEnd::GetInstance() will return non-null until all tests 101 // are run and the test suite destroyed. 102 testing::UnitTest::GetInstance()->listeners().Append( 103 new PathDeleterOnTestEnd()); 104 DCHECK(PathDeleterOnTestEnd::GetInstance()); 105 } 106 107 PathDeleterOnTestEnd::GetInstance()->DeletePathRecursivelyUponTestEnd(path); 108 109 return path; 110 } 111 112 } // namespace base 113