b4b69e4f77
Summary: Our existing test notation is very similar to what is used in gtest. It makes it easy to adopt what is different. In this diff I modify existing [[ https://code.google.com/p/googletest/wiki/Primer#Test_Fixtures:_Using_the_Same_Data_Configuration_for_Multiple_Te | test fixture ]] classes to inherit from `testing::Test`. Also for unit tests that use fixture class, `TEST` is replaced with `TEST_F` as required in gtest. There are several custom `main` functions in our existing tests. To make this transition easier, I modify all `main` functions to fallow gtest notation. But eventually we can remove them and use implementation of `main` that gtest provides. ```lang=bash % cat ~/transform #!/bin/sh files=$(git ls-files '*test\.cc') for file in $files do if grep -q "rocksdb::test::RunAllTests()" $file then if grep -Eq '^class \w+Test {' $file then perl -pi -e 's/^(class \w+Test) {/${1}: public testing::Test {/g' $file perl -pi -e 's/^(TEST)/${1}_F/g' $file fi perl -pi -e 's/(int main.*\{)/${1}::testing::InitGoogleTest(&argc, argv);/g' $file perl -pi -e 's/rocksdb::test::RunAllTests/RUN_ALL_TESTS/g' $file fi done % sh ~/transform % make format ``` Second iteration of this diff contains only scripted changes. Third iteration contains manual changes to fix last errors and make it compilable. Test Plan: Build and notice no errors. ```lang=bash % USE_CLANG=1 make check -j55 ``` Tests are still testing. Reviewers: meyering, sdong, rven, igor Reviewed By: igor Subscribers: dhruba, leveldb Differential Revision: https://reviews.facebook.net/D35157
275 lines
9.3 KiB
C++
275 lines
9.3 KiB
C++
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
#include <set>
|
|
|
|
#include "rocksdb/utilities/spatial_db.h"
|
|
#include "util/testharness.h"
|
|
#include "util/testutil.h"
|
|
#include "util/random.h"
|
|
|
|
namespace rocksdb {
|
|
namespace spatial {
|
|
|
|
class SpatialDBTest : public testing::Test {
|
|
public:
|
|
SpatialDBTest() {
|
|
dbname_ = test::TmpDir() + "/spatial_db_test";
|
|
DestroyDB(dbname_, Options());
|
|
}
|
|
|
|
void AssertCursorResults(BoundingBox<double> bbox, const std::string& index,
|
|
const std::vector<std::string>& blobs) {
|
|
Cursor* c = db_->Query(ReadOptions(), bbox, index);
|
|
ASSERT_OK(c->status());
|
|
std::multiset<std::string> b;
|
|
for (auto x : blobs) {
|
|
b.insert(x);
|
|
}
|
|
|
|
while (c->Valid()) {
|
|
auto itr = b.find(c->blob().ToString());
|
|
ASSERT_TRUE(itr != b.end());
|
|
b.erase(itr);
|
|
c->Next();
|
|
}
|
|
ASSERT_EQ(b.size(), 0U);
|
|
ASSERT_OK(c->status());
|
|
delete c;
|
|
}
|
|
|
|
std::string dbname_;
|
|
SpatialDB* db_;
|
|
};
|
|
|
|
TEST_F(SpatialDBTest, FeatureSetSerializeTest) {
|
|
FeatureSet fs;
|
|
|
|
fs.Set("a", std::string("b"));
|
|
fs.Set("x", static_cast<uint64_t>(3));
|
|
fs.Set("y", false);
|
|
fs.Set("n", Variant()); // null
|
|
fs.Set("m", 3.25);
|
|
|
|
ASSERT_TRUE(fs.Find("w") == fs.end());
|
|
ASSERT_TRUE(fs.Find("x") != fs.end());
|
|
ASSERT_TRUE((*fs.Find("x")).second == Variant(static_cast<uint64_t>(3)));
|
|
ASSERT_TRUE((*fs.Find("y")).second != Variant(true));
|
|
std::set<std::string> keys({"a", "x", "y", "n", "m"});
|
|
for (const auto& x : fs) {
|
|
ASSERT_TRUE(keys.find(x.first) != keys.end());
|
|
keys.erase(x.first);
|
|
}
|
|
ASSERT_EQ(keys.size(), 0U);
|
|
|
|
std::string serialized;
|
|
fs.Serialize(&serialized);
|
|
|
|
FeatureSet deserialized;
|
|
ASSERT_TRUE(deserialized.Deserialize(serialized));
|
|
|
|
ASSERT_TRUE(deserialized.Contains("a"));
|
|
ASSERT_EQ(deserialized.Get("a").type(), Variant::kString);
|
|
ASSERT_EQ(deserialized.Get("a").get_string(), "b");
|
|
ASSERT_TRUE(deserialized.Contains("x"));
|
|
ASSERT_EQ(deserialized.Get("x").type(), Variant::kInt);
|
|
ASSERT_EQ(deserialized.Get("x").get_int(), static_cast<uint64_t>(3));
|
|
ASSERT_TRUE(deserialized.Contains("y"));
|
|
ASSERT_EQ(deserialized.Get("y").type(), Variant::kBool);
|
|
ASSERT_EQ(deserialized.Get("y").get_bool(), false);
|
|
ASSERT_TRUE(deserialized.Contains("n"));
|
|
ASSERT_EQ(deserialized.Get("n").type(), Variant::kNull);
|
|
ASSERT_TRUE(deserialized.Contains("m"));
|
|
ASSERT_EQ(deserialized.Get("m").type(), Variant::kDouble);
|
|
ASSERT_EQ(deserialized.Get("m").get_double(), 3.25);
|
|
|
|
// corrupted serialization
|
|
serialized = serialized.substr(0, serialized.size() - 3);
|
|
deserialized.Clear();
|
|
ASSERT_TRUE(!deserialized.Deserialize(serialized));
|
|
}
|
|
|
|
TEST_F(SpatialDBTest, TestNextID) {
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("simple", BoundingBox<double>(0, 0, 100, 100), 2)}));
|
|
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(5, 5, 10, 10),
|
|
"one", FeatureSet(), {"simple"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(10, 10, 15, 15),
|
|
"two", FeatureSet(), {"simple"}));
|
|
delete db_;
|
|
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(55, 55, 65, 65),
|
|
"three", FeatureSet(), {"simple"}));
|
|
delete db_;
|
|
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
AssertCursorResults(BoundingBox<double>(0, 0, 100, 100), "simple",
|
|
{"one", "two", "three"});
|
|
delete db_;
|
|
}
|
|
|
|
TEST_F(SpatialDBTest, FeatureSetTest) {
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("simple", BoundingBox<double>(0, 0, 100, 100), 2)}));
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
|
|
FeatureSet fs;
|
|
fs.Set("a", std::string("b"));
|
|
fs.Set("c", std::string("d"));
|
|
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(5, 5, 10, 10),
|
|
"one", fs, {"simple"}));
|
|
|
|
Cursor* c =
|
|
db_->Query(ReadOptions(), BoundingBox<double>(5, 5, 10, 10), "simple");
|
|
|
|
ASSERT_TRUE(c->Valid());
|
|
ASSERT_EQ(c->blob().compare("one"), 0);
|
|
FeatureSet returned = c->feature_set();
|
|
ASSERT_TRUE(returned.Contains("a"));
|
|
ASSERT_TRUE(!returned.Contains("b"));
|
|
ASSERT_TRUE(returned.Contains("c"));
|
|
ASSERT_EQ(returned.Get("a").type(), Variant::kString);
|
|
ASSERT_EQ(returned.Get("a").get_string(), "b");
|
|
ASSERT_EQ(returned.Get("c").type(), Variant::kString);
|
|
ASSERT_EQ(returned.Get("c").get_string(), "d");
|
|
|
|
c->Next();
|
|
ASSERT_TRUE(!c->Valid());
|
|
|
|
delete c;
|
|
delete db_;
|
|
}
|
|
|
|
TEST_F(SpatialDBTest, SimpleTest) {
|
|
// iter 0 -- not read only
|
|
// iter 1 -- read only
|
|
for (int iter = 0; iter < 2; ++iter) {
|
|
DestroyDB(dbname_, Options());
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("index", BoundingBox<double>(0, 0, 128, 128),
|
|
3)}));
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(33, 17, 63, 79),
|
|
"one", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(65, 65, 111, 111),
|
|
"two", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(1, 49, 127, 63),
|
|
"three", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(20, 100, 21, 101),
|
|
"four", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(81, 33, 127, 63),
|
|
"five", FeatureSet(), {"index"}));
|
|
ASSERT_OK(db_->Insert(WriteOptions(), BoundingBox<double>(1, 65, 47, 95),
|
|
"six", FeatureSet(), {"index"}));
|
|
|
|
if (iter == 1) {
|
|
delete db_;
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_, true));
|
|
}
|
|
|
|
AssertCursorResults(BoundingBox<double>(33, 17, 47, 31), "index", {"one"});
|
|
AssertCursorResults(BoundingBox<double>(17, 33, 79, 63), "index",
|
|
{"one", "three"});
|
|
AssertCursorResults(BoundingBox<double>(17, 81, 63, 111), "index",
|
|
{"four", "six"});
|
|
AssertCursorResults(BoundingBox<double>(85, 86, 85, 86), "index", {"two"});
|
|
AssertCursorResults(BoundingBox<double>(33, 1, 127, 111), "index",
|
|
{"one", "two", "three", "five", "six"});
|
|
// even though the bounding box doesn't intersect, we got "four" back
|
|
// because
|
|
// it's in the same tile
|
|
AssertCursorResults(BoundingBox<double>(18, 98, 19, 99), "index", {"four"});
|
|
AssertCursorResults(BoundingBox<double>(130, 130, 131, 131), "index", {});
|
|
AssertCursorResults(BoundingBox<double>(81, 17, 127, 31), "index", {});
|
|
AssertCursorResults(BoundingBox<double>(90, 50, 91, 51), "index",
|
|
{"three", "five"});
|
|
|
|
delete db_;
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
std::string RandomStr(Random* rnd) {
|
|
std::string r;
|
|
for (int k = 0; k < 10; ++k) {
|
|
r.push_back(rnd->Uniform(26) + 'a');
|
|
}
|
|
return r;
|
|
}
|
|
|
|
BoundingBox<int> RandomBoundingBox(int limit, Random* rnd, int max_size) {
|
|
BoundingBox<int> r;
|
|
r.min_x = rnd->Uniform(limit - 1);
|
|
r.min_y = rnd->Uniform(limit - 1);
|
|
r.max_x = r.min_x + rnd->Uniform(std::min(limit - 1 - r.min_x, max_size)) + 1;
|
|
r.max_y = r.min_y + rnd->Uniform(std::min(limit - 1 - r.min_y, max_size)) + 1;
|
|
return r;
|
|
}
|
|
|
|
BoundingBox<double> ScaleBB(BoundingBox<int> b, double step) {
|
|
return BoundingBox<double>(b.min_x * step + 1, b.min_y * step + 1,
|
|
(b.max_x + 1) * step - 1,
|
|
(b.max_y + 1) * step - 1);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_F(SpatialDBTest, RandomizedTest) {
|
|
Random rnd(301);
|
|
std::vector<std::pair<std::string, BoundingBox<int>>> elements;
|
|
|
|
BoundingBox<double> spatial_index_bounds(0, 0, (1LL << 32), (1LL << 32));
|
|
ASSERT_OK(SpatialDB::Create(
|
|
SpatialDBOptions(), dbname_,
|
|
{SpatialIndexOptions("index", spatial_index_bounds, 7)}));
|
|
ASSERT_OK(SpatialDB::Open(SpatialDBOptions(), dbname_, &db_));
|
|
double step = (1LL << 32) / (1 << 7);
|
|
|
|
for (int i = 0; i < 1000; ++i) {
|
|
std::string blob = RandomStr(&rnd);
|
|
BoundingBox<int> bbox = RandomBoundingBox(128, &rnd, 10);
|
|
ASSERT_OK(db_->Insert(WriteOptions(), ScaleBB(bbox, step), blob,
|
|
FeatureSet(), {"index"}));
|
|
elements.push_back(make_pair(blob, bbox));
|
|
}
|
|
|
|
// parallel
|
|
db_->Compact(2);
|
|
// serial
|
|
db_->Compact(1);
|
|
|
|
for (int i = 0; i < 1000; ++i) {
|
|
BoundingBox<int> int_bbox = RandomBoundingBox(128, &rnd, 10);
|
|
BoundingBox<double> double_bbox = ScaleBB(int_bbox, step);
|
|
std::vector<std::string> blobs;
|
|
for (auto e : elements) {
|
|
if (e.second.Intersects(int_bbox)) {
|
|
blobs.push_back(e.first);
|
|
}
|
|
}
|
|
AssertCursorResults(double_bbox, "index", blobs);
|
|
}
|
|
|
|
delete db_;
|
|
}
|
|
|
|
} // namespace spatial
|
|
} // namespace rocksdb
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|