Fix experimental app list search box disappearing on profile switch.
[chromium-blink-merge.git] / components / nacl / browser / pnacl_host_unittest.cc
blob3f2d3efadfb2e56c7fef72d534bbf7aed9c0bb84
1 // Copyright 2013 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.
5 #include "components/nacl/browser/pnacl_host.h"
7 #include <stdio.h>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/run_loop.h"
13 #include "base/threading/sequenced_worker_pool.h"
14 #include "components/nacl/browser/pnacl_translation_cache.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "content/public/test/test_utils.h"
18 #include "net/base/test_completion_callback.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 #if defined(OS_WIN)
22 #define snprintf _snprintf
23 #endif
25 namespace pnacl {
26 namespace {
28 // Size of a buffer used for writing and reading from a file.
29 const size_t kBufferSize = 16u;
31 } // namespace
33 class PnaclHostTest : public testing::Test {
34 protected:
35 PnaclHostTest()
36 : host_(NULL),
37 temp_callback_count_(0),
38 write_callback_count_(0),
39 thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
40 void SetUp() override {
41 host_ = new PnaclHost();
42 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
43 host_->InitForTest(temp_dir_.path(), true);
44 base::RunLoop().RunUntilIdle();
45 EXPECT_EQ(PnaclHost::CacheReady, host_->cache_state_);
47 void TearDown() override {
48 EXPECT_EQ(0U, host_->pending_translations());
49 // Give the host a chance to de-init the backend, and then delete it.
50 host_->RendererClosing(0);
51 content::RunAllBlockingPoolTasksUntilIdle();
52 EXPECT_EQ(PnaclHost::CacheUninitialized, host_->cache_state_);
53 delete host_;
55 int GetCacheSize() { return host_->disk_cache_->Size(); }
56 int CacheIsInitialized() {
57 return host_->cache_state_ == PnaclHost::CacheReady;
59 void ReInitBackend() {
60 host_->InitForTest(temp_dir_.path(), true);
61 base::RunLoop().RunUntilIdle();
62 EXPECT_EQ(PnaclHost::CacheReady, host_->cache_state_);
65 public: // Required for derived classes to bind this method
66 // Callbacks used by tests which call GetNexeFd.
67 // CallbackExpectMiss checks that the fd is valid and a miss is reported,
68 // and also writes some data into the file, which is read back by
69 // CallbackExpectHit
70 void CallbackExpectMiss(const base::File& file, bool is_hit) {
71 EXPECT_FALSE(is_hit);
72 ASSERT_TRUE(file.IsValid());
73 base::File::Info info;
74 base::File* mutable_file = const_cast<base::File*>(&file);
75 EXPECT_TRUE(mutable_file->GetInfo(&info));
76 EXPECT_FALSE(info.is_directory);
77 EXPECT_EQ(0LL, info.size);
78 char str[kBufferSize];
79 memset(str, 0x0, kBufferSize);
80 snprintf(str, kBufferSize, "testdata%d", ++write_callback_count_);
81 EXPECT_EQ(kBufferSize,
82 static_cast<size_t>(mutable_file->Write(0, str, kBufferSize)));
83 temp_callback_count_++;
85 void CallbackExpectHit(const base::File& file, bool is_hit) {
86 EXPECT_TRUE(is_hit);
87 ASSERT_TRUE(file.IsValid());
88 base::File::Info info;
89 base::File* mutable_file = const_cast<base::File*>(&file);
90 EXPECT_TRUE(mutable_file->GetInfo(&info));
91 EXPECT_FALSE(info.is_directory);
92 EXPECT_EQ(kBufferSize, static_cast<size_t>(info.size));
93 char data[kBufferSize];
94 memset(data, 0x0, kBufferSize);
95 char str[kBufferSize];
96 memset(str, 0x0, kBufferSize);
97 snprintf(str, kBufferSize, "testdata%d", write_callback_count_);
98 EXPECT_EQ(kBufferSize,
99 static_cast<size_t>(mutable_file->Read(0, data, kBufferSize)));
100 EXPECT_STREQ(str, data);
101 temp_callback_count_++;
104 protected:
105 PnaclHost* host_;
106 int temp_callback_count_;
107 int write_callback_count_;
108 content::TestBrowserThreadBundle thread_bundle_;
109 base::ScopedTempDir temp_dir_;
112 static nacl::PnaclCacheInfo GetTestCacheInfo() {
113 nacl::PnaclCacheInfo info;
114 info.pexe_url = GURL("http://www.google.com");
115 info.abi_version = 0;
116 info.opt_level = 0;
117 info.has_no_store_header = false;
118 return info;
121 #define GET_NEXE_FD(renderer, instance, incognito, info, expect_hit) \
122 do { \
123 SCOPED_TRACE(""); \
124 host_->GetNexeFd( \
125 renderer, \
126 0, /* ignore render_view_id for now */ \
127 instance, \
128 incognito, \
129 info, \
130 base::Bind(expect_hit ? &PnaclHostTest::CallbackExpectHit \
131 : &PnaclHostTest::CallbackExpectMiss, \
132 base::Unretained(this))); \
133 } while (0)
135 TEST_F(PnaclHostTest, BasicMiss) {
136 nacl::PnaclCacheInfo info = GetTestCacheInfo();
137 // Test cold miss.
138 GET_NEXE_FD(0, 0, false, info, false);
139 EXPECT_EQ(1U, host_->pending_translations());
140 content::RunAllBlockingPoolTasksUntilIdle();
141 EXPECT_EQ(1U, host_->pending_translations());
142 EXPECT_EQ(1, temp_callback_count_);
143 host_->TranslationFinished(0, 0, true);
144 content::RunAllBlockingPoolTasksUntilIdle();
145 EXPECT_EQ(0U, host_->pending_translations());
146 // Test that a different cache info field also misses.
147 info.etag = std::string("something else");
148 GET_NEXE_FD(0, 0, false, info, false);
149 content::RunAllBlockingPoolTasksUntilIdle();
150 EXPECT_EQ(2, temp_callback_count_);
151 EXPECT_EQ(1U, host_->pending_translations());
152 host_->RendererClosing(0);
153 content::RunAllBlockingPoolTasksUntilIdle();
154 // Check that the cache has de-initialized after the last renderer goes away.
155 EXPECT_FALSE(CacheIsInitialized());
158 TEST_F(PnaclHostTest, BadArguments) {
159 nacl::PnaclCacheInfo info = GetTestCacheInfo();
160 GET_NEXE_FD(0, 0, false, info, false);
161 EXPECT_EQ(1U, host_->pending_translations());
162 host_->TranslationFinished(0, 1, true); // nonexistent translation
163 EXPECT_EQ(1U, host_->pending_translations());
164 host_->RendererClosing(1); // nonexistent renderer
165 EXPECT_EQ(1U, host_->pending_translations());
166 content::RunAllBlockingPoolTasksUntilIdle();
167 EXPECT_EQ(1, temp_callback_count_);
168 host_->RendererClosing(0); // close without finishing
171 TEST_F(PnaclHostTest, BasicHit) {
172 nacl::PnaclCacheInfo info = GetTestCacheInfo();
173 GET_NEXE_FD(0, 0, false, info, false);
174 content::RunAllBlockingPoolTasksUntilIdle();
175 EXPECT_EQ(1, temp_callback_count_);
176 host_->TranslationFinished(0, 0, true);
177 content::RunAllBlockingPoolTasksUntilIdle();
178 GET_NEXE_FD(0, 1, false, info, true);
179 content::RunAllBlockingPoolTasksUntilIdle();
180 EXPECT_EQ(2, temp_callback_count_);
181 EXPECT_EQ(0U, host_->pending_translations());
184 TEST_F(PnaclHostTest, TranslationErrors) {
185 nacl::PnaclCacheInfo info = GetTestCacheInfo();
186 GET_NEXE_FD(0, 0, false, info, false);
187 // Early abort, before temp file request returns
188 host_->TranslationFinished(0, 0, false);
189 content::RunAllBlockingPoolTasksUntilIdle();
190 EXPECT_EQ(0U, host_->pending_translations());
191 EXPECT_EQ(0, temp_callback_count_);
192 // The backend will have been freed when the query comes back and there
193 // are no pending translations.
194 EXPECT_FALSE(CacheIsInitialized());
195 ReInitBackend();
196 // Check that another request for the same info misses successfully.
197 GET_NEXE_FD(0, 0, false, info, false);
198 content::RunAllBlockingPoolTasksUntilIdle();
199 host_->TranslationFinished(0, 0, true);
200 content::RunAllBlockingPoolTasksUntilIdle();
201 EXPECT_EQ(1, temp_callback_count_);
202 EXPECT_EQ(0U, host_->pending_translations());
204 // Now try sending the error after the temp file request returns
205 info.abi_version = 222;
206 GET_NEXE_FD(0, 0, false, info, false);
207 content::RunAllBlockingPoolTasksUntilIdle();
208 EXPECT_EQ(2, temp_callback_count_);
209 host_->TranslationFinished(0, 0, false);
210 content::RunAllBlockingPoolTasksUntilIdle();
211 EXPECT_EQ(0U, host_->pending_translations());
212 // Check another successful miss
213 GET_NEXE_FD(0, 0, false, info, false);
214 content::RunAllBlockingPoolTasksUntilIdle();
215 EXPECT_EQ(3, temp_callback_count_);
216 host_->TranslationFinished(0, 0, false);
217 EXPECT_EQ(0U, host_->pending_translations());
220 TEST_F(PnaclHostTest, OverlappedMissesAfterTempReturn) {
221 nacl::PnaclCacheInfo info = GetTestCacheInfo();
222 GET_NEXE_FD(0, 0, false, info, false);
223 content::RunAllBlockingPoolTasksUntilIdle();
224 EXPECT_EQ(1, temp_callback_count_);
225 EXPECT_EQ(1U, host_->pending_translations());
226 // Test that a second request for the same nexe while the first one is still
227 // outstanding eventually hits.
228 GET_NEXE_FD(0, 1, false, info, true);
229 content::RunAllBlockingPoolTasksUntilIdle();
230 EXPECT_EQ(2U, host_->pending_translations());
231 // The temp file should not be returned to the second request until after the
232 // first is finished translating.
233 EXPECT_EQ(1, temp_callback_count_);
234 host_->TranslationFinished(0, 0, true);
235 content::RunAllBlockingPoolTasksUntilIdle();
236 EXPECT_EQ(2, temp_callback_count_);
237 EXPECT_EQ(0U, host_->pending_translations());
240 TEST_F(PnaclHostTest, OverlappedMissesBeforeTempReturn) {
241 nacl::PnaclCacheInfo info = GetTestCacheInfo();
242 GET_NEXE_FD(0, 0, false, info, false);
243 // Send the 2nd fd request before the first one returns a temp file.
244 GET_NEXE_FD(0, 1, false, info, true);
245 content::RunAllBlockingPoolTasksUntilIdle();
246 EXPECT_EQ(1, temp_callback_count_);
247 EXPECT_EQ(2U, host_->pending_translations());
248 content::RunAllBlockingPoolTasksUntilIdle();
249 EXPECT_EQ(2U, host_->pending_translations());
250 EXPECT_EQ(1, temp_callback_count_);
251 host_->TranslationFinished(0, 0, true);
252 content::RunAllBlockingPoolTasksUntilIdle();
253 EXPECT_EQ(2, temp_callback_count_);
254 EXPECT_EQ(0U, host_->pending_translations());
257 TEST_F(PnaclHostTest, OverlappedHitsBeforeTempReturn) {
258 nacl::PnaclCacheInfo info = GetTestCacheInfo();
259 // Store one in the cache and complete it.
260 GET_NEXE_FD(0, 0, false, info, false);
261 content::RunAllBlockingPoolTasksUntilIdle();
262 EXPECT_EQ(1, temp_callback_count_);
263 host_->TranslationFinished(0, 0, true);
264 content::RunAllBlockingPoolTasksUntilIdle();
265 EXPECT_EQ(0U, host_->pending_translations());
266 GET_NEXE_FD(0, 0, false, info, true);
267 // Request the second before the first temp file returns.
268 GET_NEXE_FD(0, 1, false, info, true);
269 content::RunAllBlockingPoolTasksUntilIdle();
270 EXPECT_EQ(3, temp_callback_count_);
271 EXPECT_EQ(0U, host_->pending_translations());
274 TEST_F(PnaclHostTest, OverlappedHitsAfterTempReturn) {
275 nacl::PnaclCacheInfo info = GetTestCacheInfo();
276 // Store one in the cache and complete it.
277 GET_NEXE_FD(0, 0, false, info, false);
278 content::RunAllBlockingPoolTasksUntilIdle();
279 EXPECT_EQ(1, temp_callback_count_);
280 host_->TranslationFinished(0, 0, true);
281 content::RunAllBlockingPoolTasksUntilIdle();
282 EXPECT_EQ(0U, host_->pending_translations());
283 GET_NEXE_FD(0, 0, false, info, true);
284 content::RunAllBlockingPoolTasksUntilIdle();
285 GET_NEXE_FD(0, 1, false, info, true);
286 content::RunAllBlockingPoolTasksUntilIdle();
287 EXPECT_EQ(3, temp_callback_count_);
288 EXPECT_EQ(0U, host_->pending_translations());
291 TEST_F(PnaclHostTest, OverlappedMissesRendererClosing) {
292 nacl::PnaclCacheInfo info = GetTestCacheInfo();
293 GET_NEXE_FD(0, 0, false, info, false);
294 // Send the 2nd fd request from a different renderer.
295 // Test that it eventually gets an fd after the first renderer closes.
296 GET_NEXE_FD(1, 1, false, info, false);
297 content::RunAllBlockingPoolTasksUntilIdle();
298 EXPECT_EQ(1, temp_callback_count_);
299 EXPECT_EQ(2U, host_->pending_translations());
300 content::RunAllBlockingPoolTasksUntilIdle();
301 EXPECT_EQ(2U, host_->pending_translations());
302 EXPECT_EQ(1, temp_callback_count_);
303 host_->RendererClosing(0);
304 content::RunAllBlockingPoolTasksUntilIdle();
305 EXPECT_EQ(2, temp_callback_count_);
306 EXPECT_EQ(1U, host_->pending_translations());
307 host_->RendererClosing(1);
310 TEST_F(PnaclHostTest, Incognito) {
311 nacl::PnaclCacheInfo info = GetTestCacheInfo();
312 GET_NEXE_FD(0, 0, true, info, false);
313 content::RunAllBlockingPoolTasksUntilIdle();
314 EXPECT_EQ(1, temp_callback_count_);
315 host_->TranslationFinished(0, 0, true);
316 content::RunAllBlockingPoolTasksUntilIdle();
317 // Check that an incognito translation is not stored in the cache
318 GET_NEXE_FD(0, 0, false, info, false);
319 content::RunAllBlockingPoolTasksUntilIdle();
320 EXPECT_EQ(2, temp_callback_count_);
321 host_->TranslationFinished(0, 0, true);
322 content::RunAllBlockingPoolTasksUntilIdle();
323 // Check that an incognito translation can hit from a normal one.
324 GET_NEXE_FD(0, 0, true, info, true);
325 content::RunAllBlockingPoolTasksUntilIdle();
326 EXPECT_EQ(3, temp_callback_count_);
329 TEST_F(PnaclHostTest, IncognitoOverlappedMiss) {
330 nacl::PnaclCacheInfo info = GetTestCacheInfo();
331 GET_NEXE_FD(0, 0, true, info, false);
332 GET_NEXE_FD(0, 1, false, info, false);
333 content::RunAllBlockingPoolTasksUntilIdle();
334 // Check that both translations have returned misses, (i.e. that the
335 // second one has not blocked on the incognito one)
336 EXPECT_EQ(2, temp_callback_count_);
337 host_->TranslationFinished(0, 0, true);
338 host_->TranslationFinished(0, 1, true);
339 content::RunAllBlockingPoolTasksUntilIdle();
340 EXPECT_EQ(0U, host_->pending_translations());
342 // Same test, but issue the 2nd request after the first has returned a miss.
343 info.abi_version = 222;
344 GET_NEXE_FD(0, 0, true, info, false);
345 content::RunAllBlockingPoolTasksUntilIdle();
346 EXPECT_EQ(3, temp_callback_count_);
347 GET_NEXE_FD(0, 1, false, info, false);
348 content::RunAllBlockingPoolTasksUntilIdle();
349 EXPECT_EQ(4, temp_callback_count_);
350 host_->RendererClosing(0);
353 TEST_F(PnaclHostTest, IncognitoSecondOverlappedMiss) {
354 // If the non-incognito request comes first, it should
355 // behave exactly like OverlappedMissBeforeTempReturn
356 nacl::PnaclCacheInfo info = GetTestCacheInfo();
357 GET_NEXE_FD(0, 0, false, info, false);
358 // Send the 2nd fd request before the first one returns a temp file.
359 GET_NEXE_FD(0, 1, true, info, true);
360 content::RunAllBlockingPoolTasksUntilIdle();
361 EXPECT_EQ(1, temp_callback_count_);
362 EXPECT_EQ(2U, host_->pending_translations());
363 content::RunAllBlockingPoolTasksUntilIdle();
364 EXPECT_EQ(2U, host_->pending_translations());
365 EXPECT_EQ(1, temp_callback_count_);
366 host_->TranslationFinished(0, 0, true);
367 content::RunAllBlockingPoolTasksUntilIdle();
368 EXPECT_EQ(2, temp_callback_count_);
369 EXPECT_EQ(0U, host_->pending_translations());
372 // Test that pexes with the no-store header do not get cached.
373 TEST_F(PnaclHostTest, CacheControlNoStore) {
374 nacl::PnaclCacheInfo info = GetTestCacheInfo();
375 info.has_no_store_header = true;
376 GET_NEXE_FD(0, 0, false, info, false);
377 content::RunAllBlockingPoolTasksUntilIdle();
378 EXPECT_EQ(1, temp_callback_count_);
379 host_->TranslationFinished(0, 0, true);
380 content::RunAllBlockingPoolTasksUntilIdle();
381 EXPECT_EQ(0U, host_->pending_translations());
382 EXPECT_EQ(0, GetCacheSize());
385 // Test that no-store pexes do not wait, but do duplicate translations
386 TEST_F(PnaclHostTest, NoStoreOverlappedMiss) {
387 nacl::PnaclCacheInfo info = GetTestCacheInfo();
388 info.has_no_store_header = true;
389 GET_NEXE_FD(0, 0, false, info, false);
390 GET_NEXE_FD(0, 1, false, info, false);
391 content::RunAllBlockingPoolTasksUntilIdle();
392 // Check that both translations have returned misses, (i.e. that the
393 // second one has not blocked on the first one)
394 EXPECT_EQ(2, temp_callback_count_);
395 host_->TranslationFinished(0, 0, true);
396 host_->TranslationFinished(0, 1, true);
397 content::RunAllBlockingPoolTasksUntilIdle();
398 EXPECT_EQ(0U, host_->pending_translations());
400 // Same test, but issue the 2nd request after the first has returned a miss.
401 info.abi_version = 222;
402 GET_NEXE_FD(0, 0, false, info, false);
403 content::RunAllBlockingPoolTasksUntilIdle();
404 EXPECT_EQ(3, temp_callback_count_);
405 GET_NEXE_FD(0, 1, false, info, false);
406 content::RunAllBlockingPoolTasksUntilIdle();
407 EXPECT_EQ(4, temp_callback_count_);
408 host_->RendererClosing(0);
411 TEST_F(PnaclHostTest, ClearTranslationCache) {
412 nacl::PnaclCacheInfo info = GetTestCacheInfo();
413 // Add 2 entries in the cache
414 GET_NEXE_FD(0, 0, false, info, false);
415 info.abi_version = 222;
416 GET_NEXE_FD(0, 1, false, info, false);
417 content::RunAllBlockingPoolTasksUntilIdle();
418 EXPECT_EQ(2, temp_callback_count_);
419 host_->TranslationFinished(0, 0, true);
420 host_->TranslationFinished(0, 1, true);
421 content::RunAllBlockingPoolTasksUntilIdle();
422 EXPECT_EQ(0U, host_->pending_translations());
423 EXPECT_EQ(2, GetCacheSize());
424 net::TestCompletionCallback cb;
425 // Since we are using a memory backend, the clear should happen immediately.
426 host_->ClearTranslationCacheEntriesBetween(
427 base::Time(), base::Time(), base::Bind(cb.callback(), 0));
428 // Check that the translation cache has been cleared before flushing the
429 // queues, because the backend will be freed once it is.
430 EXPECT_EQ(0, GetCacheSize());
431 EXPECT_EQ(0, cb.GetResult(net::ERR_IO_PENDING));
432 // Now check that the backend has been freed.
433 EXPECT_FALSE(CacheIsInitialized());
436 // A version of PnaclHostTest that initializes cache on disk.
437 class PnaclHostTestDisk : public PnaclHostTest {
438 protected:
439 void SetUp() override {
440 host_ = new PnaclHost();
441 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
442 host_->InitForTest(temp_dir_.path(), false);
443 EXPECT_EQ(PnaclHost::CacheInitializing, host_->cache_state_);
445 void DeInit() {
446 host_->DeInitIfSafe();
449 TEST_F(PnaclHostTestDisk, DeInitWhileInitializing) {
450 // Since there's no easy way to pump message queues one message at a time, we
451 // have to simulate what would happen if 1 DeInitIfsafe task gets queued, then
452 // a GetNexeFd gets queued, and then another DeInitIfSafe gets queued before
453 // the first one runs. We can just shortcut and call DeInitIfSafe while the
454 // cache is still initializing.
455 DeInit();
456 base::RunLoop().RunUntilIdle();
459 } // namespace pnacl