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