pnacl_translation_cache_unittest.cc 11 KB

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