blob: 32e408c1cd3087c04b7ca92c6c3839d9590c04e1 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* 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.
*/
#define LOG_TAG "EGL_test"
//#define LOG_NDEBUG 0
#include <gtest/gtest.h>
#include <utils/Log.h>
#include <android-base/test_utils.h>
#include "egl_cache.h"
#include "MultifileBlobCache.h"
#include "egl_display.h"
#include <memory>
using namespace std::literals;
namespace android {
class EGLCacheTest : public ::testing::TestWithParam<egl_cache_t::EGLCacheMode> {
protected:
virtual void SetUp() {
// Terminate to clean up any previous cache in this process
mCache->terminate();
mTempFile.reset(new TemporaryFile());
mCache->setCacheFilename(&mTempFile->path[0]);
mCache->setCacheLimit(1024);
mCache->setCacheMode(mCacheMode);
}
virtual void TearDown() {
mCache->terminate();
mCache->setCacheFilename("");
mTempFile.reset(nullptr);
}
std::string getCachefileName();
egl_cache_t* mCache = egl_cache_t::get();
std::unique_ptr<TemporaryFile> mTempFile;
egl_cache_t::EGLCacheMode mCacheMode = GetParam();
};
TEST_P(EGLCacheTest, UninitializedCacheAlwaysMisses) {
uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee };
mCache->setBlob("abcd", 4, "efgh", 4);
ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
ASSERT_EQ(0xee, buf[2]);
ASSERT_EQ(0xee, buf[3]);
}
TEST_P(EGLCacheTest, InitializedCacheAlwaysHits) {
uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee };
mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
mCache->setBlob("abcd", 4, "efgh", 4);
ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
ASSERT_EQ('g', buf[2]);
ASSERT_EQ('h', buf[3]);
}
TEST_P(EGLCacheTest, TerminatedCacheAlwaysMisses) {
uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee };
mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
mCache->setBlob("abcd", 4, "efgh", 4);
mCache->terminate();
ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
ASSERT_EQ(0xee, buf[2]);
ASSERT_EQ(0xee, buf[3]);
}
TEST_P(EGLCacheTest, ReinitializedCacheContainsValues) {
uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee };
mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
mCache->setBlob("abcd", 4, "efgh", 4);
mCache->terminate();
mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
ASSERT_EQ('g', buf[2]);
ASSERT_EQ('h', buf[3]);
}
std::string EGLCacheTest::getCachefileName() {
// Return the monolithic filename unless we find the multifile dir
std::string cachePath = &mTempFile->path[0];
std::string multifileDirName = cachePath + ".multifile";
std::string cachefileName = "";
struct stat info;
if (stat(multifileDirName.c_str(), &info) == 0) {
// Ensure we only have one file to manage
int realFileCount = 0;
// We have a multifile dir. Return the only real file in it.
DIR* dir;
struct dirent* entry;
if ((dir = opendir(multifileDirName.c_str())) != nullptr) {
while ((entry = readdir(dir)) != nullptr) {
if (entry->d_name == "."s || entry->d_name == ".."s) {
continue;
}
cachefileName = multifileDirName + "/" + entry->d_name;
realFileCount++;
}
} else {
printf("Unable to open %s, error: %s\n", multifileDirName.c_str(), std::strerror(errno));
}
if (realFileCount != 1) {
// If there was more than one real file in the directory, this
// violates test assumptions
cachefileName = "";
}
} else {
printf("Unable to stat %s, error: %s\n", multifileDirName.c_str(), std::strerror(errno));
}
return cachefileName;
}
TEST_P(EGLCacheTest, ModifiedCacheMisses) {
// Skip if not in multifile mode
if (mCacheMode == egl_cache_t::EGLCacheMode::Monolithic) {
GTEST_SKIP() << "Skipping test designed for multifile";
}
uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee };
mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
mCache->setBlob("abcd", 4, "efgh", 4);
ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
ASSERT_EQ('g', buf[2]);
ASSERT_EQ('h', buf[3]);
// Ensure the cache file is written to disk
mCache->terminate();
// Depending on the cache mode, the file will be in different locations
std::string cachefileName = getCachefileName();
ASSERT_TRUE(cachefileName.length() > 0);
// Stomp on the beginning of the cache file, breaking the key match
const long stomp = 0xbadf00d;
FILE *file = fopen(cachefileName.c_str(), "w");
fprintf(file, "%ld", stomp);
fflush(file);
fclose(file);
// Ensure no cache hit
mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
uint8_t buf2[4] = { 0xee, 0xee, 0xee, 0xee };
// getBlob may return junk for required size, but should not return a cache hit
mCache->getBlob("abcd", 4, buf2, 4);
ASSERT_EQ(0xee, buf2[0]);
ASSERT_EQ(0xee, buf2[1]);
ASSERT_EQ(0xee, buf2[2]);
ASSERT_EQ(0xee, buf2[3]);
}
TEST_P(EGLCacheTest, TerminatedCacheBelowCacheLimit) {
uint8_t buf[4] = { 0xee, 0xee, 0xee, 0xee };
mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
mCache->setBlob("abcd", 4, "efgh", 4);
ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
ASSERT_EQ('g', buf[2]);
ASSERT_EQ('h', buf[3]);
mCache->setBlob("ijkl", 4, "mnop", 4);
ASSERT_EQ(4, mCache->getBlob("ijkl", 4, buf, 4));
ASSERT_EQ('m', buf[0]);
ASSERT_EQ('n', buf[1]);
ASSERT_EQ('o', buf[2]);
ASSERT_EQ('p', buf[3]);
mCache->setBlob("qrst", 4, "uvwx", 4);
ASSERT_EQ(4, mCache->getBlob("qrst", 4, buf, 4));
ASSERT_EQ('u', buf[0]);
ASSERT_EQ('v', buf[1]);
ASSERT_EQ('w', buf[2]);
ASSERT_EQ('x', buf[3]);
// Cache should contain both the key and the value
// So 8 bytes per entry, at least 24 bytes
ASSERT_GE(mCache->getCacheSize(), 24);
mCache->setCacheLimit(4);
mCache->terminate();
ASSERT_LE(mCache->getCacheSize(), 4);
}
INSTANTIATE_TEST_CASE_P(MonolithicCacheTests, EGLCacheTest, ::testing::Values(egl_cache_t::EGLCacheMode::Monolithic));
INSTANTIATE_TEST_CASE_P(MultifileCacheTests, EGLCacheTest, ::testing::Values(egl_cache_t::EGLCacheMode::Multifile));
}