Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Side by Side Diff: chrome/browser/extensions/sandboxed_extension_unpacker_unittest.cc

Issue 6297003: Fail gracefully if profile Temp dir can not be accessed. (Closed) Base URL: http://git.chromium.org/git/chromium.git
Patch Set: Rebase. Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <fstream>
6
5 #include "base/file_util.h" 7 #include "base/file_util.h"
6 #include "base/path_service.h" 8 #include "base/path_service.h"
7 #include "base/ref_counted.h" 9 #include "base/ref_counted.h"
8 #include "base/scoped_temp_dir.h" 10 #include "base/scoped_temp_dir.h"
9 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/extensions/sandboxed_extension_unpacker.h" 13 #include "chrome/browser/extensions/sandboxed_extension_unpacker.h"
11 #include "chrome/common/chrome_paths.h" 14 #include "chrome/common/chrome_paths.h"
12 #include "chrome/common/extensions/extension.h" 15 #include "chrome/common/extensions/extension.h"
13 #include "chrome/common/extensions/extension_constants.h" 16 #include "chrome/common/extensions/extension_constants.h"
14 #include "chrome/common/extensions/extension_unpacker.h" 17 #include "chrome/common/extensions/extension_unpacker.h"
15 #include "testing/gmock/include/gmock/gmock.h" 18 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h" 19 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/skia/include/core/SkBitmap.h" 20 #include "third_party/skia/include/core/SkBitmap.h"
18 21
19 namespace errors = extension_manifest_errors; 22 namespace errors = extension_manifest_errors;
20 namespace keys = extension_manifest_keys; 23 namespace keys = extension_manifest_keys;
21 24
22 using testing::_; 25 using testing::_;
23 using testing::Invoke; 26 using testing::Invoke;
24 27
28 namespace {
29
30 // Create a non-empty file.
31 void CreateTextFile(const FilePath& filename) {
32 std::ofstream file;
33 file.open(WideToUTF8(filename.ToWStringHack()).c_str());
Erik does not do reviews 2011/01/14 22:34:44 This looks problematic - potential filename incomp
Sam Kerner (Chrome) 2011/01/18 19:26:45 Done.
34 ASSERT_TRUE(file.is_open());
35 file << "I am a text file.";
36 file.close();
37 }
38
39 // Clear a scoped_temp_dir if it has any contents.
40 void ClearScopedTempDir(ScopedTempDir& scoped_temp_dir) {
41 if (scoped_temp_dir.IsValid()) {
Erik does not do reviews 2011/01/14 22:34:44 nit: remove {}
Sam Kerner (Chrome) 2011/01/18 19:26:45 Done.
42 EXPECT_TRUE(scoped_temp_dir.Delete());
43 }
44 }
45
25 void OnUnpackSuccess(const FilePath& temp_dir, 46 void OnUnpackSuccess(const FilePath& temp_dir,
26 const FilePath& extension_root, 47 const FilePath& extension_root,
27 const Extension* extension) { 48 const Extension* extension) {
28 // Don't delete temp_dir here, we need to do some post op checking. 49 // Don't delete temp_dir here, we need to do some post op checking.
29 } 50 }
30 51
52 }
53
31 class MockSandboxedExtensionUnpackerClient 54 class MockSandboxedExtensionUnpackerClient
32 : public SandboxedExtensionUnpackerClient { 55 : public SandboxedExtensionUnpackerClient {
33 public: 56 public:
34 virtual ~MockSandboxedExtensionUnpackerClient() {} 57 virtual ~MockSandboxedExtensionUnpackerClient() {}
35 58
36 MOCK_METHOD3(OnUnpackSuccess, 59 MOCK_METHOD3(OnUnpackSuccess,
37 void(const FilePath& temp_dir, 60 void(const FilePath& temp_dir,
38 const FilePath& extension_root, 61 const FilePath& extension_root,
39 const Extension* extension)); 62 const Extension* extension));
40 63
(...skipping 30 matching lines...) Expand all
71 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &original_path)); 94 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &original_path));
72 original_path = original_path.AppendASCII("extensions") 95 original_path = original_path.AppendASCII("extensions")
73 .AppendASCII("unpacker") 96 .AppendASCII("unpacker")
74 .AppendASCII(crx_name); 97 .AppendASCII(crx_name);
75 ASSERT_TRUE(file_util::PathExists(original_path)) << original_path.value(); 98 ASSERT_TRUE(file_util::PathExists(original_path)) << original_path.value();
76 99
77 // Try bots won't let us write into DIR_TEST_DATA, so we have to create 100 // Try bots won't let us write into DIR_TEST_DATA, so we have to create
78 // a temp folder to play in. 101 // a temp folder to play in.
79 ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &install_dir_)); 102 ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &install_dir_));
80 install_dir_ = 103 install_dir_ =
81 install_dir_.AppendASCII("sandboxed_extension_unpacker_test"); 104 install_dir_.AppendASCII("sandboxed_extension_unpacker_test");
82 file_util::Delete(install_dir_, true); 105 file_util::Delete(install_dir_, true);
83 file_util::CreateDirectory(install_dir_); 106 file_util::CreateDirectory(install_dir_);
84 107
85 FilePath crx_path = install_dir_.AppendASCII(crx_name); 108 FilePath crx_path = install_dir_.AppendASCII(crx_name);
86 ASSERT_TRUE(file_util::CopyFile(original_path, crx_path)) << 109 ASSERT_TRUE(file_util::CopyFile(original_path, crx_path)) <<
87 "Original path: " << original_path.value() << 110 "Original path: " << original_path.value() <<
88 ", Crx path: " << crx_path.value(); 111 ", Crx path: " << crx_path.value();
89 112
90 unpacker_.reset(new ExtensionUnpacker(crx_path)); 113 unpacker_.reset(new ExtensionUnpacker(crx_path));
91 114
92
93 // Build a temp area where the extension will be unpacked. 115 // Build a temp area where the extension will be unpacked.
94 ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &temp_dir_)); 116 ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &temp_dir_));
95 temp_dir_ = temp_dir_.AppendASCII("sandboxed_extension_unpacker_test_Temp"); 117 temp_dir_ = temp_dir_.AppendASCII("sandboxed_extension_unpacker_test_Temp");
96 file_util::CreateDirectory(temp_dir_); 118 ASSERT_TRUE(file_util::CreateDirectory(temp_dir_));
119
120 //PathService::Override(chrome::DIR_USER_DATA_TEMP, temp_dir_);
Erik does not do reviews 2011/01/14 22:34:44 remove unused code
Sam Kerner (Chrome) 2011/01/18 19:26:45 Done.
97 121
98 sandboxed_unpacker_ = 122 sandboxed_unpacker_ =
99 new SandboxedExtensionUnpacker(crx_path, temp_dir_, NULL, client_); 123 new SandboxedExtensionUnpacker(crx_path, NULL, client_);
124
100 // Hack since SandboxedExtensionUnpacker gets its background thread id from 125 // Hack since SandboxedExtensionUnpacker gets its background thread id from
101 // the Start call, but we don't call it here. 126 // the Start call, but we don't call it here.
102 sandboxed_unpacker_->thread_identifier_ = BrowserThread::FILE; 127 sandboxed_unpacker_->thread_identifier_ = BrowserThread::FILE;
103 EXPECT_TRUE(PrepareUnpackerEnv());
104 } 128 }
105 129
106 bool PrepareUnpackerEnv() { 130 bool PrepareUnpackerEnv() {
107 sandboxed_unpacker_->extension_root_ = 131 sandboxed_unpacker_->extension_root_ =
108 install_dir_.AppendASCII(extension_filenames::kTempExtensionName); 132 install_dir_.AppendASCII(extension_filenames::kTempExtensionName);
109 133
110 if (!sandboxed_unpacker_->temp_dir_.Set(install_dir_)) 134 if (!sandboxed_unpacker_->temp_dir_.Set(install_dir_))
111 return false; 135 return false;
112 sandboxed_unpacker_->public_key_ = 136 sandboxed_unpacker_->public_key_ =
113 "ocnapchkplbmjmpfehjocmjnipfmogkh"; 137 "ocnapchkplbmjmpfehjocmjnipfmogkh";
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 FilePath temp_dir_; 176 FilePath temp_dir_;
153 MockSandboxedExtensionUnpackerClient* client_; 177 MockSandboxedExtensionUnpackerClient* client_;
154 scoped_ptr<ExtensionUnpacker> unpacker_; 178 scoped_ptr<ExtensionUnpacker> unpacker_;
155 scoped_refptr<SandboxedExtensionUnpacker> sandboxed_unpacker_; 179 scoped_refptr<SandboxedExtensionUnpacker> sandboxed_unpacker_;
156 MessageLoop loop_; 180 MessageLoop loop_;
157 scoped_ptr<BrowserThread> file_thread_; 181 scoped_ptr<BrowserThread> file_thread_;
158 }; 182 };
159 183
160 TEST_F(SandboxedExtensionUnpackerTest, NoCatalogsSuccess) { 184 TEST_F(SandboxedExtensionUnpackerTest, NoCatalogsSuccess) {
161 EXPECT_CALL(*client_, OnUnpackSuccess(_, _, _)); 185 EXPECT_CALL(*client_, OnUnpackSuccess(_, _, _));
186 EXPECT_CALL(*client_, OnUnpackFailure(_)).Times(0);
162 187
163 SetupUnpacker("no_l10n.crx"); 188 SetupUnpacker("no_l10n.crx");
189 PrepareUnpackerEnv();
Erik does not do reviews 2011/01/14 22:34:44 shouldn't this have EXPECT or ASSERT on it? (and o
Sam Kerner (Chrome) 2011/01/18 19:26:45 Yes. Done.
164 ASSERT_TRUE(unpacker_->Run()); 190 ASSERT_TRUE(unpacker_->Run());
165 ASSERT_TRUE(unpacker_->DumpImagesToFile()); 191 ASSERT_TRUE(unpacker_->DumpImagesToFile());
166 ASSERT_TRUE(unpacker_->DumpMessageCatalogsToFile()); 192 ASSERT_TRUE(unpacker_->DumpMessageCatalogsToFile());
167
168 // Check that there is no _locales folder. 193 // Check that there is no _locales folder.
169 FilePath install_path = 194 FilePath install_path =
170 GetInstallPath().Append(Extension::kLocaleFolder); 195 GetInstallPath().Append(Extension::kLocaleFolder);
171 EXPECT_FALSE(file_util::PathExists(install_path)); 196 EXPECT_FALSE(file_util::PathExists(install_path));
172
173 OnUnpackSucceeded(); 197 OnUnpackSucceeded();
174 198
175 // Check that there still is no _locales folder. 199 // Check that there still is no _locales folder.
176 EXPECT_FALSE(file_util::PathExists(install_path)); 200 EXPECT_FALSE(file_util::PathExists(install_path));
177 201
178 ASSERT_TRUE(TempFilesRemoved()); 202 ASSERT_TRUE(TempFilesRemoved());
179 } 203 }
180 204
181 TEST_F(SandboxedExtensionUnpackerTest, WithCatalogsSuccess) { 205 TEST_F(SandboxedExtensionUnpackerTest, WithCatalogsSuccess) {
182 EXPECT_CALL(*client_, OnUnpackSuccess(_, _, _)); 206 EXPECT_CALL(*client_, OnUnpackSuccess(_, _, _));
207 EXPECT_CALL(*client_, OnUnpackFailure(_)).Times(0);
183 208
184 SetupUnpacker("good_l10n.crx"); 209 SetupUnpacker("good_l10n.crx");
210 PrepareUnpackerEnv();
185 ASSERT_TRUE(unpacker_->Run()); 211 ASSERT_TRUE(unpacker_->Run());
186 ASSERT_TRUE(unpacker_->DumpImagesToFile()); 212 ASSERT_TRUE(unpacker_->DumpImagesToFile());
187 ASSERT_TRUE(unpacker_->DumpMessageCatalogsToFile()); 213 ASSERT_TRUE(unpacker_->DumpMessageCatalogsToFile());
188 214
189 // Set timestamp on _locales/en_US/messages.json into the past. 215 // Set timestamp on _locales/en_US/messages.json into the past.
190 FilePath messages_file; 216 FilePath messages_file;
191 messages_file = GetInstallPath().Append(Extension::kLocaleFolder) 217 messages_file = GetInstallPath().Append(Extension::kLocaleFolder)
192 .AppendASCII("en_US") 218 .AppendASCII("en_US")
193 .Append(Extension::kMessagesFilename); 219 .Append(Extension::kMessagesFilename);
194 base::PlatformFileInfo old_info; 220 base::PlatformFileInfo old_info;
195 EXPECT_TRUE(file_util::GetFileInfo(messages_file, &old_info)); 221 EXPECT_TRUE(file_util::GetFileInfo(messages_file, &old_info));
196 base::Time old_time = 222 base::Time old_time =
197 old_info.last_modified - base::TimeDelta::FromSeconds(2); 223 old_info.last_modified - base::TimeDelta::FromSeconds(2);
198 EXPECT_TRUE(file_util::SetLastModifiedTime(messages_file, old_time)); 224 EXPECT_TRUE(file_util::SetLastModifiedTime(messages_file, old_time));
199 // Refresh old_info, just to be sure. 225 // Refresh old_info, just to be sure.
200 EXPECT_TRUE(file_util::GetFileInfo(messages_file, &old_info)); 226 EXPECT_TRUE(file_util::GetFileInfo(messages_file, &old_info));
201 227
202 OnUnpackSucceeded(); 228 OnUnpackSucceeded();
203 229
204 // Check that there is newer _locales/en_US/messages.json file. 230 // Check that there is newer _locales/en_US/messages.json file.
205 base::PlatformFileInfo new_info; 231 base::PlatformFileInfo new_info;
206 EXPECT_TRUE(file_util::GetFileInfo(messages_file, &new_info)); 232 EXPECT_TRUE(file_util::GetFileInfo(messages_file, &new_info));
207 233
208 EXPECT_TRUE(new_info.last_modified > old_info.last_modified); 234 EXPECT_TRUE(new_info.last_modified > old_info.last_modified);
209 235
210 ASSERT_TRUE(TempFilesRemoved()); 236 ASSERT_TRUE(TempFilesRemoved());
211 } 237 }
238
239 TEST_F(SandboxedExtensionUnpackerTest, CreateTempDirectory) {
Erik does not do reviews 2011/01/14 22:34:44 If we ditch the multiple dir support for now, is t
Sam Kerner (Chrome) 2011/01/18 19:26:45 No, but it could be used to test error handling of
240 // To be sure overriding path keys does not change the paths seen
241 // by existing code, use some path keys that do not exist outside
242 // this test.
243 enum {
244 PATH_START = chrome::PATH_END+1,
245 TEST_DIR_WORKS,
246 TEST_DIR_CANT_GET,
247 TEST_DIR_CANT_WRITE,
248 PATH_END
249 };
250
251 // Create a fake temp path.
252 ScopedTempDir fake_user_temp_dir;
253 ASSERT_TRUE(fake_user_temp_dir.CreateUniqueTempDir());
254
255 // |dir_works| will work for unpacking.
256 FilePath dir_works(fake_user_temp_dir.path());
257
258 // Needed because path service code runs AbsolutePath() on all values
259 // it returns. This changes the path on the mac trybots, and we need
260 // to compare this path to the result from PathService::Get() below.
261 ASSERT_TRUE(file_util::AbsolutePath(&dir_works));
262
263 // To make directory creation fail, use a base path which is a file.
264 FilePath dir_cant_write(fake_user_temp_dir.path().AppendASCII("cant_write"));
265 CreateTextFile(dir_cant_write);
266
267 // Set up test paths:
268 PathService::Override(TEST_DIR_WORKS, dir_works);
269 PathService::Override(TEST_DIR_CANT_GET, FilePath());
270 PathService::Override(TEST_DIR_CANT_WRITE, dir_cant_write);
271
272 // Test that our path keys give paths with the desired properties:
273 FilePath scratch;
274 ASSERT_TRUE(PathService::Get(TEST_DIR_WORKS, &scratch));
275 ASSERT_EQ(dir_works.value(), scratch.value());
276
277 ASSERT_FALSE(PathService::Get(TEST_DIR_CANT_GET, &scratch));
278
279 ASSERT_TRUE(PathService::Get(TEST_DIR_CANT_WRITE, &scratch));
280 ASSERT_EQ(dir_cant_write.value(), scratch.value());
281 ASSERT_FALSE(file_util::CreateDirectory(
282 dir_cant_write.AppendASCII("cant_make_dir_in_a_file")));
283
284 SetupUnpacker("good_l10n.crx");
285
286 // Test that a valid, writable path is read and used.
287 const int kWorkingDir[] = {
288 TEST_DIR_WORKS
289 };
290 // Clear |temp_dir_|, so that we can test that it was set.
291 ClearScopedTempDir(sandboxed_unpacker_->temp_dir_);
292 EXPECT_CALL(*client_, OnUnpackFailure(_)).Times(0);
293 ASSERT_TRUE(sandboxed_unpacker_->CreateTempDirectory(
294 kWorkingDir, arraysize(kWorkingDir)));
295 ASSERT_EQ(dir_works.value(),
296 sandboxed_unpacker_->temp_dir_.path().DirName().value());
297
298 // Test that two unusable paths both fail.
299 const int kFailingDir[] = {
300 TEST_DIR_CANT_GET,
301 TEST_DIR_CANT_WRITE
302 };
303 ClearScopedTempDir(sandboxed_unpacker_->temp_dir_);
304 EXPECT_CALL(*client_, OnUnpackFailure(_)).Times(1);
305 ASSERT_FALSE(sandboxed_unpacker_->CreateTempDirectory(
306 kFailingDir, arraysize(kFailingDir)));
307
308 // If at first you don't succeed, try try again.
309 const int kFallback[] = {
310 TEST_DIR_CANT_WRITE,
311 TEST_DIR_CANT_GET,
312 TEST_DIR_WORKS
313 };
314 ClearScopedTempDir(sandboxed_unpacker_->temp_dir_);
315 EXPECT_CALL(*client_, OnUnpackFailure(_)).Times(0);
316 ASSERT_TRUE(
317 sandboxed_unpacker_->CreateTempDirectory(
318 kFallback, arraysize(kFallback)));
319 ASSERT_EQ(
320 dir_works.value(),
321 sandboxed_unpacker_->temp_dir_.path().DirName().value());
322 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698