self_cleaning_temp_dir_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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#include <wincrypt.h>
7
8#include "base/file_util.h"
9#include "base/files/scoped_temp_dir.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/installer/util/self_cleaning_temp_dir.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace {
16
17// Returns a string of 8 characters consisting of the letter 'R' followed by
18// seven random hex digits.
19std::wstring GetRandomFilename() {
20  uint8 data[4];
21  HCRYPTPROV crypt_ctx = NULL;
22
23  // Get four bytes of randomness.  Use CAPI rather than the CRT since I've
24  // seen the latter trivially repeat.
25  EXPECT_NE(FALSE, CryptAcquireContext(&crypt_ctx, NULL, NULL, PROV_RSA_FULL,
26                                        CRYPT_VERIFYCONTEXT));
27  EXPECT_NE(FALSE, CryptGenRandom(crypt_ctx, arraysize(data), &data[0]));
28  EXPECT_NE(FALSE, CryptReleaseContext(crypt_ctx, 0));
29
30  // Hexify the value.
31  std::string result(base::HexEncode(&data[0], arraysize(data)));
32  EXPECT_EQ(8, result.size());
33
34  // Replace the first digit with the letter 'R' (for "random", get it?).
35  result[0] = 'R';
36
37  return base::ASCIIToWide(result);
38}
39
40}  // namespace
41
42namespace installer {
43
44class SelfCleaningTempDirTest : public testing::Test {
45};
46
47// Test the implementation of GetTopDirToCreate when given the root of a
48// volume.
49TEST_F(SelfCleaningTempDirTest, TopLevel) {
50  base::FilePath base_dir;
51  SelfCleaningTempDir::GetTopDirToCreate(base::FilePath(L"C:\\"), &base_dir);
52  EXPECT_TRUE(base_dir.empty());
53}
54
55// Test the implementation of GetTopDirToCreate when given a non-existant dir
56// under the root of a volume.
57TEST_F(SelfCleaningTempDirTest, TopLevelPlusOne) {
58  base::FilePath base_dir;
59  base::FilePath parent_dir(L"C:\\");
60  parent_dir = parent_dir.Append(GetRandomFilename());
61  SelfCleaningTempDir::GetTopDirToCreate(parent_dir, &base_dir);
62  EXPECT_EQ(parent_dir, base_dir);
63}
64
65// Test that all intermediate dirs are cleaned up if they're empty when
66// Delete() is called.
67TEST_F(SelfCleaningTempDirTest, RemoveUnusedOnDelete) {
68  // Make a directory in which we'll work.
69  base::ScopedTempDir work_dir;
70  EXPECT_TRUE(work_dir.CreateUniqueTempDir());
71
72  // Make up some path under the temp dir.
73  base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two"));
74  SelfCleaningTempDir temp_dir;
75  EXPECT_TRUE(temp_dir.Initialize(parent_temp_dir, L"Three"));
76  EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir.path());
77  EXPECT_TRUE(base::DirectoryExists(temp_dir.path()));
78  EXPECT_TRUE(temp_dir.Delete());
79  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three")));
80  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir));
81  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName()));
82  EXPECT_TRUE(base::DirectoryExists(parent_temp_dir.DirName().DirName()));
83  EXPECT_TRUE(work_dir.Delete());
84  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName()));
85}
86
87// Test that two clients can work in the same area.
88TEST_F(SelfCleaningTempDirTest, TwoClients) {
89  // Make a directory in which we'll work.
90  base::ScopedTempDir work_dir;
91  EXPECT_TRUE(work_dir.CreateUniqueTempDir());
92
93  // Make up some path under the temp dir.
94  base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two"));
95  SelfCleaningTempDir temp_dir1;
96  SelfCleaningTempDir temp_dir2;
97  // First client is created.
98  EXPECT_TRUE(temp_dir1.Initialize(parent_temp_dir, L"Three"));
99  // Second client is created in the same space.
100  EXPECT_TRUE(temp_dir2.Initialize(parent_temp_dir, L"Three"));
101  // Both clients are where they are expected.
102  EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir1.path());
103  EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir2.path());
104  EXPECT_TRUE(base::DirectoryExists(temp_dir1.path()));
105  EXPECT_TRUE(base::DirectoryExists(temp_dir2.path()));
106  // Second client goes away.
107  EXPECT_TRUE(temp_dir2.Delete());
108  // The first is now useless.
109  EXPECT_FALSE(base::DirectoryExists(temp_dir1.path()));
110  // But the intermediate dirs are still present
111  EXPECT_TRUE(base::DirectoryExists(parent_temp_dir));
112  // Now the first goes away.
113  EXPECT_TRUE(temp_dir1.Delete());
114  // And cleans up after itself.
115  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three")));
116  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir));
117  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName()));
118  EXPECT_TRUE(base::DirectoryExists(parent_temp_dir.DirName().DirName()));
119  EXPECT_TRUE(work_dir.Delete());
120  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName()));
121}
122
123// Test that all intermediate dirs are cleaned up if they're empty when the
124// destructor is called.
125TEST_F(SelfCleaningTempDirTest, RemoveUnusedOnDestroy) {
126  // Make a directory in which we'll work.
127  base::ScopedTempDir work_dir;
128  EXPECT_TRUE(work_dir.CreateUniqueTempDir());
129
130  // Make up some path under the temp dir.
131  base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two"));
132  {
133    SelfCleaningTempDir temp_dir;
134    EXPECT_TRUE(temp_dir.Initialize(parent_temp_dir, L"Three"));
135    EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir.path());
136    EXPECT_TRUE(base::DirectoryExists(temp_dir.path()));
137  }
138  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three")));
139  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir));
140  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName()));
141  EXPECT_TRUE(base::DirectoryExists(parent_temp_dir.DirName().DirName()));
142  EXPECT_TRUE(work_dir.Delete());
143  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName()));
144}
145
146// Test that intermediate dirs are left behind if they're not empty when the
147// destructor is called.
148TEST_F(SelfCleaningTempDirTest, LeaveUsedOnDestroy) {
149  static const char kHiHon[] = "hi, hon";
150
151  // Make a directory in which we'll work.
152  base::ScopedTempDir work_dir;
153  EXPECT_TRUE(work_dir.CreateUniqueTempDir());
154
155  // Make up some path under the temp dir.
156  base::FilePath parent_temp_dir(work_dir.path().Append(L"One").Append(L"Two"));
157  {
158    SelfCleaningTempDir temp_dir;
159    EXPECT_TRUE(temp_dir.Initialize(parent_temp_dir, L"Three"));
160    EXPECT_EQ(parent_temp_dir.Append(L"Three"), temp_dir.path());
161    EXPECT_TRUE(base::DirectoryExists(temp_dir.path()));
162    // Drop a file somewhere.
163    EXPECT_EQ(arraysize(kHiHon) - 1,
164              base::WriteFile(parent_temp_dir.Append(GetRandomFilename()),
165                              kHiHon, arraysize(kHiHon) - 1));
166  }
167  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.Append(L"Three")));
168  EXPECT_TRUE(base::DirectoryExists(parent_temp_dir));
169  EXPECT_TRUE(work_dir.Delete());
170  EXPECT_FALSE(base::DirectoryExists(parent_temp_dir.DirName().DirName()));
171}
172
173}  // namespace installer
174