2016-02-10 00:12:00 +01:00
|
|
|
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
2017-07-16 01:03:42 +02:00
|
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
|
|
// (found in the LICENSE.Apache file in the root directory).
|
2013-12-21 02:17:00 +01:00
|
|
|
//
|
2015-06-19 00:57:19 +02:00
|
|
|
#ifndef ROCKSDB_LITE
|
2013-12-21 02:17:00 +01:00
|
|
|
#include "utilities/geodb/geodb_impl.h"
|
|
|
|
|
|
|
|
#include <cctype>
|
|
|
|
#include "util/testharness.h"
|
|
|
|
|
|
|
|
namespace rocksdb {
|
|
|
|
|
2015-03-17 22:08:00 +01:00
|
|
|
class GeoDBTest : public testing::Test {
|
2013-12-21 02:17:00 +01:00
|
|
|
public:
|
|
|
|
static const std::string kDefaultDbName;
|
|
|
|
static Options options;
|
|
|
|
DB* db;
|
|
|
|
GeoDB* geodb;
|
|
|
|
|
|
|
|
GeoDBTest() {
|
|
|
|
GeoDBOptions geodb_options;
|
rocksdb: Replace ASSERT* with EXPECT* in functions that does not return void value
Summary:
gtest does not use exceptions to fail a unit test by design, and `ASSERT*`s are implemented using `return`. As a consequence we cannot use `ASSERT*` in a function that does not return `void` value ([[ https://code.google.com/p/googletest/wiki/AdvancedGuide#Assertion_Placement | 1]]), and have to fix our existing code. This diff does this in a generic way, with no manual changes.
In order to detect all existing `ASSERT*` that are used in functions that doesn't return void value, I change the code to generate compile errors for such cases.
In `util/testharness.h` I defined `EXPECT*` assertions, the same way as `ASSERT*`, and redefined `ASSERT*` to return `void`. Then executed:
```lang=bash
% USE_CLANG=1 make all -j55 -k 2> build.log
% perl -naF: -e 'print "-- -number=".$F[1]." ".$F[0]."\n" if /: error:/' \
build.log | xargs -L 1 perl -spi -e 's/ASSERT/EXPECT/g if $. == $number'
% make format
```
After that I reverted back change to `ASSERT*` in `util/testharness.h`. But preserved introduced `EXPECT*`, which is the same as `ASSERT*`. This will be deleted once switched to gtest.
This diff is independent and contains manual changes only in `util/testharness.h`.
Test Plan:
Make sure all tests are passing.
```lang=bash
% USE_CLANG=1 make check
```
Reviewers: igor, lgalanis, sdong, yufei.zhu, rven, meyering
Reviewed By: meyering
Subscribers: dhruba, leveldb
Differential Revision: https://reviews.facebook.net/D33333
2015-03-17 04:52:32 +01:00
|
|
|
EXPECT_OK(DestroyDB(kDefaultDbName, options));
|
2013-12-21 02:17:00 +01:00
|
|
|
options.create_if_missing = true;
|
|
|
|
Status status = DB::Open(options, kDefaultDbName, &db);
|
|
|
|
geodb = new GeoDBImpl(db, geodb_options);
|
|
|
|
}
|
|
|
|
|
|
|
|
~GeoDBTest() {
|
|
|
|
delete geodb;
|
|
|
|
}
|
|
|
|
|
|
|
|
GeoDB* getdb() {
|
|
|
|
return geodb;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-22 02:22:49 +02:00
|
|
|
const std::string GeoDBTest::kDefaultDbName = test::TmpDir() + "/geodb_test";
|
2013-12-21 02:17:00 +01:00
|
|
|
Options GeoDBTest::options = Options();
|
|
|
|
|
|
|
|
// Insert, Get and Remove
|
2015-03-17 22:08:00 +01:00
|
|
|
TEST_F(GeoDBTest, SimpleTest) {
|
2013-12-21 02:17:00 +01:00
|
|
|
GeoPosition pos1(100, 101);
|
|
|
|
std::string id1("id1");
|
|
|
|
std::string value1("value1");
|
|
|
|
|
|
|
|
// insert first object into database
|
|
|
|
GeoObject obj1(pos1, id1, value1);
|
|
|
|
Status status = getdb()->Insert(obj1);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// insert second object into database
|
|
|
|
GeoPosition pos2(200, 201);
|
|
|
|
std::string id2("id2");
|
|
|
|
std::string value2 = "value2";
|
|
|
|
GeoObject obj2(pos2, id2, value2);
|
|
|
|
status = getdb()->Insert(obj2);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// retrieve first object using position
|
|
|
|
std::string value;
|
|
|
|
status = getdb()->GetByPosition(pos1, Slice(id1), &value);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
ASSERT_EQ(value, value1);
|
|
|
|
|
|
|
|
// retrieve first object using id
|
|
|
|
GeoObject obj;
|
|
|
|
status = getdb()->GetById(Slice(id1), &obj);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
ASSERT_EQ(obj.position.latitude, 100);
|
|
|
|
ASSERT_EQ(obj.position.longitude, 101);
|
|
|
|
ASSERT_EQ(obj.id.compare(id1), 0);
|
|
|
|
ASSERT_EQ(obj.value, value1);
|
|
|
|
|
|
|
|
// delete first object
|
|
|
|
status = getdb()->Remove(Slice(id1));
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
status = getdb()->GetByPosition(pos1, Slice(id1), &value);
|
|
|
|
ASSERT_TRUE(status.IsNotFound());
|
|
|
|
status = getdb()->GetById(id1, &obj);
|
|
|
|
ASSERT_TRUE(status.IsNotFound());
|
|
|
|
|
|
|
|
// check that we can still find second object
|
|
|
|
status = getdb()->GetByPosition(pos2, id2, &value);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
ASSERT_EQ(value, value2);
|
|
|
|
status = getdb()->GetById(id2, &obj);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search.
|
|
|
|
// Verify distances via http://www.stevemorse.org/nearest/distance.php
|
2015-03-17 22:08:00 +01:00
|
|
|
TEST_F(GeoDBTest, Search) {
|
2013-12-21 02:17:00 +01:00
|
|
|
GeoPosition pos1(45, 45);
|
|
|
|
std::string id1("mid1");
|
|
|
|
std::string value1 = "midvalue1";
|
|
|
|
|
|
|
|
// insert object at 45 degree latitude
|
|
|
|
GeoObject obj1(pos1, id1, value1);
|
|
|
|
Status status = getdb()->Insert(obj1);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// search all objects centered at 46 degree latitude with
|
|
|
|
// a radius of 200 kilometers. We should find the one object that
|
|
|
|
// we inserted earlier.
|
2015-11-05 22:30:51 +01:00
|
|
|
GeoIterator* iter1 = getdb()->SearchRadial(GeoPosition(46, 46), 200000);
|
2013-12-21 02:17:00 +01:00
|
|
|
ASSERT_TRUE(status.ok());
|
2015-11-05 22:30:51 +01:00
|
|
|
ASSERT_EQ(iter1->geo_object().value, "midvalue1");
|
2015-11-05 05:10:16 +01:00
|
|
|
uint32_t size = 0;
|
2015-11-05 22:30:51 +01:00
|
|
|
while (iter1->Valid()) {
|
2018-05-15 08:54:06 +02:00
|
|
|
GeoObject obj;
|
|
|
|
status = getdb()->GetById(Slice(id1), &obj);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
ASSERT_EQ(iter1->geo_object().position.latitude, pos1.latitude);
|
|
|
|
ASSERT_EQ(iter1->geo_object().position.longitude, pos1.longitude);
|
|
|
|
ASSERT_EQ(iter1->geo_object().id.compare(id1), 0);
|
|
|
|
ASSERT_EQ(iter1->geo_object().value, value1);
|
|
|
|
|
2015-11-02 22:49:13 +01:00
|
|
|
size++;
|
2015-11-05 22:30:51 +01:00
|
|
|
iter1->Next();
|
2018-05-15 08:54:06 +02:00
|
|
|
ASSERT_TRUE(!iter1->Valid());
|
2015-11-02 22:49:13 +01:00
|
|
|
}
|
|
|
|
ASSERT_EQ(size, 1U);
|
2015-11-05 22:30:51 +01:00
|
|
|
delete iter1;
|
2013-12-21 02:17:00 +01:00
|
|
|
|
|
|
|
// search all objects centered at 46 degree latitude with
|
|
|
|
// a radius of 2 kilometers. There should be none.
|
2015-11-05 22:30:51 +01:00
|
|
|
GeoIterator* iter2 = getdb()->SearchRadial(GeoPosition(46, 46), 2);
|
2013-12-21 02:17:00 +01:00
|
|
|
ASSERT_TRUE(status.ok());
|
2015-11-05 22:30:51 +01:00
|
|
|
ASSERT_FALSE(iter2->Valid());
|
|
|
|
delete iter2;
|
2013-12-21 02:17:00 +01:00
|
|
|
}
|
|
|
|
|
2018-05-15 08:54:06 +02:00
|
|
|
TEST_F(GeoDBTest, DifferentPosInSameQuadkey) {
|
|
|
|
// insert obj1 into database
|
|
|
|
GeoPosition pos1(40.00001, 116.00001);
|
|
|
|
std::string id1("12");
|
|
|
|
std::string value1("value1");
|
|
|
|
|
|
|
|
GeoObject obj1(pos1, id1, value1);
|
|
|
|
Status status = getdb()->Insert(obj1);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// insert obj2 into database
|
|
|
|
GeoPosition pos2(40.00002, 116.00002);
|
|
|
|
std::string id2("123");
|
|
|
|
std::string value2 = "value2";
|
|
|
|
|
|
|
|
GeoObject obj2(pos2, id2, value2);
|
|
|
|
status = getdb()->Insert(obj2);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// get obj1's quadkey
|
|
|
|
ReadOptions opt;
|
|
|
|
PinnableSlice quadkey1;
|
|
|
|
status = getdb()->Get(opt, getdb()->DefaultColumnFamily(), "k:" + id1, &quadkey1);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// get obj2's quadkey
|
|
|
|
PinnableSlice quadkey2;
|
|
|
|
status = getdb()->Get(opt, getdb()->DefaultColumnFamily(), "k:" + id2, &quadkey2);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
|
|
|
|
// obj1 and obj2 have the same quadkey
|
|
|
|
ASSERT_EQ(quadkey1, quadkey2);
|
|
|
|
|
|
|
|
// get obj1 by id, and check value
|
|
|
|
GeoObject obj;
|
|
|
|
status = getdb()->GetById(Slice(id1), &obj);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
ASSERT_EQ(obj.position.latitude, pos1.latitude);
|
|
|
|
ASSERT_EQ(obj.position.longitude, pos1.longitude);
|
|
|
|
ASSERT_EQ(obj.id.compare(id1), 0);
|
|
|
|
ASSERT_EQ(obj.value, value1);
|
|
|
|
|
|
|
|
// get obj2 by id, and check value
|
|
|
|
status = getdb()->GetById(Slice(id2), &obj);
|
|
|
|
ASSERT_TRUE(status.ok());
|
|
|
|
ASSERT_EQ(obj.position.latitude, pos2.latitude);
|
|
|
|
ASSERT_EQ(obj.position.longitude, pos2.longitude);
|
|
|
|
ASSERT_EQ(obj.id.compare(id2), 0);
|
|
|
|
ASSERT_EQ(obj.value, value2);
|
|
|
|
}
|
|
|
|
|
2013-12-21 02:17:00 +01:00
|
|
|
} // namespace rocksdb
|
|
|
|
|
|
|
|
int main(int argc, char* argv[]) {
|
2015-03-17 22:08:00 +01:00
|
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
return RUN_ALL_TESTS();
|
2013-12-21 02:17:00 +01:00
|
|
|
}
|
2015-06-19 00:57:19 +02:00
|
|
|
#else
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
fprintf(stderr, "SKIPPED\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // !ROCKSDB_LITE
|