blob: 1a244412fe7ef47ad3668bb7716cc73175240007 [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: pulkitg@google.com (Pulkit Goyal)
// Unit test for CachePropertyStore.
#include "pagespeed/opt/http/cache_property_store.h"
#include <cstddef>
#include "pagespeed/kernel/base/cache_interface.h"
#include "pagespeed/kernel/base/callback.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/mock_timer.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/shared_string.h"
#include "pagespeed/kernel/base/thread_system.h"
#include "pagespeed/kernel/cache/lru_cache.h"
#include "pagespeed/kernel/util/platform.h"
#include "pagespeed/kernel/util/simple_stats.h"
#include "pagespeed/opt/http/abstract_property_store_get_callback.h"
#include "pagespeed/opt/http/mock_property_page.h"
#include "pagespeed/opt/http/property_cache.pb.h"
namespace net_instaweb {
namespace {
const size_t kMaxCacheSize = 200;
const char kCohortName1[] = "cohort1";
const char kCohortName2[] = "cohort2";
const char kUrl[] = "www.test.com/sample.html";
const char kParsableContent[] =
"value { name: 'prop1' value: 'value1' }";
const char kNonParsableContent[] = "random";
const char kOptionsSignatureHash[] = "hash";
const char kCacheKeySuffix[] = "CacheKeySuffix";
} // namespace
class CachePropertyStoreTest : public testing::Test {
public:
CachePropertyStoreTest()
: lru_cache_(kMaxCacheSize),
thread_system_(Platform::CreateThreadSystem()),
stats_(thread_system_.get()),
timer_(thread_system_->NewMutex(), MockTimer::kApr_5_2010_ms),
cache_property_store_(
"test/", &lru_cache_, &timer_, &stats_, thread_system_.get()),
property_cache_(&cache_property_store_,
&timer_,
&stats_,
thread_system_.get()),
num_callback_with_false_called_(0),
num_callback_with_true_called_(0),
cache_lookup_status_(false) {
PropertyCache::InitCohortStats(kCohortName1, &stats_);
PropertyStoreGetCallback::InitStats(&stats_);
cohort_ = property_cache_.AddCohort(kCohortName1);
cache_property_store_.AddCohort(kCohortName1);
cohort_list_.push_back(cohort_);
}
void SetUp() {
page_.reset(
new MockPropertyPage(
thread_system_.get(),
&property_cache_,
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix));
property_cache_.Read(page_.get());
}
void ResultCallback(bool result) {
cache_lookup_status_ = result;
if (result) {
++num_callback_with_true_called_;
} else {
++num_callback_with_false_called_;
}
}
bool ExecuteGet(PropertyPage* page) {
AbstractPropertyStoreGetCallback* callback = NULL;
cache_property_store_.Get(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort_list_,
page,
NewCallback(this, &CachePropertyStoreTest::ResultCallback),
&callback);
callback->DeleteWhenDone();
return cache_lookup_status_;
}
protected:
LRUCache lru_cache_;
scoped_ptr<ThreadSystem> thread_system_;
SimpleStats stats_;
MockTimer timer_;
CachePropertyStore cache_property_store_;
PropertyCache property_cache_;
const PropertyCache::Cohort* cohort_;
PropertyCache::CohortVector cohort_list_;
scoped_ptr<MockPropertyPage> page_;
int num_callback_with_false_called_;
int num_callback_with_true_called_;
bool cache_lookup_status_;
private:
DISALLOW_COPY_AND_ASSIGN(CachePropertyStoreTest);
};
TEST_F(CachePropertyStoreTest, TestNoResultAvailable) {
EXPECT_FALSE(ExecuteGet(page_.get()));
EXPECT_EQ(CacheInterface::kNotFound, page_->GetCacheState(cohort_));
EXPECT_EQ(1, num_callback_with_false_called_);
EXPECT_EQ(0, num_callback_with_true_called_);
}
TEST_F(CachePropertyStoreTest, TestResultAvailable) {
PropertyCacheValues values;
values.ParseFromString(kParsableContent);
cache_property_store_.Put(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort_,
&values,
NULL);
EXPECT_TRUE(ExecuteGet(page_.get()));
EXPECT_EQ(CacheInterface::kAvailable, page_->GetCacheState(cohort_));
EXPECT_EQ(0, num_callback_with_false_called_);
EXPECT_EQ(1, num_callback_with_true_called_);
}
TEST_F(CachePropertyStoreTest, TestResultAvailableButNonParsable) {
SharedString put_buffer(kNonParsableContent);
lru_cache_.Put(cache_property_store_.CacheKey(kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort_),
&put_buffer);
EXPECT_FALSE(ExecuteGet(page_.get()));
EXPECT_EQ(CacheInterface::kAvailable, page_->GetCacheState(cohort_));
EXPECT_EQ(1, num_callback_with_false_called_);
EXPECT_EQ(0, num_callback_with_true_called_);
}
TEST_F(CachePropertyStoreTest, TestMultipleCohorts) {
PropertyCache::InitCohortStats(kCohortName2, &stats_);
const PropertyCache::Cohort* cohort2 =
property_cache_.AddCohort(kCohortName2);
cache_property_store_.AddCohort(kCohortName2);
MockPropertyPage page(thread_system_.get(),
&property_cache_,
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix);
property_cache_.Read(&page);
PropertyCacheValues values;
values.ParseFromString(kParsableContent);
cohort_list_.push_back(cohort2);
lru_cache_.ClearStats();
EXPECT_FALSE(ExecuteGet(&page));
EXPECT_EQ(0, lru_cache_.num_hits());
EXPECT_EQ(2, lru_cache_.num_misses());
EXPECT_EQ(0, lru_cache_.num_inserts());
lru_cache_.ClearStats();
// Insert the value for cohort1.
cache_property_store_.Put(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort_,
&values,
NULL);
EXPECT_TRUE(ExecuteGet(&page));
EXPECT_EQ(1, lru_cache_.num_hits());
EXPECT_EQ(1, lru_cache_.num_misses());
EXPECT_EQ(1, lru_cache_.num_inserts());
lru_cache_.ClearStats();
// Insert the value for cohort2.
cache_property_store_.Put(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort2,
&values,
NULL);
EXPECT_TRUE(ExecuteGet(&page));
EXPECT_EQ(2, lru_cache_.num_hits());
EXPECT_EQ(0, lru_cache_.num_misses());
EXPECT_EQ(1, lru_cache_.num_inserts());
EXPECT_EQ(1, num_callback_with_false_called_);
EXPECT_EQ(2, num_callback_with_true_called_);
}
TEST_F(CachePropertyStoreTest, TestMultipleCacheBackends) {
// Create a second cache implementation.
LRUCache second_cache(kMaxCacheSize);
PropertyCache::InitCohortStats(kCohortName2, &stats_);
const PropertyCache::Cohort* cohort2 =
property_cache_.AddCohort(kCohortName2);
cache_property_store_.AddCohortWithCache(kCohortName2, &second_cache);
MockPropertyPage page(
thread_system_.get(),
&property_cache_,
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix);
property_cache_.Read(&page);
PropertyCacheValues values;
values.ParseFromString(kParsableContent);
lru_cache_.ClearStats();
second_cache.ClearStats();
// Insert the value for cohort1.
cache_property_store_.Put(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort_,
&values,
NULL);
// Insert the value for cohort2.
cache_property_store_.Put(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort2,
&values,
NULL);
cohort_list_.push_back(cohort2);
// Get the value for cohort1 and cohort2.
EXPECT_TRUE(ExecuteGet(&page));
EXPECT_EQ(CacheInterface::kAvailable, page.GetCacheState(cohort_));
EXPECT_EQ(CacheInterface::kAvailable, page.GetCacheState(cohort2));
EXPECT_EQ(1, lru_cache_.num_hits());
EXPECT_EQ(0, lru_cache_.num_misses());
EXPECT_EQ(1, lru_cache_.num_inserts());
EXPECT_EQ(1, second_cache.num_hits());
EXPECT_EQ(0, second_cache.num_misses());
EXPECT_EQ(1, second_cache.num_inserts());
EXPECT_EQ(0, num_callback_with_false_called_);
EXPECT_EQ(1, num_callback_with_true_called_);
}
TEST_F(CachePropertyStoreTest, TestPropertyCacheKeyMethod) {
GoogleString cache_key = cache_property_store_.CacheKey(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort_);
GoogleString expected = StrCat(
"test/",
kUrl, "_",
kOptionsSignatureHash,
kCacheKeySuffix, "@",
cohort_->name());
EXPECT_EQ(expected, cache_key);
}
TEST_F(CachePropertyStoreTest, TestPutHandlesNonNullCallback) {
PropertyCacheValues values;
values.ParseFromString(kParsableContent);
cache_property_store_.Put(
kUrl,
kOptionsSignatureHash,
kCacheKeySuffix,
cohort_,
&values,
NewCallback(this, &CachePropertyStoreTest::ResultCallback));
EXPECT_EQ(0, num_callback_with_false_called_);
EXPECT_EQ(1, num_callback_with_true_called_);
}
} // namespace net_instaweb