diff options
Diffstat (limited to 'components/nacl/browser/pnacl_translation_cache_unittest.cc')
-rw-r--r-- | components/nacl/browser/pnacl_translation_cache_unittest.cc | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/components/nacl/browser/pnacl_translation_cache_unittest.cc b/components/nacl/browser/pnacl_translation_cache_unittest.cc new file mode 100644 index 0000000..94cd681 --- /dev/null +++ b/components/nacl/browser/pnacl_translation_cache_unittest.cc @@ -0,0 +1,269 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/nacl/browser/pnacl_translation_cache.h" + +#include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "components/nacl/common/pnacl_types.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "net/base/io_buffer.h" +#include "net/base/test_completion_callback.h" +#include "testing/gtest/include/gtest/gtest.h" + +using content::BrowserThread; +using base::FilePath; + +namespace pnacl { + +const int kTestDiskCacheSize = 16 * 1024 * 1024; + +class PnaclTranslationCacheTest : public testing::Test { + protected: + PnaclTranslationCacheTest() + : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {} + virtual ~PnaclTranslationCacheTest() {} + virtual void SetUp() { cache_.reset(new PnaclTranslationCache()); } + virtual void TearDown() { + // The destructor of PnaclTranslationCacheWriteEntry posts a task to the IO + // thread to close the backend cache entry. We want to make sure the entries + // are closed before we delete the backend (and in particular the destructor + // for the memory backend has a DCHECK to verify this), so we run the loop + // here to ensure the task gets processed. + base::RunLoop().RunUntilIdle(); + cache_.reset(); + } + + void InitBackend(bool in_mem); + void StoreNexe(const std::string& key, const std::string& nexe); + std::string GetNexe(const std::string& key); + + scoped_ptr<PnaclTranslationCache> cache_; + content::TestBrowserThreadBundle thread_bundle_; + base::ScopedTempDir temp_dir_; +}; + +void PnaclTranslationCacheTest::InitBackend(bool in_mem) { + net::TestCompletionCallback init_cb; + if (!in_mem) { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + } + // Use the private init method so we can control the size + int rv = cache_->Init(in_mem ? net::MEMORY_CACHE : net::PNACL_CACHE, + temp_dir_.path(), + in_mem ? kMaxMemCacheSize : kTestDiskCacheSize, + init_cb.callback()); + if (in_mem) + ASSERT_EQ(net::OK, rv); + ASSERT_EQ(net::OK, init_cb.GetResult(rv)); + ASSERT_EQ(0, cache_->Size()); +} + +void PnaclTranslationCacheTest::StoreNexe(const std::string& key, + const std::string& nexe) { + net::TestCompletionCallback store_cb; + scoped_refptr<net::DrainableIOBuffer> nexe_buf( + new net::DrainableIOBuffer(new net::StringIOBuffer(nexe), nexe.size())); + cache_->StoreNexe(key, nexe_buf, store_cb.callback()); + // Using ERR_IO_PENDING here causes the callback to wait for the result + // which should be harmless even if it returns OK immediately. This is because + // we don't plumb the intermediate writing stages all the way out. + EXPECT_EQ(net::OK, store_cb.GetResult(net::ERR_IO_PENDING)); +} + +// Inspired by net::TestCompletionCallback. Instantiate a TestNexeCallback and +// pass the GetNexeCallback returned by the callback() method to GetNexe. +// Then call GetResult, which will pump the message loop until it gets a result, +// return the resulting IOBuffer and fill in the return value +class TestNexeCallback { + public: + TestNexeCallback() + : have_result_(false), + result_(-1), + cb_(base::Bind(&TestNexeCallback::SetResult, base::Unretained(this))) {} + GetNexeCallback callback() { return cb_; } + net::DrainableIOBuffer* GetResult(int* result) { + while (!have_result_) + base::RunLoop().RunUntilIdle(); + have_result_ = false; + *result = result_; + return buf_.get(); + } + + private: + void SetResult(int rv, scoped_refptr<net::DrainableIOBuffer> buf) { + have_result_ = true; + result_ = rv; + buf_ = buf; + } + bool have_result_; + int result_; + scoped_refptr<net::DrainableIOBuffer> buf_; + const GetNexeCallback cb_; +}; + +std::string PnaclTranslationCacheTest::GetNexe(const std::string& key) { + TestNexeCallback load_cb; + cache_->GetNexe(key, load_cb.callback()); + int rv; + scoped_refptr<net::DrainableIOBuffer> buf(load_cb.GetResult(&rv)); + EXPECT_EQ(net::OK, rv); + if (buf.get() == NULL) // for some reason ASSERT macros don't work here. + return std::string(); + std::string nexe(buf->data(), buf->size()); + return nexe; +} + +static const std::string test_key("1"); +static const std::string test_store_val("testnexe"); +static const int kLargeNexeSize = 8 * 1024 * 1024; + +TEST(PnaclTranslationCacheKeyTest, CacheKeyTest) { + nacl::PnaclCacheInfo info; + info.pexe_url = GURL("http://www.google.com"); + info.abi_version = 0; + info.opt_level = 0; + std::string test_time("Wed, 15 Nov 1995 06:25:24 GMT"); + base::Time::FromString(test_time.c_str(), &info.last_modified); + // Basic check for URL and time components + EXPECT_EQ("ABI:0;opt:0;URL:http://www.google.com/;" + "modified:1995:11:15:6:25:24:0:UTC;etag:", + PnaclTranslationCache::GetKey(info)); + // Check that query portion of URL is not stripped + info.pexe_url = GURL("http://www.google.com/?foo=bar"); + EXPECT_EQ("ABI:0;opt:0;URL:http://www.google.com/?foo=bar;" + "modified:1995:11:15:6:25:24:0:UTC;etag:", + PnaclTranslationCache::GetKey(info)); + // Check that username, password, and normal port are stripped + info.pexe_url = GURL("https://user:host@www.google.com:443/"); + EXPECT_EQ("ABI:0;opt:0;URL:https://www.google.com/;" + "modified:1995:11:15:6:25:24:0:UTC;etag:", + PnaclTranslationCache::GetKey(info)); + // Check that unusual port is not stripped but ref is stripped + info.pexe_url = GURL("https://www.google.com:444/#foo"); + EXPECT_EQ("ABI:0;opt:0;URL:https://www.google.com:444/;" + "modified:1995:11:15:6:25:24:0:UTC;etag:", + PnaclTranslationCache::GetKey(info)); + // Check chrome-extesnsion scheme + info.pexe_url = GURL("chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/"); + EXPECT_EQ("ABI:0;opt:0;" + "URL:chrome-extension://ljacajndfccfgnfohlgkdphmbnpkjflk/;" + "modified:1995:11:15:6:25:24:0:UTC;etag:", + PnaclTranslationCache::GetKey(info)); + // Check that ABI version, opt level, and etag are in the key + info.pexe_url = GURL("http://www.google.com/"); + info.abi_version = 2; + EXPECT_EQ("ABI:2;opt:0;URL:http://www.google.com/;" + "modified:1995:11:15:6:25:24:0:UTC;etag:", + PnaclTranslationCache::GetKey(info)); + info.opt_level = 2; + EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;" + "modified:1995:11:15:6:25:24:0:UTC;etag:", + PnaclTranslationCache::GetKey(info)); + info.etag = std::string("etag"); + EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;" + "modified:1995:11:15:6:25:24:0:UTC;etag:etag", + PnaclTranslationCache::GetKey(info)); + + // Check for all the time components, and null time + info.last_modified = base::Time(); + EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;" + "modified:0:0:0:0:0:0:0:UTC;etag:etag", + PnaclTranslationCache::GetKey(info)); + test_time.assign("Fri, 29 Feb 2008 13:04:12 GMT"); + base::Time::FromString(test_time.c_str(), &info.last_modified); + EXPECT_EQ("ABI:2;opt:2;URL:http://www.google.com/;" + "modified:2008:2:29:13:4:12:0:UTC;etag:etag", + PnaclTranslationCache::GetKey(info)); +} + +TEST_F(PnaclTranslationCacheTest, StoreSmallInMem) { + // Test that a single store puts something in the mem backend + InitBackend(true); + StoreNexe(test_key, test_store_val); + EXPECT_EQ(1, cache_->Size()); +} + +TEST_F(PnaclTranslationCacheTest, StoreSmallOnDisk) { + // Test that a single store puts something in the disk backend + InitBackend(false); + StoreNexe(test_key, test_store_val); + EXPECT_EQ(1, cache_->Size()); +} + +TEST_F(PnaclTranslationCacheTest, StoreLargeOnDisk) { + // Test a value too large(?) for a single I/O operation + InitBackend(false); + const std::string large_buffer(kLargeNexeSize, 'a'); + StoreNexe(test_key, large_buffer); + EXPECT_EQ(1, cache_->Size()); +} + +TEST_F(PnaclTranslationCacheTest, InMemSizeLimit) { + InitBackend(true); + scoped_refptr<net::DrainableIOBuffer> large_buffer(new net::DrainableIOBuffer( + new net::StringIOBuffer(std::string(kMaxMemCacheSize + 1, 'a')), + kMaxMemCacheSize + 1)); + net::TestCompletionCallback store_cb; + cache_->StoreNexe(test_key, large_buffer, store_cb.callback()); + EXPECT_EQ(net::ERR_FAILED, store_cb.GetResult(net::ERR_IO_PENDING)); + base::RunLoop().RunUntilIdle(); // Ensure the entry is closed. + EXPECT_EQ(0, cache_->Size()); +} + +TEST_F(PnaclTranslationCacheTest, GetOneInMem) { + InitBackend(true); + StoreNexe(test_key, test_store_val); + EXPECT_EQ(1, cache_->Size()); + EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val)); +} + +TEST_F(PnaclTranslationCacheTest, GetOneOnDisk) { + InitBackend(false); + StoreNexe(test_key, test_store_val); + EXPECT_EQ(1, cache_->Size()); + EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val)); +} + +TEST_F(PnaclTranslationCacheTest, GetLargeOnDisk) { + InitBackend(false); + const std::string large_buffer(kLargeNexeSize, 'a'); + StoreNexe(test_key, large_buffer); + EXPECT_EQ(1, cache_->Size()); + EXPECT_EQ(0, GetNexe(test_key).compare(large_buffer)); +} + +TEST_F(PnaclTranslationCacheTest, StoreTwice) { + // Test that storing twice with the same key overwrites + InitBackend(true); + StoreNexe(test_key, test_store_val); + StoreNexe(test_key, test_store_val + "aaa"); + EXPECT_EQ(1, cache_->Size()); + EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val + "aaa")); +} + +TEST_F(PnaclTranslationCacheTest, StoreTwo) { + InitBackend(true); + StoreNexe(test_key, test_store_val); + StoreNexe(test_key + "a", test_store_val + "aaa"); + EXPECT_EQ(2, cache_->Size()); + EXPECT_EQ(0, GetNexe(test_key).compare(test_store_val)); + EXPECT_EQ(0, GetNexe(test_key + "a").compare(test_store_val + "aaa")); +} + +TEST_F(PnaclTranslationCacheTest, GetMiss) { + InitBackend(true); + StoreNexe(test_key, test_store_val); + TestNexeCallback load_cb; + std::string nexe; + cache_->GetNexe(test_key + "a", load_cb.callback()); + int rv; + scoped_refptr<net::DrainableIOBuffer> buf(load_cb.GetResult(&rv)); + EXPECT_EQ(net::ERR_FAILED, rv); +} + +} // namespace pnacl |