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_translation_cache.h"
7 #include "base/files/file_path.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "components/nacl/common/pnacl_types.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/test_completion_callback.h"
16 #include "testing/gtest/include/gtest/gtest.h"
18 using content::BrowserThread
;
23 const int kTestDiskCacheSize
= 16 * 1024 * 1024;
25 class PnaclTranslationCacheTest
: public testing::Test
{
27 PnaclTranslationCacheTest()
28 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
) {}
29 virtual ~PnaclTranslationCacheTest() {}
30 virtual void SetUp() { cache_
.reset(new PnaclTranslationCache()); }
31 virtual void TearDown() {
32 // The destructor of PnaclTranslationCacheWriteEntry posts a task to the IO
33 // thread to close the backend cache entry. We want to make sure the entries
34 // are closed before we delete the backend (and in particular the destructor
35 // for the memory backend has a DCHECK to verify this), so we run the loop
36 // here to ensure the task gets processed.
37 base::RunLoop().RunUntilIdle();
41 void InitBackend(bool in_mem
);
42 void StoreNexe(const std::string
& key
, const std::string
& nexe
);
43 std::string
GetNexe(const std::string
& key
);
45 scoped_ptr
<PnaclTranslationCache
> cache_
;
46 content::TestBrowserThreadBundle thread_bundle_
;
47 base::ScopedTempDir temp_dir_
;
50 void PnaclTranslationCacheTest::InitBackend(bool in_mem
) {
51 net::TestCompletionCallback init_cb
;
53 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
55 // Use the private init method so we can control the size
56 int rv
= cache_
->Init(in_mem
? net::MEMORY_CACHE
: net::PNACL_CACHE
,
58 in_mem
? kMaxMemCacheSize
: kTestDiskCacheSize
,
61 ASSERT_EQ(net::OK
, rv
);
62 ASSERT_EQ(net::OK
, init_cb
.GetResult(rv
));
63 ASSERT_EQ(0, cache_
->Size());
66 void PnaclTranslationCacheTest::StoreNexe(const std::string
& key
,
67 const std::string
& nexe
) {
68 net::TestCompletionCallback store_cb
;
69 scoped_refptr
<net::DrainableIOBuffer
> nexe_buf(
70 new net::DrainableIOBuffer(new net::StringIOBuffer(nexe
), nexe
.size()));
71 cache_
->StoreNexe(key
, nexe_buf
.get(), store_cb
.callback());
72 // Using ERR_IO_PENDING here causes the callback to wait for the result
73 // which should be harmless even if it returns OK immediately. This is because
74 // we don't plumb the intermediate writing stages all the way out.
75 EXPECT_EQ(net::OK
, store_cb
.GetResult(net::ERR_IO_PENDING
));
78 // Inspired by net::TestCompletionCallback. Instantiate a TestNexeCallback and
79 // pass the GetNexeCallback returned by the callback() method to GetNexe.
80 // Then call GetResult, which will pump the message loop until it gets a result,
81 // return the resulting IOBuffer and fill in the return value
82 class TestNexeCallback
{
85 : have_result_(false),
87 cb_(base::Bind(&TestNexeCallback::SetResult
, base::Unretained(this))) {}
88 GetNexeCallback
callback() { return cb_
; }
89 net::DrainableIOBuffer
* GetResult(int* result
) {
91 base::RunLoop().RunUntilIdle();
98 void SetResult(int rv
, scoped_refptr
<net::DrainableIOBuffer
> buf
) {
105 scoped_refptr
<net::DrainableIOBuffer
> buf_
;
106 const GetNexeCallback cb_
;
109 std::string
PnaclTranslationCacheTest::GetNexe(const std::string
& key
) {
110 TestNexeCallback load_cb
;
111 cache_
->GetNexe(key
, load_cb
.callback());
113 scoped_refptr
<net::DrainableIOBuffer
> buf(load_cb
.GetResult(&rv
));
114 EXPECT_EQ(net::OK
, rv
);
115 if (buf
.get() == NULL
) // for some reason ASSERT macros don't work here.
116 return std::string();
117 std::string
nexe(buf
->data(), buf
->size());
121 static const std::string
test_key("1");
122 static const std::string
test_store_val("testnexe");
123 static const int kLargeNexeSize
= 8 * 1024 * 1024;
125 TEST(PnaclTranslationCacheKeyTest
, CacheKeyTest
) {
126 nacl::PnaclCacheInfo info
;
127 info
.pexe_url
= GURL("http://www.google.com");
128 info
.abi_version
= 0;
130 info
.sandbox_isa
= "x86-32";
131 std::string
test_time("Wed, 15 Nov 1995 06:25:24 GMT");
132 base::Time::FromString(test_time
.c_str(), &info
.last_modified
);
133 // Basic check for URL and time components
134 EXPECT_EQ("ABI:0;opt:0;URL:http://www.google.com/;"
135 "modified:1995:11:15:6:25:24:0:UTC;etag:;"
136 "sandbox:x86-32;extra_flags:;",
137 PnaclTranslationCache::GetKey(info
));
138 // Check that query portion of URL is not stripped
139 info
.pexe_url
= GURL("http://www.google.com/?foo=bar");
140 EXPECT_EQ("ABI:0;opt:0;URL:http://www.google.com/?foo=bar;"
141 "modified:1995:11:15:6:25:24:0:UTC;etag:;"
142 "sandbox:x86-32;extra_flags:;",
143 PnaclTranslationCache::GetKey(info
));
144 // Check that username, password, and normal port are stripped
145 info
.pexe_url
= GURL("https://user:host@www.google.com:443/");
146 EXPECT_EQ("ABI:0;opt:0;URL:https://www.google.com/;"
147 "modified:1995:11:15:6:25:24:0:UTC;etag:;"
148 "sandbox:x86-32;extra_flags:;",
149 PnaclTranslationCache::GetKey(info
));
150 // Check that unusual port is not stripped but ref is stripped
151 info
.pexe_url
= GURL("https://www.google.com:444/#foo");
152 EXPECT_EQ("ABI:0;opt:0;URL:https://www.google.com:444/;"
153 "modified:1995:11:15:6:25:24:0:UTC;etag:;"
154 "sandbox:x86-32;extra_flags:;",
155 PnaclTranslationCache::GetKey(info
));
156 // Check chrome-extesnsion scheme
157 info
.pexe_url
= GURL("chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/");
158 EXPECT_EQ("ABI:0;opt:0;"
159 "URL:chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/;"
160 "modified:1995:11:15:6:25:24:0:UTC;etag:;"
161 "sandbox:x86-32;extra_flags:;",
162 PnaclTranslationCache::GetKey(info
));
163 // Check that ABI version, opt level, and etag are in the key
164 info
.pexe_url
= GURL("http://www.google.com/");
165 info
.abi_version
= 2;
166 EXPECT_EQ("ABI:2;opt:0;URL:http://www.google.com/;"
167 "modified:1995:11:15:6:25:24:0:UTC;etag:;"
168 "sandbox:x86-32;extra_flags:;",
169 PnaclTranslationCache::GetKey(info
));
171 EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
172 "modified:1995:11:15:6:25:24:0:UTC;etag:;"
173 "sandbox:x86-32;extra_flags:;",
174 PnaclTranslationCache::GetKey(info
));
175 info
.etag
= std::string("etag");
176 EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
177 "modified:1995:11:15:6:25:24:0:UTC;etag:etag;"
178 "sandbox:x86-32;extra_flags:;",
179 PnaclTranslationCache::GetKey(info
));
181 info
.extra_flags
= "-mavx-neon";
182 EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
183 "modified:1995:11:15:6:25:24:0:UTC;etag:etag;"
184 "sandbox:x86-32;extra_flags:-mavx-neon;",
185 PnaclTranslationCache::GetKey(info
));
187 // Check for all the time components, and null time
188 info
.last_modified
= base::Time();
189 EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
190 "modified:0:0:0:0:0:0:0:UTC;etag:etag;"
191 "sandbox:x86-32;extra_flags:-mavx-neon;",
192 PnaclTranslationCache::GetKey(info
));
193 test_time
.assign("Fri, 29 Feb 2008 13:04:12 GMT");
194 base::Time::FromString(test_time
.c_str(), &info
.last_modified
);
195 EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
196 "modified:2008:2:29:13:4:12:0:UTC;etag:etag;"
197 "sandbox:x86-32;extra_flags:-mavx-neon;",
198 PnaclTranslationCache::GetKey(info
));
201 TEST_F(PnaclTranslationCacheTest
, StoreSmallInMem
) {
202 // Test that a single store puts something in the mem backend
204 StoreNexe(test_key
, test_store_val
);
205 EXPECT_EQ(1, cache_
->Size());
208 TEST_F(PnaclTranslationCacheTest
, StoreSmallOnDisk
) {
209 // Test that a single store puts something in the disk backend
211 StoreNexe(test_key
, test_store_val
);
212 EXPECT_EQ(1, cache_
->Size());
215 TEST_F(PnaclTranslationCacheTest
, StoreLargeOnDisk
) {
216 // Test a value too large(?) for a single I/O operation
218 const std::string
large_buffer(kLargeNexeSize
, 'a');
219 StoreNexe(test_key
, large_buffer
);
220 EXPECT_EQ(1, cache_
->Size());
223 TEST_F(PnaclTranslationCacheTest
, InMemSizeLimit
) {
225 scoped_refptr
<net::DrainableIOBuffer
> large_buffer(new net::DrainableIOBuffer(
226 new net::StringIOBuffer(std::string(kMaxMemCacheSize
+ 1, 'a')),
227 kMaxMemCacheSize
+ 1));
228 net::TestCompletionCallback store_cb
;
229 cache_
->StoreNexe(test_key
, large_buffer
.get(), store_cb
.callback());
230 EXPECT_EQ(net::ERR_FAILED
, store_cb
.GetResult(net::ERR_IO_PENDING
));
231 base::RunLoop().RunUntilIdle(); // Ensure the entry is closed.
232 EXPECT_EQ(0, cache_
->Size());
235 TEST_F(PnaclTranslationCacheTest
, GetOneInMem
) {
237 StoreNexe(test_key
, test_store_val
);
238 EXPECT_EQ(1, cache_
->Size());
239 EXPECT_EQ(0, GetNexe(test_key
).compare(test_store_val
));
242 TEST_F(PnaclTranslationCacheTest
, GetOneOnDisk
) {
244 StoreNexe(test_key
, test_store_val
);
245 EXPECT_EQ(1, cache_
->Size());
246 EXPECT_EQ(0, GetNexe(test_key
).compare(test_store_val
));
249 TEST_F(PnaclTranslationCacheTest
, GetLargeOnDisk
) {
251 const std::string
large_buffer(kLargeNexeSize
, 'a');
252 StoreNexe(test_key
, large_buffer
);
253 EXPECT_EQ(1, cache_
->Size());
254 EXPECT_EQ(0, GetNexe(test_key
).compare(large_buffer
));
257 TEST_F(PnaclTranslationCacheTest
, StoreTwice
) {
258 // Test that storing twice with the same key overwrites
260 StoreNexe(test_key
, test_store_val
);
261 StoreNexe(test_key
, test_store_val
+ "aaa");
262 EXPECT_EQ(1, cache_
->Size());
263 EXPECT_EQ(0, GetNexe(test_key
).compare(test_store_val
+ "aaa"));
266 TEST_F(PnaclTranslationCacheTest
, StoreTwo
) {
268 StoreNexe(test_key
, test_store_val
);
269 StoreNexe(test_key
+ "a", test_store_val
+ "aaa");
270 EXPECT_EQ(2, cache_
->Size());
271 EXPECT_EQ(0, GetNexe(test_key
).compare(test_store_val
));
272 EXPECT_EQ(0, GetNexe(test_key
+ "a").compare(test_store_val
+ "aaa"));
275 TEST_F(PnaclTranslationCacheTest
, GetMiss
) {
277 StoreNexe(test_key
, test_store_val
);
278 TestNexeCallback load_cb
;
280 cache_
->GetNexe(test_key
+ "a", load_cb
.callback());
282 scoped_refptr
<net::DrainableIOBuffer
> buf(load_cb
.GetResult(&rv
));
283 EXPECT_EQ(net::ERR_FAILED
, rv
);