Skip to content
Snippets Groups Projects
Commit 0e7e84b9 authored by dutor's avatar dutor Committed by Sherman The Tank
Browse files

Refactor the source tree (#41)

parent 4768613e
No related branches found
No related tags found
No related merge requests found
Showing
with 1396 additions and 0 deletions
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_TRAVERSEEXECUTOR_H_
#define GRAPH_TRAVERSEEXECUTOR_H_
#include "base/Base.h"
#include "graph/Executor.h"
namespace nebula {
namespace graph {
class ResultSchema final {
public:
struct Column {
std::string name_;
// TODO(dutor) type
};
void addColumn(std::string name) {
columns_.emplace_back();
columns_.back().name_ = std::move(name);
}
std::string toString() const {
std::string buf;
buf.reserve(256);
for (auto &column : columns_) {
if (column.name_.empty()) {
buf += "NULL";
} else {
buf += column.name_;
}
buf += "\t";
}
if (!buf.empty()) {
buf.resize(buf.size() - 1);
}
return buf;
}
private:
std::vector<Column> columns_;
};
class TraverseExecutor : public Executor {
public:
TraverseExecutor(ExecutionContext *ectx) : Executor(ectx) {
}
using TraverseRecord = std::vector<VariantType>;
using TraverseRecords = std::vector<TraverseRecord>;
using OnResult = std::function<void(TraverseRecords)>;
virtual void feedResult(TraverseRecords records) = 0;
/**
* `onResult_' must be set except for the right most executor
* inside the chain of pipeline.
*
* For any TraverseExecutor, if `onResult_' is set, it means that
* some other executor depends on its execution result. Otherwise,
* it means that this executor is the right most one, whose results must
* be cached during its execution and are to be used to fill `ExecutionResponse'
* upon `setupResponse()'s invoke.
*/
void setOnResult(OnResult onResult) {
onResult_ = std::move(onResult);
}
virtual ResultSchema* resultSchema() const {
return resultSchema_.get();
}
virtual void setInputResultSchema(ResultSchema *schema) {
inputResultSchema_ = schema;
}
protected:
std::unique_ptr<TraverseExecutor> makeTraverseExecutor(Sentence *sentence);
protected:
OnResult onResult_;
std::unique_ptr<ResultSchema> resultSchema_;
ResultSchema *inputResultSchema_{nullptr};
};
} // namespace graph
} // namespace nebula
#endif // GRAPH_TRAVERSEEXECUTOR_H_
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/UseExecutor.h"
namespace nebula {
namespace graph {
UseExecutor::UseExecutor(Sentence *sentence, ExecutionContext *ectx) : Executor(ectx) {
sentence_ = static_cast<UseSentence*>(sentence);
}
Status UseExecutor::prepare() {
return Status::OK();
}
void UseExecutor::execute() {
auto *session = ectx()->rctx()->session();
// TODO(dutor) Check space's validness and map to type of integer
session->setSpace(sentence_->space());
FLOG_INFO("Graph space switched to `%s'", sentence_->space().c_str());
onFinish_();
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_USEEXECUTOR_H_
#define GRAPH_USEEXECUTOR_H_
#include "base/Base.h"
#include "graph/Executor.h"
namespace nebula {
namespace graph {
class UseExecutor final : public Executor {
public:
UseExecutor(Sentence *sentence, ExecutionContext *ectx);
const char* name() const override {
return "UseExecutor";
}
Status VE_MUST_USE_RESULT prepare() override;
void execute() override;
private:
UseSentence *sentence_{nullptr};
};
} // namespace graph
} // namespace nebula
#endif // GRAPH_USEEXECUTOR_H_
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/mock/EdgeSchema.h"
namespace nebula {
namespace graph {
void EdgeSchema::addProperty(std::string name, ColumnType type) {
properties_.addProperty(std::move(name), type);
}
const PropertyItem* EdgeSchema::getProperty(const std::string &name) {
return properties_.getProperty(name);
}
std::string EdgeSchema::toString() const {
return folly::stringPrintf("%s[%u] %s[%u]->%s[%u] %s",
name_.c_str(), id_,
srcTag_.c_str(), srcId_,
dstTag_.c_str(), dstId_,
properties_.toString().c_str());
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_EDGESCHEMA_H_
#define GRAPH_EDGESCHEMA_H_
#include "base/Base.h"
#include "graph/mock/PropertiesSchema.h"
namespace nebula {
namespace graph {
class EdgeSchema final {
public:
uint32_t id() const {
return id_;
}
void setId(uint32_t id) {
id_ = id;
}
const std::string& name() const {
return name_;
}
void setName(std::string name) {
name_ = std::move(name);
}
const std::string& srcTag() const {
return srcTag_;
}
void setSrcTag(std::string tag) {
srcTag_ = tag;
}
const std::string& dstTag() const {
return dstTag_;
}
void setDstTag(std::string tag) {
dstTag_ = tag;
}
uint32_t srcId() const {
return srcId_;
}
void setSrcId(uint32_t id) {
srcId_ = id;
}
uint32_t dstId() const {
return dstId_;
}
void setDstId(uint32_t id) {
dstId_ = id;
}
void addProperty(std::string name, ColumnType type);
const PropertyItem* getProperty(const std::string &name);
const PropertiesSchema* getPropertiesSchema() const {
return &properties_;
}
std::string toString() const;
private:
uint32_t id_{0};
uint32_t srcId_{0};
uint32_t dstId_{0};
std::string name_;
std::string srcTag_;
std::string dstTag_;
PropertiesSchema properties_;
};
} // namespace graph
} // namespace nebula
#endif // GRAPH_EDGESCHEMA_H_
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/mock/PropertiesSchema.h"
namespace nebula {
namespace graph {
void PropertiesSchema::addProperty(std::string name, ColumnType type) {
auto index = properties_.size();
properties_.emplace_back();
auto &item = properties_.back();
item.index_ = index;
item.name_ = std::move(name);
item.type_ = type;
mapping_[name] = &item;
}
const PropertyItem* PropertiesSchema::getProperty(const std::string &name) const {
auto iter = mapping_.find(name);
if (iter != mapping_.end()) {
return nullptr;
}
return iter->second;
}
const std::vector<PropertyItem>& PropertiesSchema::getItems() const {
return properties_;
}
std::string PropertiesSchema::toString() const {
std::string buf;
for (auto &item : properties_) {
buf += item.name_;
buf += "[";
buf += std::to_string(item.index_);
buf += "] ";
buf += columnTypeToString(item.type_);
buf += ",";
}
if (!buf.empty()) {
buf.resize(buf.size() - 1);
}
return buf;
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_PROPERTIESSCHEMA_H_
#define GRAPH_PROPERTIESSCHEMA_H_
#include "base/Base.h"
#include "parser/Expressions.h"
namespace nebula {
namespace graph {
struct PropertyItem {
uint32_t index_{0};
std::string name_;
ColumnType type_;
};
class PropertiesSchema final {
public:
void addProperty(std::string name, ColumnType type);
const PropertyItem* getProperty(const std::string &name) const;
const std::vector<PropertyItem>& getItems() const;
std::string toString() const;
private:
using MappingType = std::unordered_map<std::string, const PropertyItem*>;
std::vector<PropertyItem> properties_;
MappingType mapping_;
};
} // namespace graph
} // namespace nebula
#endif // GRAPH_PROPERTIESSCHEMA_H_
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/mock/SchemaManager.h"
namespace nebula {
namespace graph {
void SchemaManager::addEdgeSchema(const std::string &name,
const std::string &src,
const std::string &dst,
const std::vector<ColumnSpecification*> &specs) {
// TODO(dutor) check existence of src & dst tag
auto &schema = edges_[name];
schema.setId(nextEdgeId_++);
schema.setName(name);
schema.setSrcTag(src);
schema.setDstTag(dst);
schema.setSrcId(tags_[src].id());
schema.setDstId(tags_[dst].id());
for (auto *spec : specs) {
schema.addProperty(*spec->name(), spec->type());
}
}
void SchemaManager::addTagSchema(const std::string &name,
const std::vector<ColumnSpecification*> &specs) {
auto &schema = tags_[name];
schema.setId(nextTagId_++);
schema.setName(name);
for (auto *spec : specs) {
schema.addProperty(*spec->name(), spec->type());
}
}
const EdgeSchema* SchemaManager::getEdgeSchema(const std::string &name) {
auto iter = edges_.find(name);
if (iter == edges_.end()) {
return nullptr;
}
return &iter->second;
}
const TagSchema* SchemaManager::getTagSchema(const std::string &name) {
auto iter = tags_.find(name);
if (iter == tags_.end()) {
return nullptr;
}
return &iter->second;
}
void SchemaManager::print() const {
for (auto &entry : edges_) {
FLOG_INFO("Edge `%s': \n%s", entry.first.c_str(), entry.second.toString().c_str());
}
for (auto &entry : tags_) {
FLOG_INFO("Tag `%s': \n%s", entry.first.c_str(), entry.second.toString().c_str());
}
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_SCHEMAMANAGER_H_
#define GRAPH_SCHEMAMANAGER_H_
#include "base/Base.h"
#include "graph/mock/EdgeSchema.h"
#include "graph/mock/TagSchema.h"
#include "parser/MaintainSentences.h"
namespace nebula {
namespace graph {
class SchemaManager final {
public:
void addEdgeSchema(const std::string &name,
const std::string &src,
const std::string &dst,
const std::vector<ColumnSpecification*> &specs);
void addTagSchema(const std::string &name,
const std::vector<ColumnSpecification*> &specs);
const EdgeSchema* getEdgeSchema(const std::string &name);
const TagSchema* getTagSchema(const std::string &name);
void print() const;
private:
uint32_t nextEdgeId_{0};
uint32_t nextTagId_{0};
std::unordered_map<std::string, EdgeSchema> edges_;
std::unordered_map<std::string, TagSchema> tags_;
};
} // namespace graph
} // namespace nebula
#endif // GRAPH_SCHEMAMANAGER_H_
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/mock/StorageService.h"
namespace nebula {
namespace graph {
StorageService::StorageService(SchemaManager *sm) {
pool_ = std::make_unique<thread::GenericThreadPool>();
pool_->start(4, "storage-svc");
sm_ = sm;
}
folly::SemiFuture<Status>
StorageService::addTag(const std::string *tag,
int64_t id,
const std::vector<std::string*> &names,
const std::vector<VariantType> &values) {
auto task = [this, tag, id, names, values] () -> Status {
auto *schema = sm_->getTagSchema(*tag);
if (schema == nullptr) {
return Status::Error("Tag `%s' not defined", tag->c_str());
}
TagKey key;
key.id_ = id;
key.type_ = schema->id();
auto &props = tags_[key];
for (auto i = 0u; i < names.size(); i++) {
props[*names[i]] = values[i];
}
return Status::OK();
};
return pool_->addTask(std::move(task));
}
folly::SemiFuture<Status>
StorageService::addEdge(const std::string *edge,
int64_t srcid, int64_t dstid,
const std::vector<std::string*> &names,
const std::vector<VariantType> &values) {
auto task = [this, edge, srcid, dstid, names, values] () -> Status {
auto *schema = sm_->getEdgeSchema(*edge);
if (schema == nullptr) {
return Status::Error("Edge `%s' not defined", edge->c_str());
}
EdgeKey key;
key.srcid_ = srcid;
key.dstid_ = dstid;
key.type_ = schema->id();
auto &props = edges_[key];
for (auto i = 0u; i < names.size(); i++) {
props[*names[i]] = values[i];
}
return Status::OK();
};
return pool_->addTask(std::move(task));
}
folly::SemiFuture<StorageService::OutBoundResult>
StorageService::getOutBound(const std::vector<int64_t> &ids,
const std::string *edge,
const std::vector<std::string> &eprops,
const std::vector<std::string> &vprops) {
auto task = [this, ids, edge, eprops, vprops] () -> OutBoundResult {
OutBoundResult result;
auto *schema = sm_->getEdgeSchema(*edge);
if (schema == nullptr) {
return Status::Error("Edge `%s' not defined", edge->c_str());
}
//storage::cpp2::QueryResponse resp;
for (auto id : ids) {
EdgeKey start, end;
start.srcid_ = id;
start.type_ = schema->id();
start.dstid_ = -1;
end.srcid_ = id;
end.type_ = start.type_ + 1;
end.dstid_ = -1;
auto left = edges_.lower_bound(start);
auto right = edges_.lower_bound(end);
for (auto iter = left; iter != right; ++iter) {
if (iter->first.srcid_ != id) {
break;
}
if (iter->first.type_ != start.type_) {
break;
}
//auto &properties = iter->second;
FLOG_INFO("%ld -%s-> %ld", id, edge->c_str(), iter->first.dstid_);
}
}
return result;
};
return pool_->addTask(std::move(task));
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_MOCK_STORAGESERVICE_H_
#define GRAPH_MOCK_STORAGESERVICE_H_
#include "base/Base.h"
#include "base/Status.h"
#include "base/StatusOr.h"
#include "gen-cpp2/StorageService.h"
#include "thread/GenericThreadPool.h"
#include "graph/mock/SchemaManager.h"
namespace nebula {
namespace graph {
class StorageService {
public:
StorageService(SchemaManager *sm);
folly::SemiFuture<Status> addTag(const std::string *tag,
int64_t id,
const std::vector<std::string*> &names,
const std::vector<VariantType> &values);
folly::SemiFuture<Status> addEdge(const std::string *edge,
int64_t srcid, int64_t dstid,
const std::vector<std::string*> &names,
const std::vector<VariantType> &values);
using OutBoundResult = StatusOr<storage::cpp2::QueryResponse>;
folly::SemiFuture<OutBoundResult> getOutBound(const std::vector<int64_t> &ids,
const std::string *edge,
const std::vector<std::string> &eprops,
const std::vector<std::string> &vprops);
private:
struct TagKey {
int64_t id_{0};
int64_t type_{0};
};
struct EdgeKey {
int64_t srcid_{0};
int64_t dstid_{0};
int32_t type_{0};
};
struct TagLess {
bool operator()(const TagKey &lhs, const TagKey &rhs) const {
if (lhs.id_ != rhs.id_) {
return lhs.id_ < rhs.id_;
}
return lhs.type_ < rhs.type_;
}
};
struct EdgeLess {
bool operator()(const EdgeKey &lhs, const EdgeKey &rhs) const {
if (lhs.srcid_ != rhs.srcid_) {
return lhs.srcid_ < rhs.dstid_;
}
if (lhs.type_ != rhs.type_) {
return lhs.type_ < rhs.type_;
}
return lhs.dstid_ < rhs.dstid_;
}
};
using PropertiesType = std::unordered_map<std::string, VariantType>;
using TagsType = std::map<TagKey, PropertiesType, TagLess>;
using EdgesType = std::map<EdgeKey, PropertiesType, EdgeLess>;
private:
TagsType tags_;
EdgesType edges_;
std::unique_ptr<thread::GenericThreadPool> pool_;
SchemaManager *sm_;
};
} // namespace graph
} // namespace nebula
#endif
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/mock/TagSchema.h"
namespace nebula {
namespace graph {
void TagSchema::addProperty(std::string name, ColumnType type) {
properties_.addProperty(std::move(name), type);
}
const PropertyItem* TagSchema::getProperty(const std::string &name) const {
return properties_.getProperty(name);
}
std::string TagSchema::toString() const {
return folly::stringPrintf("%s[%u] %s",
name_.c_str(), id_, properties_.toString().c_str());
}
const PropertiesSchema* TagSchema::getPropertiesSchema() const {
return &properties_;
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_TAGSCHEMA_H_
#define GRAPH_TAGSCHEMA_H_
#include "base/Base.h"
#include "graph/mock/PropertiesSchema.h"
namespace nebula {
namespace graph {
class TagSchema final {
public:
uint32_t id() const {
return id_;
}
void setId(uint32_t id) {
id_ = id;
}
const std::string &name() const {
return name_;
}
void setName(std::string name) {
name_ = std::move(name);
}
void addProperty(std::string name, ColumnType type);
const PropertyItem* getProperty(const std::string &name) const;
const PropertiesSchema* getPropertiesSchema() const;
std::string toString() const;
private:
uint32_t id_{0};
std::string name_;
PropertiesSchema properties_;
};
} // namespace graph
} // namespace nebula
#endif // GRAPH_TAGSCHEMA_H_
add_executable(
session_manager_test
SessionManagerTest.cpp
$<TARGET_OBJECTS:graph_obj>
$<TARGET_OBJECTS:base_obj>
$<TARGET_OBJECTS:graph_thrift_obj>
$<TARGET_OBJECTS:time_obj>
$<TARGET_OBJECTS:fs_obj>
$<TARGET_OBJECTS:thread_obj>
$<TARGET_OBJECTS:parser_obj>
)
target_link_libraries(
session_manager_test
${THRIFT_LIBRARIES}
wangle
folly
boost_system
boost_context
${OPENSSL_LIBRARIES}
${KRB5_LIBRARIES}
gtest
gtest_main
glog
gflags
event
${COMPRESSION_LIBRARIES}
resolv
double-conversion
dl
-pthread
)
add_test(NAME session_manager_test COMMAND session_manager_test)
add_executable(
query_engine_test
TestMain.cpp
TestEnv.cpp
TestBase.cpp
DefineSchemaTest.cpp
$<TARGET_OBJECTS:graph_obj>
$<TARGET_OBJECTS:client_cpp_obj>
$<TARGET_OBJECTS:base_obj>
$<TARGET_OBJECTS:graph_thrift_obj>
$<TARGET_OBJECTS:time_obj>
$<TARGET_OBJECTS:fs_obj>
$<TARGET_OBJECTS:thread_obj>
$<TARGET_OBJECTS:parser_obj>
)
target_link_libraries(
query_engine_test
${THRIFT_LIBRARIES}
wangle
folly
boost_system
boost_context
${OPENSSL_LIBRARIES}
${KRB5_LIBRARIES}
gtest
gtest_main
glog
gflags
event
${COMPRESSION_LIBRARIES}
resolv
double-conversion
dl
-pthread
)
add_test(NAME query_engine_test COMMAND query_engine_test)
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/test/TestEnv.h"
#include "graph/test/TestBase.h"
namespace nebula {
namespace graph {
class DefineSchemaTest : public TestBase {
protected:
void SetUp() override {
TestBase::SetUp();
// ...
}
void TearDown() override {
// ...
TestBase::TearDown();
}
};
TEST_F(DefineSchemaTest, Simple) {
auto client = gEnv->getClient();
ASSERT_NE(nullptr, client);
{
cpp2::ExecutionResponse resp;
std::string query = "DEFINE TAG person(name string, email string, age int16, gender string)";
auto code = client->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
}
{
cpp2::ExecutionResponse resp;
std::string query = "DESCRIBE TAG person";
client->execute(query, resp);
std::vector<uniform_tuple_t<std::string, 2>> expected{
{"email", "string"},
{"name", "string"},
{"age", "int16"},
{"gender", "string"},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
std::string query = "DEFINE TAG account(id int64, balance double)";
auto code = client->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
}
{
cpp2::ExecutionResponse resp;
std::string query = "DESCRIBE TAG account";
client->execute(query, resp);
std::vector<uniform_tuple_t<std::string, 2>> expected{
{"id", "int64"},
{"balance", "double"},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
std::string query = "DEFINE EDGE friend_of person -> person()";
auto code = client->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
}
{
cpp2::ExecutionResponse resp;
std::string query = "DESCRIBE EDGE friend_of";
client->execute(query, resp);
std::vector<uniform_tuple_t<std::string, 2>> expected{
{"person", "person"},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
std::string query = "DEFINE EDGE transfer "
"account -> account(amount double, time int64)";
auto code = client->execute(query, resp);
ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
}
{
cpp2::ExecutionResponse resp;
std::string query = "DESCRIBE EDGE transfer";
client->execute(query, resp);
std::vector<uniform_tuple_t<std::string, 4>> expected{
{"account", "account", "amount", "double"},
{"account", "account", "time", "int64"},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
// compound sentences
{
cpp2::ExecutionResponse resp;
std::string query = "DESCRIBE EDGE friend_of; DESCRIBE EDGE transfer";
client->execute(query, resp);
std::vector<uniform_tuple_t<std::string, 4>> expected{
{"account", "account", "amount", "double"},
{"account", "account", "time", "int64"},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
{
cpp2::ExecutionResponse resp;
std::string query = "DESCRIBE EDGE transfer; DESCRIBE EDGE friend_of";
client->execute(query, resp);
std::vector<uniform_tuple_t<std::string, 2>> expected{
{"person", "person"},
};
ASSERT_TRUE(verifyResult(resp, expected));
}
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include <gtest/gtest.h>
#include "graph/SessionManager.h"
#include "graph/GraphFlags.h"
#include "thread/GenericWorker.h"
using nebula::thread::GenericWorker;
namespace nebula {
namespace graph {
TEST(SessionManager, Basic) {
auto sm = std::make_shared<SessionManager>();
auto session = sm->createSession();
ASSERT_NE(nullptr, session);
ASSERT_NE(0, session->id());
auto result = sm->findSession(session->id());
ASSERT_TRUE(result.ok());
ASSERT_EQ(session.get(), result.value().get());
}
TEST(SessionManager, ExpiredSession) {
FLAGS_session_idle_timeout_secs = 3;
FLAGS_session_reclaim_interval_secs = 1;
auto sm = std::make_shared<SessionManager>();
auto worker = std::make_shared<GenericWorker>();
ASSERT_TRUE(worker->start());
auto idle = sm->createSession();
auto active = sm->createSession();
ASSERT_NE(nullptr, idle);
ASSERT_NE(nullptr, active);
ASSERT_NE(idle.get(), active.get());
ASSERT_NE(idle->id(), active->id());
// keep `active' active
auto charger = [&] () {
active->charge();
};
worker->addRepeatTask(1000/*ms*/, charger);
// assert `idle' not expired
auto check_not_expired = [&] () {
auto result = sm->findSession(idle->id());
ASSERT_TRUE(result.ok());
ASSERT_NE(nullptr, result.value());
};
// assert `idle' has expired
auto check_already_expired = [&] () {
auto result = sm->findSession(idle->id());
ASSERT_FALSE(result.ok());
};
auto timeout = FLAGS_session_idle_timeout_secs;
auto future1 = worker->addDelayTask((timeout - 1) * 1000 - 50/*ms*/, check_not_expired);
auto future2 = worker->addDelayTask((timeout + 1) * 1000 + 50/*ms*/, check_already_expired);
std::move(future1).get();
std::move(future2).get();
auto result = sm->findSession(active->id());
ASSERT_TRUE(result.ok());
ASSERT_NE(nullptr, result.value());
ASSERT_EQ(active.get(), result.value().get());
worker->stop();
worker->wait();
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/test/TestBase.h"
namespace nebula {
namespace graph {
void TestBase::SetUp() {
}
void TestBase::TearDown() {
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_TEST_TESTBASE_H_
#define GRAPH_TEST_TESTBASE_H_
#include "base/Base.h"
#include <gtest/gtest.h>
#include "gen-cpp2/GraphService.h"
/**
* According to the ADL(Argument-dependent Lookup) rules,
* we have to define operator<< for `std::tuple<...>' in the global scope or `std'
*/
namespace std {
template <typename Tuple, size_t...Is>
void printTupleImpl(std::ostream &os, const Tuple &tuple, std::index_sequence<Is...>) {
auto flags = os.flags();
os << std::boolalpha;
using DumyType = int[];
(void)DumyType{(void(os << (Is == 0 ? "" : ", ") << std::get<Is>(tuple)), 0)...};
os.flags(flags);
}
template <typename Tuple>
void printTuple(std::ostream &os, const Tuple &tuple) {
printTupleImpl(os, tuple, std::make_index_sequence<std::tuple_size<Tuple>::value>());
}
template <typename...Args>
std::ostream& operator<<(std::ostream &os, const std::tuple<Args...> &tuple) {
os << "[";
printTuple(os, tuple);
os << "]";
return os;
}
} // namespace std
namespace nebula {
namespace graph {
class TestBase : public ::testing::Test {
protected:
void SetUp() override;
void TearDown() override;
using AssertionResult = ::testing::AssertionResult;
using ColumnType = cpp2::ColumnValue::Type;
using Row = std::vector<cpp2::ColumnValue>;
using Rows = std::vector<Row>;
template <typename, typename>
struct uniform_tuple_impl;
template <typename T, size_t...Is>
struct uniform_tuple_impl<T, std::index_sequence<Is...>> {
template <size_t>
using IndexedType = T;
using type = std::tuple<IndexedType<Is>...>;
};
template <typename T, size_t N>
struct uniform_tuple {
using type = typename uniform_tuple_impl<T, std::make_index_sequence<N>>::type;
};
template <typename T, size_t N>
using uniform_tuple_t = typename uniform_tuple<T, N>::type;
Rows respToRecords(const cpp2::ExecutionResponse &resp) {
CHECK(resp.get_rows() != nullptr);
Rows result;
for (auto &row : *resp.get_rows()) {
auto &columns = row.get_columns();
result.emplace_back();
result.back().assign(columns.begin(), columns.end());
}
return result;
}
/**
* Convert `ColumnValue' to its cooresponding type
*/
template <typename T>
std::enable_if_t<std::is_integral<T>::value, T>
convert(const cpp2::ColumnValue &v) {
switch (v.getType()) {
case ColumnType::integer:
return v.get_integer();
case ColumnType::timestamp:
return v.get_timestamp();
case ColumnType::id:
return v.get_id();
case ColumnType::boolean:
return v.get_boolean();
default:
throw TestError() << "Cannot convert unknown dynamic column type to integer: "
<< static_cast<int32_t>(v.getType());
}
return T(); // suppress the no-return waring
}
template <typename T>
std::enable_if_t<std::is_same<T, std::string>::value, T>
convert(const cpp2::ColumnValue &v) {
switch (v.getType()) {
case ColumnType::str:
return v.get_str();
default:
throw TestError() << "Cannot convert unknown dynamic column type to string: "
<< static_cast<int32_t>(v.getType());
}
return T(); // suppress the no-return warning
}
/**
* Transform rows of dynamic type to tuples of static type
*/
template <typename Tuple, size_t...Is>
auto rowToTupleImpl(const Row &row, std::index_sequence<Is...>) {
return std::make_tuple(convert<std::tuple_element_t<Is, Tuple>>(row[Is])...);
}
template <typename Tuple>
auto rowToTuple(const Row &row) {
constexpr auto tupleSize = std::tuple_size<Tuple>::value;
return rowToTupleImpl<Tuple>(row, std::make_index_sequence<tupleSize>());
}
template <typename Tuple>
auto rowsToTuples(const Rows &rows) {
std::vector<Tuple> result;
if (rows.empty()) {
return result;
}
if (rows.back().size() != std::tuple_size<Tuple>::value) {
throw TestError() << "Column count not match: "
<< rows.back().size() << " vs. "
<< std::tuple_size<Tuple>::value;
}
for (auto &row : rows) {
result.emplace_back(rowToTuple<Tuple>(row));
}
return result;
}
template <typename Tuple>
AssertionResult verifyResult(const cpp2::ExecutionResponse &resp,
std::vector<Tuple> &expected) {
if (resp.get_error_code() != cpp2::ErrorCode::SUCCEEDED) {
auto *errmsg = resp.get_error_msg();
return TestError() << "Query failed with `"
<< static_cast<int32_t>(resp.get_error_code())
<< (errmsg == nullptr ? "'" : "': " + *errmsg);
}
std::vector<Tuple> rows;
try {
rows = rowsToTuples<Tuple>(respToRecords(resp));
} catch (const AssertionResult &e) {
return e;
} catch (const std::exception &e) {
return TestError() << "Unknown exception thrown: " << e.what();
}
if (expected.size() != rows.size()) {
return TestError() << "Rows' count not match: "
<< rows.size() << " vs. " << expected.size();
}
if (expected.empty()) {
return TestOK();
}
std::sort(rows.begin(), rows.end());
std::sort(expected.begin(), expected.end());
for (auto i = 0u; i < rows.size(); i++) {
if (rows[i] != expected[i]) {
return TestError() << rows[i] << " vs. " << expected[i];
}
}
return TestOK();
}
protected:
std::function<AssertionResult()> TestOK = [] { return ::testing::AssertionSuccess(); };
std::function<AssertionResult()> TestError = [] { return ::testing::AssertionFailure(); };
};
} // namespace graph
} // namespace nebula
#endif // GRAPH_TEST_TESTBASE_H_
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#include "base/Base.h"
#include "graph/test/TestEnv.h"
namespace nebula {
namespace graph {
TestEnv *gEnv = nullptr;
TestEnv::TestEnv() {
}
TestEnv::~TestEnv() {
}
void TestEnv::SetUp() {
auto interface = std::make_shared<GraphService>();
using ThriftServer = apache::thrift::ThriftServer;
server_ = std::make_unique<ThriftServer>();
server_->setInterface(std::move(interface));
server_->setPort(0); // Let the system choose an available port for us
auto serve = [this] {
server_->serve();
};
thread_ = std::make_unique<thread::NamedThread>("", serve);
// busy waiting for `thread_' to enter the loop
while (!server_->getServeEventBase() || !server_->getServeEventBase()->isRunning()) {
;
}
}
void TestEnv::TearDown() {
if (server_ != nullptr) {
server_->stop();
}
if (thread_ != nullptr) {
thread_->join();
}
server_ = nullptr;
thread_ = nullptr;
}
uint16_t TestEnv::serverPort() const {
return server_->getAddress().getPort();
}
std::unique_ptr<GraphClient> TestEnv::getClient() const {
auto client = std::make_unique<GraphClient>("127.0.0.1", serverPort());
if (cpp2::ErrorCode::SUCCEEDED != client->connect("user", "password")) {
return nullptr;
}
return client;
}
} // namespace graph
} // namespace nebula
/* Copyright (c) 2018 - present, VE Software Inc. All rights reserved
*
* This source code is licensed under Apache 2.0 License
* (found in the LICENSE.Apache file in the root directory)
*/
#ifndef GRAPH_TEST_TESTENV_H_
#define GRAPH_TEST_TESTENV_H_
#include "base/Base.h"
#include <gtest/gtest.h>
#include "thread/NamedThread.h"
#include <thrift/lib/cpp2/server/ThriftServer.h>
#include "graph/GraphService.h"
#include "client/cpp/GraphClient.h"
namespace apache {
namespace thrift {
class ThriftServer;
}
}
namespace nebula {
namespace graph {
class GraphClient;
class TestEnv : public ::testing::Environment {
public:
TestEnv();
virtual ~TestEnv();
void SetUp() override;
void TearDown() override;
// Obtain the system assigned listening port
uint16_t serverPort() const;
std::unique_ptr<GraphClient> getClient() const;
private:
std::unique_ptr<apache::thrift::ThriftServer> server_;
std::unique_ptr<thread::NamedThread> thread_;
};
extern TestEnv *gEnv;
} // namespace graph
} // namespace nebula
#endif // GRAPH_TEST_TESTENV_H_
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment