// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/installer/util/self_cleaning_temp_dir.h" #include "testing/gtest/include/gtest/gtest.h" namespace { // Returns a string of 8 characters consisting of the letter 'R' followed by // seven random hex digits. std::wstring GetRandomFilename() { uint8 data[4]; HCRYPTPROV crypt_ctx = NULL; // Get four bytes of randomness. Use CAPI rather than the CRT since I've // seen the latter trivially repeat. EXPECT_NE(FALSE, CryptAcquireContext(&crypt_ctx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)); EXPECT_NE(FALSE, CryptGenRandom(crypt_ctx, arraysize(data), &data[0])); EXPECT_NE(FALSE, CryptReleaseContext(crypt_ctx, 0)); // Hexify the value. std::string result(base::HexEncode(&data[0], arraysize(data))); EXPECT_EQ(8, result.size()); // Replace the first digit with the letter 'R' (for "random", get it?). result[0] = 'R'; return base::ASCIIToWide(result); } } // namespace namespace installer { class SelfCleaningTempDirTest : public testing::Test { }; // Test the implementation of GetTopDirToCreate when given the root of a // volume. TEST_F(SelfCleaningTempDirTest, TopLevel) { base::FilePath base_dir; SelfCleaningTempDir::GetTopDirToCreate(base::FilePath(L"C:\\"), &base_dir); EXPECT_TRUE(base_dir.empty()); } // Test the implementation of GetTopDirToCreate when given a non-existant dir // under the root of a volume. TEST_F(SelfCleaningTempDirTest, TopLevelPlusOne) { base::FilePath base_dir; base::FilePath parent_dir(L"C:\\"); parent_dir = parent_dir.Append(GetRandomFilename()); SelfCleaningTempDir::GetTopDirToCreate(parent_dir, &base_dir); EXPECT_EQ(parent_dir, base_dir); } // Test that all intermediate dirs are cleaned up if they're empty when // Delete() is called. TEST_F(SelfCleaningTempDirTest, RemoveUnusedOnDelete) { // Make a directory in which we'll work. base::ScopedTempDir work_dir; EXPECT_TRUE(work_dir.CreateUniqueTempDir()); // Make up some path under the temp dir. base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two")); SelfCleaningTempDir temp_dir; EXPECT_TRUE(temp_dir.Initialize(parent_temp_dir, L"Three")); EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir.path()); EXPECT_TRUE(base::DirectoryExists(temp_dir.path())); EXPECT_TRUE(temp_dir.Delete()); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three"))); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir)); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName())); EXPECT_TRUE(base::DirectoryExists(parent_temp_dir.DirName().DirName())); EXPECT_TRUE(work_dir.Delete()); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName())); } // Test that two clients can work in the same area. TEST_F(SelfCleaningTempDirTest, TwoClients) { // Make a directory in which we'll work. base::ScopedTempDir work_dir; EXPECT_TRUE(work_dir.CreateUniqueTempDir()); // Make up some path under the temp dir. base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two")); SelfCleaningTempDir temp_dir1; SelfCleaningTempDir temp_dir2; // First client is created. EXPECT_TRUE(temp_dir1.Initialize(parent_temp_dir, L"Three")); // Second client is created in the same space. EXPECT_TRUE(temp_dir2.Initialize(parent_temp_dir, L"Three")); // Both clients are where they are expected. EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir1.path()); EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir2.path()); EXPECT_TRUE(base::DirectoryExists(temp_dir1.path())); EXPECT_TRUE(base::DirectoryExists(temp_dir2.path())); // Second client goes away. EXPECT_TRUE(temp_dir2.Delete()); // The first is now useless. EXPECT_FALSE(base::DirectoryExists(temp_dir1.path())); // But the intermediate dirs are still present EXPECT_TRUE(base::DirectoryExists(parent_temp_dir)); // Now the first goes away. EXPECT_TRUE(temp_dir1.Delete()); // And cleans up after itself. EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three"))); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir)); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName())); EXPECT_TRUE(base::DirectoryExists(parent_temp_dir.DirName().DirName())); EXPECT_TRUE(work_dir.Delete()); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName())); } // Test that all intermediate dirs are cleaned up if they're empty when the // destructor is called. TEST_F(SelfCleaningTempDirTest, RemoveUnusedOnDestroy) { // Make a directory in which we'll work. base::ScopedTempDir work_dir; EXPECT_TRUE(work_dir.CreateUniqueTempDir()); // Make up some path under the temp dir. base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two")); { SelfCleaningTempDir temp_dir; EXPECT_TRUE(temp_dir.Initialize(parent_temp_dir, L"Three")); EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir.path()); EXPECT_TRUE(base::DirectoryExists(temp_dir.path())); } EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three"))); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir)); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName())); EXPECT_TRUE(base::DirectoryExists(parent_temp_dir.DirName().DirName())); EXPECT_TRUE(work_dir.Delete()); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName())); } // Test that intermediate dirs are left behind if they're not empty when the // destructor is called. TEST_F(SelfCleaningTempDirTest, LeaveUsedOnDestroy) { static const char kHiHon[] = "hi, hon"; // Make a directory in which we'll work. base::ScopedTempDir work_dir; EXPECT_TRUE(work_dir.CreateUniqueTempDir()); // Make up some path under the temp dir. base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two")); { SelfCleaningTempDir temp_dir; EXPECT_TRUE(temp_dir.Initialize(parent_temp_dir, L"Three")); EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir.path()); EXPECT_TRUE(base::DirectoryExists(temp_dir.path())); // Drop a file somewhere. EXPECT_EQ(arraysize(kHiHon) - 1, base::WriteFile(parent_temp_dir.Append(GetRandomFilename()), kHiHon, arraysize(kHiHon) - 1)); } EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three"))); EXPECT_TRUE(base::DirectoryExists(parent_temp_dir)); EXPECT_TRUE(work_dir.Delete()); EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName())); } } // namespace installer