summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-26 04:30:12 +0000
committerncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-05-26 04:30:12 +0000
commit8c67083771dd35498e832fa241aa3adb815b47e9 (patch)
treeb23112e2d07565e48e46c8a5e46e1ad14c539ff7
parentb74b4885d8268a943bb9498abbe1d4a288d97f70 (diff)
downloadchromium_src-8c67083771dd35498e832fa241aa3adb815b47e9.zip
chromium_src-8c67083771dd35498e832fa241aa3adb815b47e9.tar.gz
chromium_src-8c67083771dd35498e832fa241aa3adb815b47e9.tar.bz2
Persist NaCl's validation cache to disk.
Persisting the cache is straightforward: it is pickled, and the pickle data is sent to the blocking pool to be written to disk. Reading the cache off disk is a little trickier, because it needs to be done before sel_ldr is started in the NaCl process. This is implemented as an asynchronous task that blocks starting sel_ldr, similar to opening the IRT. Functionality to serialize and deserialize the validation cache was also added. To improve testability, features such as cache enabling / disabling and UMA reporting were shifted from NaClValidationCache onto the NaClBrowser singleton. This allowed unit tests to be written for NaClValidationCache. BUG= http://code.google.com/p/nativeclient/issues/detail?id=2515 TEST= Run nexe in browser with NACL_VALIDATION_CACHE=1 Review URL: https://chromiumcodereview.appspot.com/10399053 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139179 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/nacl_host/nacl_browser.cc163
-rw-r--r--chrome/browser/nacl_host/nacl_browser.h26
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc9
-rw-r--r--chrome/browser/nacl_host/nacl_validation_cache.cc128
-rw-r--r--chrome/browser/nacl_host/nacl_validation_cache.h27
-rw-r--r--chrome/browser/nacl_host/nacl_validation_cache_unittest.cc180
-rw-r--r--chrome/chrome_tests.gypi2
7 files changed, 477 insertions, 58 deletions
diff --git a/chrome/browser/nacl_host/nacl_browser.cc b/chrome/browser/nacl_host/nacl_browser.cc
index 84ca17c..e2c0d49 100644
--- a/chrome/browser/nacl_host/nacl_browser.cc
+++ b/chrome/browser/nacl_host/nacl_browser.cc
@@ -5,13 +5,28 @@
#include "chrome/browser/nacl_host/nacl_browser.h"
#include "base/message_loop.h"
+#include "base/metrics/histogram.h"
#include "base/path_service.h"
+#include "base/pickle.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_paths_internal.h"
#include "content/public/browser/browser_thread.h"
namespace {
+// An arbitrary delay to coalesce multiple writes to the cache.
+const int kValidationCacheCoalescingTimeMS = 6000;
+const char kValidationCacheSequenceName[] = "NaClValidationCache";
+const FilePath::CharType kValidationCacheFileName[] =
+ FILE_PATH_LITERAL("nacl_validation_cache.bin");
+
+enum ValidationCacheStatus {
+ CACHE_MISS = 0,
+ CACHE_HIT,
+ CACHE_MAX
+};
+
// Determine the name of the IRT file based on the architecture.
#define NACL_IRT_FILE_NAME(arch_string) \
(FILE_PATH_LITERAL("nacl_irt_") \
@@ -39,6 +54,36 @@ const FilePath::StringType NaClIrtName() {
#endif
}
+bool CheckEnvVar(const char* name, bool default_value) {
+ bool result = default_value;
+ const char* var = getenv(name);
+ if (var && strlen(var) > 0) {
+ result = var[0] != '0';
+ }
+ return result;
+}
+
+void ReadCache(const FilePath& filename, std::string* data) {
+ if (!file_util::ReadFileToString(filename, data)) {
+ // Zero-size data used as an in-band error code.
+ data->clear();
+ }
+}
+
+void WriteCache(const FilePath& filename, const Pickle* pickle) {
+ file_util::WriteFile(filename, static_cast<const char*>(pickle->data()),
+ pickle->size());
+}
+
+void LogCacheQuery(ValidationCacheStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX);
+}
+
+void LogCacheSet(ValidationCacheStatus status) {
+ // Bucket zero is reserved for future use.
+ UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX);
+}
+
} // namespace
NaClBrowser::NaClBrowser()
@@ -46,6 +91,10 @@ NaClBrowser::NaClBrowser()
irt_platform_file_(base::kInvalidPlatformFileValue),
irt_filepath_(),
irt_state_(NaClResourceUninitialized),
+ validation_cache_file_path_(),
+ validation_cache_is_enabled_(CheckEnvVar("NACL_VALIDATION_CACHE", false)),
+ validation_cache_is_modified_(false),
+ validation_cache_state_(NaClResourceUninitialized),
ok_(true) {
InitIrtFilePath();
}
@@ -82,7 +131,9 @@ NaClBrowser* NaClBrowser::GetInstance() {
}
bool NaClBrowser::IsReady() const {
- return IsOk() && irt_state_ == NaClResourceReady;
+ return (IsOk() &&
+ irt_state_ == NaClResourceReady &&
+ validation_cache_state_ == NaClResourceReady);
}
bool NaClBrowser::IsOk() const {
@@ -96,9 +147,8 @@ base::PlatformFile NaClBrowser::IrtFile() const {
}
void NaClBrowser::EnsureAllResourcesAvailable() {
- // Currently the only resource we need to initialize is the IRT.
- // In the future we will need to load the validation cache from disk.
EnsureIrtAvailable();
+ EnsureValidationCacheAvailable();
}
// Load the IRT async.
@@ -136,6 +186,66 @@ void NaClBrowser::OnIrtOpened(base::PlatformFileError error_code,
CheckWaiting();
}
+void NaClBrowser::EnsureValidationCacheAvailable() {
+ if (IsOk() && validation_cache_state_ == NaClResourceUninitialized) {
+ if (ValidationCacheIsEnabled()) {
+ validation_cache_state_ = NaClResourceRequested;
+
+ // Determine where the validation cache resides in the file system. It
+ // exists in Chrome's cache directory and is not tied to any specific
+ // profile.
+ // Start by finding the user data directory.
+ FilePath user_data_dir;
+ if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
+ RunWithoutValidationCache();
+ return;
+ }
+ // The cache directory may or may not be the user data directory.
+ FilePath cache_file_path;
+ chrome::GetUserCacheDirectory(user_data_dir, &cache_file_path);
+ // Append the base file name to the cache directory.
+ validation_cache_file_path_ =
+ cache_file_path.Append(kValidationCacheFileName);
+
+ // Structure for carrying data between the callbacks.
+ std::string* data = new std::string();
+ // We can get away not giving this a sequence ID because this is the first
+ // task and further file access will not occur until after we get a
+ // response.
+ if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
+ FROM_HERE,
+ base::Bind(ReadCache, validation_cache_file_path_, data),
+ base::Bind(&NaClBrowser::OnValidationCacheLoaded,
+ weak_factory_.GetWeakPtr(),
+ base::Owned(data)))) {
+ RunWithoutValidationCache();
+ }
+ } else {
+ RunWithoutValidationCache();
+ }
+ }
+}
+
+void NaClBrowser::OnValidationCacheLoaded(const std::string *data) {
+ if (data->size() == 0) {
+ // No file found.
+ validation_cache_.Reset();
+ } else {
+ Pickle pickle(data->data(), data->size());
+ validation_cache_.Deserialize(&pickle);
+ }
+ validation_cache_state_ = NaClResourceReady;
+ CheckWaiting();
+}
+
+void NaClBrowser::RunWithoutValidationCache() {
+ // Be paranoid.
+ validation_cache_.Reset();
+ validation_cache_is_enabled_ = false;
+ validation_cache_state_ = NaClResourceReady;
+ CheckWaiting();
+}
+
void NaClBrowser::CheckWaiting() {
if (!IsOk() || IsReady()) {
// Queue the waiting tasks into the message loop. This helps avoid
@@ -164,3 +274,50 @@ void NaClBrowser::WaitForResources(const base::Closure& reply) {
const FilePath& NaClBrowser::GetIrtFilePath() {
return irt_filepath_;
}
+
+bool NaClBrowser::QueryKnownToValidate(const std::string& signature) {
+ bool result = validation_cache_.QueryKnownToValidate(signature);
+ LogCacheQuery(result ? CACHE_HIT : CACHE_MISS);
+ // Queries can modify the MRU order of the cache.
+ MarkValidationCacheAsModified();
+ return result;
+}
+
+void NaClBrowser::SetKnownToValidate(const std::string& signature) {
+ validation_cache_.SetKnownToValidate(signature);
+ // The number of sets should be equal to the number of cache misses, minus
+ // validation failures and successful validations where stubout occurs.
+ LogCacheSet(CACHE_HIT);
+ MarkValidationCacheAsModified();
+}
+
+void NaClBrowser::MarkValidationCacheAsModified() {
+ if (!validation_cache_is_modified_) {
+ // Wait before persisting to disk. This can coalesce multiple cache
+ // modifications info a single disk write.
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&NaClBrowser::PersistValidationCache,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kValidationCacheCoalescingTimeMS));
+ validation_cache_is_modified_ = true;
+ }
+}
+
+void NaClBrowser::PersistValidationCache() {
+ if (!validation_cache_file_path_.empty()) {
+ Pickle* pickle = new Pickle();
+ validation_cache_.Serialize(pickle);
+
+ // Pass the serialized data to another thread to write to disk. File IO is
+ // not allowed on the IO thread (which is the thread this method runs on)
+ // because it can degrade the responsiveness of the browser.
+ // The task is sequenced so that multiple writes happen in order.
+ content::BrowserThread::PostBlockingPoolSequencedTask(
+ kValidationCacheSequenceName,
+ FROM_HERE,
+ base::Bind(WriteCache, validation_cache_file_path_,
+ base::Owned(pickle)));
+ }
+ validation_cache_is_modified_ = false;
+}
diff --git a/chrome/browser/nacl_host/nacl_browser.h b/chrome/browser/nacl_host/nacl_browser.h
index 4fac991b..96b63c4 100644
--- a/chrome/browser/nacl_host/nacl_browser.h
+++ b/chrome/browser/nacl_host/nacl_browser.h
@@ -44,7 +44,16 @@ class NaClBrowser {
// IRT file handle, only available when IsReady().
base::PlatformFile IrtFile() const;
- NaClValidationCache validation_cache;
+ bool ValidationCacheIsEnabled() const {
+ return validation_cache_is_enabled_;
+ }
+
+ const std::string& GetValidationCacheKey() const {
+ return validation_cache_.GetValidationCacheKey();
+ }
+
+ bool QueryKnownToValidate(const std::string& signature);
+ void SetKnownToValidate(const std::string& signature);
private:
friend struct DefaultSingletonTraits<NaClBrowser>;
@@ -65,19 +74,32 @@ class NaClBrowser {
void OnIrtOpened(base::PlatformFileError error_code,
base::PassPlatformFile file, bool created);
+ void EnsureValidationCacheAvailable();
+ void OnValidationCacheLoaded(const std::string* data);
+ void RunWithoutValidationCache();
+
// Dispatch waiting tasks if we are ready, or if we know we'll never be ready.
void CheckWaiting();
// Indicate that it is impossible to launch a NaCl process.
void MarkAsFailed();
+ void MarkValidationCacheAsModified();
+ void PersistValidationCache();
+
// Singletons get destroyed at shutdown.
base::WeakPtrFactory<NaClBrowser> weak_factory_;
base::PlatformFile irt_platform_file_;
FilePath irt_filepath_;
-
NaClResourceState irt_state_;
+
+ NaClValidationCache validation_cache_;
+ FilePath validation_cache_file_path_;
+ bool validation_cache_is_enabled_;
+ bool validation_cache_is_modified_;
+ NaClResourceState validation_cache_state_;
+
bool ok_;
// A list of pending tasks to start NaCl processes.
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index 3e9ec97..b5aa055 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -599,9 +599,8 @@ bool NaClProcessHost::StartNaClExecution() {
NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
nacl::NaClStartParams params;
- params.validation_cache_enabled = nacl_browser->validation_cache.IsEnabled();
- params.validation_cache_key =
- nacl_browser->validation_cache.GetValidationCacheKey();
+ params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled();
+ params.validation_cache_key = nacl_browser->GetValidationCacheKey();
params.version = chrome::VersionInfo().CreateVersionString();
params.enable_exception_handling = enable_exception_handling_;
@@ -684,11 +683,11 @@ bool NaClProcessHost::StartWithLaunchedProcess() {
void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature,
bool* result) {
NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
- *result = nacl_browser->validation_cache.QueryKnownToValidate(signature);
+ *result = nacl_browser->QueryKnownToValidate(signature);
}
void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) {
- NaClBrowser::GetInstance()->validation_cache.SetKnownToValidate(signature);
+ NaClBrowser::GetInstance()->SetKnownToValidate(signature);
}
#if defined(OS_WIN)
diff --git a/chrome/browser/nacl_host/nacl_validation_cache.cc b/chrome/browser/nacl_host/nacl_validation_cache.cc
index 84c45ab..669fe94 100644
--- a/chrome/browser/nacl_host/nacl_validation_cache.cc
+++ b/chrome/browser/nacl_host/nacl_validation_cache.cc
@@ -4,7 +4,7 @@
#include "chrome/browser/nacl_host/nacl_validation_cache.h"
-#include "base/metrics/histogram.h"
+#include "base/pickle.h"
#include "base/rand_util.h"
namespace {
@@ -16,37 +16,16 @@ const size_t kValidationCacheKeySize = 64;
// Entry size is equal to the digest size of SHA256.
const size_t kValidationCacheEntrySize = 32;
-enum ValidationCacheStatus {
- CACHE_MISS = 0,
- CACHE_HIT,
- CACHE_ERROR,
- CACHE_MAX
-};
-
-void LogCacheQuery(ValidationCacheStatus status) {
- UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query", status, CACHE_MAX);
-}
-
-void LogCacheSet(ValidationCacheStatus status) {
- // Bucket zero is reserved for future use.
- UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", status, CACHE_MAX);
-}
-
-bool CheckEnvVar(const char* name, bool default_value) {
- bool result = default_value;
- const char* var = getenv(name);
- if (var && strlen(var) > 0) {
- result = var[0] != '0';
- }
- return result;
-}
+const char kValidationCacheBeginMagic[] = "NaCl";
+const char kValidationCacheEndMagic[] = "Done";
} // namespace
NaClValidationCache::NaClValidationCache()
- : validation_cache_(kValidationCacheCacheSize),
- validation_cache_key_(base::RandBytesAsString(kValidationCacheKeySize)),
- enabled_(CheckEnvVar("NACL_VALIDATION_CACHE", false)){
+ : validation_cache_(kValidationCacheCacheSize) {
+ // Make sure the cache key is unpredictable, even if the cache has not
+ // been loaded.
+ Reset();
}
NaClValidationCache::~NaClValidationCache() {
@@ -54,28 +33,91 @@ NaClValidationCache::~NaClValidationCache() {
}
bool NaClValidationCache::QueryKnownToValidate(const std::string& signature) {
- bool result = false;
- if (signature.length() != kValidationCacheEntrySize) {
- // Signature is the wrong size, something is wrong.
- LogCacheQuery(CACHE_ERROR);
- } else {
+ if (signature.length() == kValidationCacheEntrySize) {
ValidationCacheType::iterator iter = validation_cache_.Get(signature);
if (iter != validation_cache_.end()) {
- result = iter->second;
+ return iter->second;
}
- LogCacheQuery(result ? CACHE_HIT : CACHE_MISS);
}
- return result;
+ return false;
}
void NaClValidationCache::SetKnownToValidate(const std::string& signature) {
- if (signature.length() != kValidationCacheEntrySize) {
- // Signature is the wrong size, something is wrong.
- LogCacheSet(CACHE_ERROR);
- } else {
+ if (signature.length() == kValidationCacheEntrySize) {
validation_cache_.Put(signature, true);
- // The number of sets should be equal to the number of cache misses, minus
- // validation failures and successful validations where stubout occurs.
- LogCacheSet(CACHE_HIT);
}
}
+
+void NaClValidationCache::Serialize(Pickle* pickle) const {
+ // Mark the beginning of the data stream.
+ pickle->WriteString(kValidationCacheBeginMagic);
+ pickle->WriteString(validation_cache_key_);
+ pickle->WriteInt(validation_cache_.size());
+
+ // Serialize the cache in reverse order so that deserializing it can easily
+ // preserve the MRU order. (Last item deserialized => most recently used.)
+ ValidationCacheType::const_reverse_iterator iter;
+ for (iter = validation_cache_.rbegin();
+ iter != validation_cache_.rend();
+ ++iter) {
+ pickle->WriteString(iter->first);
+ }
+
+ // Mark the end of the data stream.
+ pickle->WriteString(kValidationCacheEndMagic);
+}
+
+void NaClValidationCache::Reset() {
+ validation_cache_key_ = base::RandBytesAsString(kValidationCacheKeySize);
+ validation_cache_.Clear();
+}
+
+bool NaClValidationCache::Deserialize(const Pickle* pickle) {
+ bool success = DeserializeImpl(pickle);
+ if (!success) {
+ Reset();
+ }
+ return success;
+}
+
+bool NaClValidationCache::DeserializeImpl(const Pickle* pickle) {
+ PickleIterator iter(*pickle);
+ std::string buffer;
+ int count;
+
+ // Magic
+ if (!iter.ReadString(&buffer))
+ return false;
+ if (0 != buffer.compare(kValidationCacheBeginMagic))
+ return false;
+
+ // Key
+ if (!iter.ReadString(&buffer))
+ return false;
+ if (buffer.size() != kValidationCacheKeySize)
+ return false;
+
+ validation_cache_key_ = buffer;
+ validation_cache_.Clear();
+
+ // Cache entries
+ if (!iter.ReadInt(&count))
+ return false;
+ for (int i = 0; i < count; ++i) {
+ if (!iter.ReadString(&buffer))
+ return false;
+ if (buffer.size() != kValidationCacheEntrySize)
+ return false;
+ validation_cache_.Put(buffer, true);
+ }
+
+ // Magic
+ if (!iter.ReadString(&buffer))
+ return false;
+ if (0 != buffer.compare(kValidationCacheEndMagic))
+ return false;
+
+ // Success!
+ return true;
+}
+
diff --git a/chrome/browser/nacl_host/nacl_validation_cache.h b/chrome/browser/nacl_host/nacl_validation_cache.h
index eace325..bdcb217 100644
--- a/chrome/browser/nacl_host/nacl_validation_cache.h
+++ b/chrome/browser/nacl_host/nacl_validation_cache.h
@@ -27,19 +27,36 @@ class NaClValidationCache {
// Put the validation signature in the database.
void SetKnownToValidate(const std::string& signature);
- // Should the cache be used?
- bool IsEnabled() {
- return enabled_;
+ void Reset();
+ void Serialize(Pickle* pickle) const;
+ bool Deserialize(const Pickle* pickle);
+
+ // Testing functions
+ size_t size() const {
+ return validation_cache_.size();
+ }
+ void SetValidationCacheKey(std::string& key) {
+ validation_cache_key_ = key;
+ }
+ std::vector<std::string> GetContents() const {
+ std::vector<std::string> contents;
+ ValidationCacheType::const_iterator iter = validation_cache_.begin();
+ for (iter = validation_cache_.begin();
+ iter != validation_cache_.end();
+ iter++) {
+ contents.push_back(iter->first);
+ }
+ return contents;
}
private:
+ bool DeserializeImpl(const Pickle* pickle);
+
typedef base::HashingMRUCache<std::string, bool> ValidationCacheType;
ValidationCacheType validation_cache_;
std::string validation_cache_key_;
- bool enabled_;
-
DISALLOW_COPY_AND_ASSIGN(NaClValidationCache);
};
diff --git a/chrome/browser/nacl_host/nacl_validation_cache_unittest.cc b/chrome/browser/nacl_host/nacl_validation_cache_unittest.cc
new file mode 100644
index 0000000..42c9653
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_validation_cache_unittest.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2012 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 "base/pickle.h"
+#include "chrome/browser/nacl_host/nacl_validation_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char key1[65] =
+ "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
+const char key2[65] =
+ "a 64-byte string of various junk................................";
+const char sig1[33] = "0123456789ABCDEF0123456789ABCDEF";
+const char sig2[33] = "a 32-byte string of various junk";
+
+class NaClValidationCacheTest : public ::testing::Test {
+ protected:
+ NaClValidationCache cache1;
+ NaClValidationCache cache2;
+
+ void SetUp() {
+ // The compiler chokes if std::string(key1) is passed directly as an arg.
+ std::string key(key1);
+ cache1.SetValidationCacheKey(key);
+ cache2.SetValidationCacheKey(key);
+ }
+
+ bool IsIdentical(const NaClValidationCache& a,
+ const NaClValidationCache& b) const {
+ if (a.GetValidationCacheKey() != b.GetValidationCacheKey())
+ return false;
+ if (a.size() != b.size())
+ return false;
+ return a.GetContents() == b.GetContents();
+ }
+};
+
+TEST_F(NaClValidationCacheTest, Sanity) {
+ ASSERT_EQ(0, (int) cache1.size());
+ ASSERT_FALSE(cache1.QueryKnownToValidate(sig1));
+ ASSERT_FALSE(cache1.QueryKnownToValidate(sig2));
+}
+
+TEST_F(NaClValidationCacheTest, Sig1) {
+ cache1.SetKnownToValidate(sig1);
+ ASSERT_EQ(1, (int) cache1.size());
+ ASSERT_TRUE(cache1.QueryKnownToValidate(sig1));
+ ASSERT_FALSE(cache1.QueryKnownToValidate(sig2));
+}
+
+TEST_F(NaClValidationCacheTest, Sig2) {
+ cache1.SetKnownToValidate(sig2);
+ ASSERT_EQ(1, (int) cache1.size());
+ ASSERT_FALSE(cache1.QueryKnownToValidate(sig1));
+ ASSERT_TRUE(cache1.QueryKnownToValidate(sig2));
+}
+
+TEST_F(NaClValidationCacheTest, SigBoth) {
+ cache1.SetKnownToValidate(sig1);
+ cache1.SetKnownToValidate(sig2);
+ ASSERT_EQ(2, (int) cache1.size());
+ ASSERT_TRUE(cache1.QueryKnownToValidate(sig1));
+ ASSERT_TRUE(cache1.QueryKnownToValidate(sig2));
+}
+
+TEST_F(NaClValidationCacheTest, DoubleSet) {
+ cache1.SetKnownToValidate(sig1);
+ cache1.SetKnownToValidate(sig1);
+ ASSERT_EQ(1, (int) cache1.size());
+ ASSERT_TRUE(cache1.QueryKnownToValidate(sig1));
+}
+
+TEST_F(NaClValidationCacheTest, EmptyIdentical) {
+ ASSERT_TRUE(IsIdentical(cache1, cache2));
+}
+
+TEST_F(NaClValidationCacheTest, DifferentKeysNotIdentical) {
+ std::string key(key2);
+ cache2.SetValidationCacheKey(key);
+ ASSERT_FALSE(IsIdentical(cache1, cache2));
+}
+
+
+TEST_F(NaClValidationCacheTest, DifferentSizesNotIdentical) {
+ cache1.SetKnownToValidate(sig1);
+
+ ASSERT_FALSE(IsIdentical(cache1, cache2));
+}
+
+TEST_F(NaClValidationCacheTest, SameSigsIdentical) {
+ cache1.SetKnownToValidate(sig1);
+
+ cache2.SetKnownToValidate(sig1);
+
+ ASSERT_TRUE(IsIdentical(cache1, cache2));
+}
+
+TEST_F(NaClValidationCacheTest, DifferentSigsNotIdentical) {
+ cache1.SetKnownToValidate(sig1);
+
+ cache2.SetKnownToValidate(sig2);
+
+ ASSERT_FALSE(IsIdentical(cache1, cache2));
+}
+
+TEST_F(NaClValidationCacheTest, InOrderIdentical) {
+ cache1.SetKnownToValidate(sig1);
+ cache1.SetKnownToValidate(sig2);
+
+ cache2.SetKnownToValidate(sig1);
+ cache2.SetKnownToValidate(sig2);
+
+ ASSERT_TRUE(IsIdentical(cache1, cache2));
+}
+
+TEST_F(NaClValidationCacheTest, OutOfOrderNotIdentical) {
+ cache1.SetKnownToValidate(sig1);
+ cache1.SetKnownToValidate(sig2);
+
+ cache2.SetKnownToValidate(sig2);
+ cache2.SetKnownToValidate(sig1);
+
+ ASSERT_FALSE(IsIdentical(cache1, cache2));
+}
+
+TEST_F(NaClValidationCacheTest, SerializeDeserialize) {
+ std::string key(key2);
+ cache1.SetValidationCacheKey(key);
+ cache1.SetKnownToValidate(sig1);
+ cache1.SetKnownToValidate(sig2);
+
+ Pickle pickle;
+ cache1.Serialize(&pickle);
+ ASSERT_TRUE(cache2.Deserialize(&pickle));
+ ASSERT_EQ(2, (int) cache2.size());
+ ASSERT_TRUE(IsIdentical(cache1, cache2));
+}
+
+TEST_F(NaClValidationCacheTest, SerializeDeserializeTruncated) {
+ std::string key(key2);
+ cache1.SetValidationCacheKey(key);
+ cache1.SetKnownToValidate(sig1);
+ cache1.SetKnownToValidate(sig2);
+
+ Pickle pickle;
+ cache1.Serialize(&pickle);
+ Pickle truncated(static_cast<const char*>(pickle.data()), pickle.size()-20);
+ ASSERT_FALSE(cache2.Deserialize(&truncated));
+ ASSERT_EQ(0, (int) cache2.size());
+}
+
+TEST_F(NaClValidationCacheTest, DeserializeBadKey) {
+ std::string key(sig1); // Too short, will cause the deserialization to error.
+ cache1.SetValidationCacheKey(key);
+ cache1.SetKnownToValidate(sig1);
+ cache1.SetKnownToValidate(sig2);
+
+ Pickle pickle;
+ cache1.Serialize(&pickle);
+ ASSERT_FALSE(cache2.Deserialize(&pickle));
+ ASSERT_EQ(0, (int) cache2.size());
+}
+
+TEST_F(NaClValidationCacheTest, DeserializeNothing) {
+ cache1.SetKnownToValidate(sig1);
+ Pickle pickle("", 0);
+ ASSERT_FALSE(cache1.Deserialize(&pickle));
+ ASSERT_EQ(0, (int) cache1.size());
+}
+
+TEST_F(NaClValidationCacheTest, DeserializeJunk) {
+ cache1.SetKnownToValidate(sig1);
+ Pickle pickle(key1, strlen(key1));
+ ASSERT_FALSE(cache1.Deserialize(&pickle));
+ ASSERT_EQ(0, (int) cache1.size());
+}
+
+}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index b586d65..ab9a9d0 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1306,6 +1306,7 @@
'browser/metrics/metrics_service_unittest.cc',
'browser/metrics/thread_watcher_unittest.cc',
'browser/metrics/variations_service_unittest.cc',
+ 'browser/nacl_host/nacl_validation_cache_unittest.cc',
'browser/net/chrome_fraudulent_certificate_reporter_unittest.cc',
'browser/net/chrome_net_log_unittest.cc',
'browser/net/connection_tester_unittest.cc',
@@ -2012,6 +2013,7 @@
}],
['disable_nacl==1', {
'sources!':[
+ 'browser/nacl_host/nacl_validation_cache_unittest.cc',
'nacl/nacl_ipc_adapter_unittest.cc',
'nacl/nacl_validation_query_unittest.cc',
],