blob: c4c937d2b1caa451d2b54d0ad4367527ed088238 [file] [log] [blame]
/*
* Copyright 2010 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: jmarantz@google.com (Joshua Marantz)
// Unit-test the threadsafe cache. Creates an LRU-cache first, and then
// wraps a thread-safe cache around that and a mutex
#include "pagespeed/kernel/cache/threadsafe_cache.h"
#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/shared_string.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/thread_system.h"
#include "pagespeed/kernel/cache/cache_interface.h"
#include "pagespeed/kernel/cache/cache_spammer.h"
#include "pagespeed/kernel/cache/cache_test_base.h"
#include "pagespeed/kernel/cache/lru_cache.h"
#include "pagespeed/kernel/util/platform.h"
namespace {
const int kMaxSize = 100;
const int kNumThreads = 4;
const int kNumIters = 10000;
const int kNumInserts = 10;
}
namespace net_instaweb {
class ThreadsafeCacheTest : public testing::Test {
protected:
ThreadsafeCacheTest()
: lru_cache_(new LRUCache(kMaxSize)),
thread_runtime_(Platform::CreateThreadSystem()),
threadsafe_cache_(lru_cache_.get(), thread_runtime_->NewMutex()) {
}
void TestHelper(bool expecting_evictions, bool do_deletes,
const char* value_pattern) {
CacheSpammer::RunTests(kNumThreads, kNumIters, kNumInserts,
expecting_evictions, do_deletes, value_pattern,
&threadsafe_cache_, thread_runtime_.get());
lru_cache_->SanityCheck();
}
scoped_ptr<LRUCache> lru_cache_;
scoped_ptr<ThreadSystem> thread_runtime_;
ThreadsafeCache threadsafe_cache_;
private:
DISALLOW_COPY_AND_ASSIGN(ThreadsafeCacheTest);
};
TEST_F(ThreadsafeCacheTest, BasicOperation) {
SharedString put_buffer("val");
threadsafe_cache_.Put("key", &put_buffer);
CacheTestBase::Callback callback;
threadsafe_cache_.Get("key", &callback);
EXPECT_TRUE(callback.called());
EXPECT_EQ(CacheInterface::kAvailable, callback.state());
EXPECT_EQ(GoogleString("val"), callback.value()->Value());
}
TEST_F(ThreadsafeCacheTest, SpamCacheNoEvictionsOrDeletions) {
// By writing 10 inserts, with 5 bytes of value "valu%d" plus 5 bytes
// of key, we should never evict anything. In this test the
// threads can each check that all their Gets succeed.
TestHelper(false, false, "valu");
}
TEST_F(ThreadsafeCacheTest, SpamCacheWithEvictions) {
// By writing 10 inserts, with 6 bytes of value "value%d" plus 5
// bytes of key, we may get evictions. In this test the threads
// ignores the return value from Get, but we ensure that the
// eviction logic in the cache is tested in a multi-threaded context.
TestHelper(true, false, "value");
}
TEST_F(ThreadsafeCacheTest, SpamCacheWithDeletions) {
// In this testcase, we expect no evictions, but we will be
// doing some deletions, so we do not require Gets to succeed.
TestHelper(false, true, "valu");
}
TEST_F(ThreadsafeCacheTest, SpamCacheWithDeletionsAndEvictions) {
// In this testcase, we expect evictions, and we will also be
// doing deletions.
TestHelper(true, true, "value");
}
TEST_F(ThreadsafeCacheTest, Backend) {
EXPECT_EQ(lru_cache_.get(), threadsafe_cache_.Backend());
}
} // namespace net_instaweb