xref: /aosp_15_r20/external/cronet/components/nacl/browser/pnacl_translation_cache_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 The Chromium Authors
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_translation_cache.h"
6 
7 #include <memory>
8 
9 #include "base/files/file_path.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/functional/bind.h"
12 #include "base/run_loop.h"
13 #include "build/build_config.h"
14 #include "components/nacl/common/pnacl_types.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/test/browser_task_environment.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/test_completion_callback.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 using content::BrowserThread;
22 using base::FilePath;
23 
24 namespace pnacl {
25 
26 const int kTestDiskCacheSize = 16 * 1024 * 1024;
27 
28 class PnaclTranslationCacheTest : public testing::Test {
29  protected:
PnaclTranslationCacheTest()30   PnaclTranslationCacheTest()
31       : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
~PnaclTranslationCacheTest()32   ~PnaclTranslationCacheTest() override {}
SetUp()33   void SetUp() override { cache_ = std::make_unique<PnaclTranslationCache>(); }
TearDown()34   void TearDown() override {
35     // The destructor of PnaclTranslationCacheWriteEntry posts a task to the IO
36     // thread to close the backend cache entry. We want to make sure the entries
37     // are closed before we delete the backend (and in particular the destructor
38     // for the memory backend has a DCHECK to verify this), so we run the loop
39     // here to ensure the task gets processed.
40     base::RunLoop().RunUntilIdle();
41     cache_.reset();
42   }
43 
44   void InitBackend(bool in_mem);
45   void StoreNexe(const std::string& key, const std::string& nexe);
46   std::string GetNexe(const std::string& key);
47 
48   std::unique_ptr<PnaclTranslationCache> cache_;
49   content::BrowserTaskEnvironment task_environment_;
50   base::ScopedTempDir temp_dir_;
51 };
52 
InitBackend(bool in_mem)53 void PnaclTranslationCacheTest::InitBackend(bool in_mem) {
54   net::TestCompletionCallback init_cb;
55   if (!in_mem) {
56     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
57   }
58   // Use the private init method so we can control the size
59   int rv = cache_->Init(in_mem ? net::MEMORY_CACHE : net::PNACL_CACHE,
60                         in_mem ? base::FilePath() : temp_dir_.GetPath(),
61                         in_mem ? kMaxMemCacheSize : kTestDiskCacheSize,
62                         init_cb.callback());
63   if (in_mem)
64     ASSERT_EQ(net::OK, rv);
65   ASSERT_EQ(net::OK, init_cb.GetResult(rv));
66   ASSERT_EQ(0, cache_->Size());
67 }
68 
StoreNexe(const std::string & key,const std::string & nexe)69 void PnaclTranslationCacheTest::StoreNexe(const std::string& key,
70                                           const std::string& nexe) {
71   net::TestCompletionCallback store_cb;
72   scoped_refptr<net::DrainableIOBuffer> nexe_buf =
73       base::MakeRefCounted<net::DrainableIOBuffer>(
74           base::MakeRefCounted<net::StringIOBuffer>(nexe), nexe.size());
75   cache_->StoreNexe(key, nexe_buf.get(), store_cb.callback());
76   // Using ERR_IO_PENDING here causes the callback to wait for the result
77   // which should be harmless even if it returns OK immediately. This is because
78   // we don't plumb the intermediate writing stages all the way out.
79   EXPECT_EQ(net::OK, store_cb.GetResult(net::ERR_IO_PENDING));
80 }
81 
82 // Inspired by net::TestCompletionCallback. Instantiate a TestNexeCallback and
83 // pass the GetNexeCallback returned by the callback() method to GetNexe.
84 // Then call GetResult, which will pump the message loop until it gets a result,
85 // return the resulting IOBuffer and fill in the return value
86 class TestNexeCallback {
87  public:
TestNexeCallback()88   TestNexeCallback()
89       : have_result_(false),
90         result_(-1),
91         cb_(base::BindOnce(&TestNexeCallback::SetResult,
92                            base::Unretained(this))) {}
callback()93   GetNexeCallback callback() { return std::move(cb_); }
GetResult(int * result)94   net::DrainableIOBuffer* GetResult(int* result) {
95     while (!have_result_)
96       base::RunLoop().RunUntilIdle();
97     have_result_ = false;
98     *result = result_;
99     return buf_.get();
100   }
101 
102  private:
SetResult(int rv,scoped_refptr<net::DrainableIOBuffer> buf)103   void SetResult(int rv, scoped_refptr<net::DrainableIOBuffer> buf) {
104     have_result_ = true;
105     result_ = rv;
106     buf_ = buf;
107   }
108   bool have_result_;
109   int result_;
110   scoped_refptr<net::DrainableIOBuffer> buf_;
111   GetNexeCallback cb_;
112 };
113 
GetNexe(const std::string & key)114 std::string PnaclTranslationCacheTest::GetNexe(const std::string& key) {
115   TestNexeCallback load_cb;
116   cache_->GetNexe(key, load_cb.callback());
117   int rv;
118   scoped_refptr<net::DrainableIOBuffer> buf(load_cb.GetResult(&rv));
119   EXPECT_EQ(net::OK, rv);
120   if (buf.get() == NULL) // for some reason ASSERT macros don't work here.
121     return std::string();
122   std::string nexe(buf->data(), buf->size());
123   return nexe;
124 }
125 
126 static const std::string test_key("1");
127 static const std::string test_store_val("testnexe");
128 static const int kLargeNexeSize = 8 * 1024 * 1024;
129 
TEST(PnaclTranslationCacheKeyTest,CacheKeyTest)130 TEST(PnaclTranslationCacheKeyTest, CacheKeyTest) {
131   nacl::PnaclCacheInfo info;
132   info.pexe_url = GURL("http://www.google.com");
133   info.abi_version = 0;
134   info.opt_level = 0;
135   info.sandbox_isa = "x86-32";
136   std::string test_time("Wed, 15 Nov 1995 06:25:24 GMT");
137   EXPECT_TRUE(base::Time::FromString(test_time.c_str(), &info.last_modified));
138   // Basic check for URL and time components
139   EXPECT_EQ("ABI:0;opt:0;URL:http://www.google.com/;"
140             "modified:1995:11:15:6:25:24:0:UTC;etag:;"
141             "sandbox:x86-32;extra_flags:;",
142             PnaclTranslationCache::GetKey(info));
143   // Check that query portion of URL is not stripped
144   info.pexe_url = GURL("http://www.google.com/?foo=bar");
145   EXPECT_EQ("ABI:0;opt:0;URL:http://www.google.com/?foo=bar;"
146             "modified:1995:11:15:6:25:24:0:UTC;etag:;"
147             "sandbox:x86-32;extra_flags:;",
148             PnaclTranslationCache::GetKey(info));
149   // Check that username, password, and normal port are stripped
150   info.pexe_url = GURL("https://user:[email protected]:443/");
151   EXPECT_EQ("ABI:0;opt:0;URL:https://www.google.com/;"
152             "modified:1995:11:15:6:25:24:0:UTC;etag:;"
153             "sandbox:x86-32;extra_flags:;",
154             PnaclTranslationCache::GetKey(info));
155   // Check that unusual port is not stripped but ref is stripped
156   info.pexe_url = GURL("https://www.google.com:444/#foo");
157   EXPECT_EQ("ABI:0;opt:0;URL:https://www.google.com:444/;"
158             "modified:1995:11:15:6:25:24:0:UTC;etag:;"
159             "sandbox:x86-32;extra_flags:;",
160             PnaclTranslationCache::GetKey(info));
161   // Check chrome-extesnsion scheme
162   info.pexe_url = GURL("chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/");
163   EXPECT_EQ("ABI:0;opt:0;"
164             "URL:chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/;"
165             "modified:1995:11:15:6:25:24:0:UTC;etag:;"
166             "sandbox:x86-32;extra_flags:;",
167             PnaclTranslationCache::GetKey(info));
168   // Check that ABI version, opt level, and etag are in the key
169   info.pexe_url = GURL("http://www.google.com/");
170   info.abi_version = 2;
171   EXPECT_EQ("ABI:2;opt:0;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.opt_level = 2;
176   EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
177             "modified:1995:11:15:6:25:24:0:UTC;etag:;"
178             "sandbox:x86-32;extra_flags:;",
179             PnaclTranslationCache::GetKey(info));
180   // Check that Subzero gets a different cache key.
181   info.use_subzero = true;
182   EXPECT_EQ("ABI:2;opt:2subzero;URL:http://www.google.com/;"
183             "modified:1995:11:15:6:25:24:0:UTC;etag:;"
184             "sandbox:x86-32;extra_flags:;",
185             PnaclTranslationCache::GetKey(info));
186   info.use_subzero = false;
187   info.etag = std::string("etag");
188   EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
189             "modified:1995:11:15:6:25:24:0:UTC;etag:etag;"
190             "sandbox:x86-32;extra_flags:;",
191             PnaclTranslationCache::GetKey(info));
192 
193   info.extra_flags = "-mavx-neon";
194   EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
195             "modified:1995:11:15:6:25:24:0:UTC;etag:etag;"
196             "sandbox:x86-32;extra_flags:-mavx-neon;",
197             PnaclTranslationCache::GetKey(info));
198 
199   // Check for all the time components, and null time
200   info.last_modified = base::Time();
201   EXPECT_EQ(
202       "ABI:2;opt:2;URL:http://www.google.com/;"
203       "modified:1970:1:1:0:0:0:0:UTC;etag:etag;"
204       "sandbox:x86-32;extra_flags:-mavx-neon;",
205       PnaclTranslationCache::GetKey(info));
206   test_time.assign("Fri, 29 Feb 2008 13:04:12 GMT");
207   EXPECT_TRUE(base::Time::FromString(test_time.c_str(), &info.last_modified));
208   EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;"
209             "modified:2008:2:29:13:4:12:0:UTC;etag:etag;"
210             "sandbox:x86-32;extra_flags:-mavx-neon;",
211             PnaclTranslationCache::GetKey(info));
212 }
213 
TEST_F(PnaclTranslationCacheTest,StoreSmallInMem)214 TEST_F(PnaclTranslationCacheTest, StoreSmallInMem) {
215   // Test that a single store puts something in the mem backend
216   InitBackend(true);
217   StoreNexe(test_key, test_store_val);
218   EXPECT_EQ(1, cache_->Size());
219 }
220 
TEST_F(PnaclTranslationCacheTest,StoreSmallOnDisk)221 TEST_F(PnaclTranslationCacheTest, StoreSmallOnDisk) {
222   // Test that a single store puts something in the disk backend
223   InitBackend(false);
224   StoreNexe(test_key, test_store_val);
225   EXPECT_EQ(1, cache_->Size());
226 }
227 
TEST_F(PnaclTranslationCacheTest,StoreLargeOnDisk)228 TEST_F(PnaclTranslationCacheTest, StoreLargeOnDisk) {
229   // Test a value too large(?) for a single I/O operation
230   InitBackend(false);
231   const std::string large_buffer(kLargeNexeSize, 'a');
232   StoreNexe(test_key, large_buffer);
233   EXPECT_EQ(1, cache_->Size());
234 }
235 
TEST_F(PnaclTranslationCacheTest,InMemSizeLimit)236 TEST_F(PnaclTranslationCacheTest, InMemSizeLimit) {
237   InitBackend(true);
238   scoped_refptr<net::DrainableIOBuffer> large_buffer =
239       base::MakeRefCounted<net::DrainableIOBuffer>(
240           base::MakeRefCounted<net::StringIOBuffer>(
241               std::string(kMaxMemCacheSize + 1, 'a')),
242           kMaxMemCacheSize + 1);
243   net::TestCompletionCallback store_cb;
244   cache_->StoreNexe(test_key, large_buffer.get(), store_cb.callback());
245   EXPECT_EQ(net::ERR_FAILED, store_cb.GetResult(net::ERR_IO_PENDING));
246   base::RunLoop().RunUntilIdle();  // Ensure the entry is closed.
247   EXPECT_EQ(0, cache_->Size());
248 }
249 
TEST_F(PnaclTranslationCacheTest,GetOneInMem)250 TEST_F(PnaclTranslationCacheTest, GetOneInMem) {
251   InitBackend(true);
252   StoreNexe(test_key, test_store_val);
253   EXPECT_EQ(1, cache_->Size());
254   EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val));
255 }
256 
TEST_F(PnaclTranslationCacheTest,GetOneOnDisk)257 TEST_F(PnaclTranslationCacheTest, GetOneOnDisk) {
258   InitBackend(false);
259   StoreNexe(test_key, test_store_val);
260   EXPECT_EQ(1, cache_->Size());
261   EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val));
262 }
263 
TEST_F(PnaclTranslationCacheTest,GetLargeOnDisk)264 TEST_F(PnaclTranslationCacheTest, GetLargeOnDisk) {
265   InitBackend(false);
266   const std::string large_buffer(kLargeNexeSize, 'a');
267   StoreNexe(test_key, large_buffer);
268   EXPECT_EQ(1, cache_->Size());
269   EXPECT_EQ(0, GetNexe(test_key).compare(large_buffer));
270 }
271 
TEST_F(PnaclTranslationCacheTest,StoreTwice)272 TEST_F(PnaclTranslationCacheTest, StoreTwice) {
273   // Test that storing twice with the same key overwrites
274   InitBackend(true);
275   StoreNexe(test_key, test_store_val);
276   StoreNexe(test_key, test_store_val + "aaa");
277   EXPECT_EQ(1, cache_->Size());
278   EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val + "aaa"));
279 }
280 
TEST_F(PnaclTranslationCacheTest,StoreTwo)281 TEST_F(PnaclTranslationCacheTest, StoreTwo) {
282   InitBackend(true);
283   StoreNexe(test_key, test_store_val);
284   StoreNexe(test_key + "a", test_store_val + "aaa");
285   EXPECT_EQ(2, cache_->Size());
286   EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val));
287   EXPECT_EQ(0, GetNexe(test_key + "a").compare(test_store_val + "aaa"));
288 }
289 
TEST_F(PnaclTranslationCacheTest,GetMiss)290 TEST_F(PnaclTranslationCacheTest, GetMiss) {
291   InitBackend(true);
292   StoreNexe(test_key, test_store_val);
293   TestNexeCallback load_cb;
294   std::string nexe;
295   cache_->GetNexe(test_key + "a", load_cb.callback());
296   int rv;
297   scoped_refptr<net::DrainableIOBuffer> buf(load_cb.GetResult(&rv));
298   EXPECT_EQ(net::ERR_FAILED, rv);
299 }
300 
301 }  // namespace pnacl
302