diff --git a/src/clients/meta/MetaClient.cpp b/src/clients/meta/MetaClient.cpp index e7058f9b91e..a3e46fc9c0d 100644 --- a/src/clients/meta/MetaClient.cpp +++ b/src/clients/meta/MetaClient.cpp @@ -90,6 +90,12 @@ bool MetaClient::isMetadReady() { } bool MetaClient::waitForMetadReady(int count, int retryIntervalSecs) { + auto status = verifyVersion(); + if (!status.ok()) { + LOG(ERROR) << status; + return false; + } + if (!options_.skipConfig_) { std::string gflagsJsonPath; GflagsManager::getGflagsModule(gflagsModule_); @@ -568,98 +574,102 @@ void MetaClient::getResponse(Request req, folly::RWSpinLock::ReadHolder holder(&hostLock_); host = toLeader ? leader_ : active_; } - folly::via(evb, - [host, - evb, - req = std::move(req), - remoteFunc = std::move(remoteFunc), - respGen = std::move(respGen), - pro = std::move(pro), - toLeader, - retry, - retryLimit, - this]() mutable { - auto client = clientsMan_->client(host, evb, false, FLAGS_meta_client_timeout_ms); - VLOG(1) << "Send request to meta " << host; - remoteFunc(client, req) - .via(evb) - .then([host, - req = std::move(req), - remoteFunc = std::move(remoteFunc), - respGen = std::move(respGen), - pro = std::move(pro), - toLeader, - retry, - retryLimit, - evb, - this](folly::Try&& t) mutable { - // exception occurred during RPC - if (t.hasException()) { - if (toLeader) { - updateLeader(); - } else { - updateActive(); - } - if (retry < retryLimit) { - evb->runAfterDelay( - [req = std::move(req), - remoteFunc = std::move(remoteFunc), - respGen = std::move(respGen), - pro = std::move(pro), - toLeader, - retry, - retryLimit, - this]() mutable { - getResponse(std::move(req), - std::move(remoteFunc), - std::move(respGen), - std::move(pro), - toLeader, - retry + 1, - retryLimit); - }, - FLAGS_meta_client_retry_interval_secs * 1000); - return; - } else { - LOG(ERROR) << "Send request to " << host << ", exceed retry limit"; - pro.setValue(Status::Error("RPC failure in MetaClient: %s", - t.exception().what().c_str())); - } - return; - } - - auto&& resp = t.value(); - if (resp.get_code() == nebula::cpp2::ErrorCode::SUCCEEDED) { - // succeeded - pro.setValue(respGen(std::move(resp))); - return; - } else if (resp.get_code() == nebula::cpp2::ErrorCode::E_LEADER_CHANGED) { - updateLeader(resp.get_leader()); - if (retry < retryLimit) { - evb->runAfterDelay( - [req = std::move(req), - remoteFunc = std::move(remoteFunc), - respGen = std::move(respGen), - pro = std::move(pro), - toLeader, - retry, - retryLimit, - this]() mutable { - getResponse(std::move(req), - std::move(remoteFunc), - std::move(respGen), - std::move(pro), - toLeader, - retry + 1, - retryLimit); - }, - FLAGS_meta_client_retry_interval_secs * 1000); - return; - } - } - pro.setValue(this->handleResponse(resp)); - }); // then - }); // via + folly::via( + evb, + [host, + evb, + req = std::move(req), + remoteFunc = std::move(remoteFunc), + respGen = std::move(respGen), + pro = std::move(pro), + toLeader, + retry, + retryLimit, + this]() mutable { + auto client = clientsMan_->client(host, evb, false, FLAGS_meta_client_timeout_ms); + VLOG(1) << "Send request to meta " << host; + remoteFunc(client, req) + .via(evb) + .then([host, + req = std::move(req), + remoteFunc = std::move(remoteFunc), + respGen = std::move(respGen), + pro = std::move(pro), + toLeader, + retry, + retryLimit, + evb, + this](folly::Try&& t) mutable { + // exception occurred during RPC + if (t.hasException()) { + if (toLeader) { + updateLeader(); + } else { + updateActive(); + } + if (retry < retryLimit) { + evb->runAfterDelay( + [req = std::move(req), + remoteFunc = std::move(remoteFunc), + respGen = std::move(respGen), + pro = std::move(pro), + toLeader, + retry, + retryLimit, + this]() mutable { + getResponse(std::move(req), + std::move(remoteFunc), + std::move(respGen), + std::move(pro), + toLeader, + retry + 1, + retryLimit); + }, + FLAGS_meta_client_retry_interval_secs * 1000); + return; + } else { + LOG(ERROR) << "Send request to " << host << ", exceed retry limit"; + pro.setValue( + Status::Error("RPC failure in MetaClient: %s", t.exception().what().c_str())); + } + return; + } + + auto&& resp = t.value(); + if (resp.get_code() == nebula::cpp2::ErrorCode::SUCCEEDED) { + // succeeded + pro.setValue(respGen(std::move(resp))); + return; + } else if (resp.get_code() == nebula::cpp2::ErrorCode::E_LEADER_CHANGED) { + updateLeader(resp.get_leader()); + if (retry < retryLimit) { + evb->runAfterDelay( + [req = std::move(req), + remoteFunc = std::move(remoteFunc), + respGen = std::move(respGen), + pro = std::move(pro), + toLeader, + retry, + retryLimit, + this]() mutable { + getResponse(std::move(req), + std::move(remoteFunc), + std::move(respGen), + std::move(pro), + toLeader, + retry + 1, + retryLimit); + }, + FLAGS_meta_client_retry_interval_secs * 1000); + return; + } + } else if (resp.get_code() == nebula::cpp2::ErrorCode::E_CLIENT_SERVER_INCOMPATIBLE) { + pro.setValue(respGen(std::move(resp))); + return; + } + pro.setValue(this->handleResponse(resp)); + }); // then + }); // via } std::vector MetaClient::toSpaceIdName(const std::vector& tIdNames) { @@ -3564,5 +3574,25 @@ bool MetaClient::checkIsPlanKilled(SessionID sessionId, ExecutionPlanID planId) return killedPlans_.load()->count({sessionId, planId}); } +Status MetaClient::verifyVersion() { + auto req = cpp2::VerifyClientVersionReq(); + folly::Promise> promise; + auto future = promise.getFuture(); + getResponse( + std::move(req), + [](auto client, auto request) { return client->future_verifyClientVersion(request); }, + [](cpp2::VerifyClientVersionResp&& resp) { return std::move(resp); }, + std::move(promise)); + + auto respStatus = std::move(future).get(); + if (!respStatus.ok()) { + return respStatus.status(); + } + auto resp = std::move(respStatus).value(); + if (resp.get_code() != nebula::cpp2::ErrorCode::SUCCEEDED) { + return Status::Error("Client verified failed: %s", resp.get_error_msg()->c_str()); + } + return Status::OK(); +} } // namespace meta } // namespace nebula diff --git a/src/clients/meta/MetaClient.h b/src/clients/meta/MetaClient.h index e6143256154..90ffecee886 100644 --- a/src/clients/meta/MetaClient.h +++ b/src/clients/meta/MetaClient.h @@ -187,6 +187,7 @@ class MetaClient { FRIEND_TEST(MetaClientTest, RetryOnceTest); FRIEND_TEST(MetaClientTest, RetryUntilLimitTest); FRIEND_TEST(MetaClientTest, RocksdbOptionsTest); + FRIEND_TEST(MetaClientTest, VerifyClientTest); friend class KillQueryMetaWrapper; FRIEND_TEST(ChainAddEdgesTest, AddEdgesLocalTest); friend class storage::MetaClientTestUpdater; @@ -710,6 +711,8 @@ class MetaClient { ListenersMap doGetListenersMap(const HostAddr& host, const LocalCache& localCache); + Status verifyVersion(); + private: std::shared_ptr ioThreadPool_; std::shared_ptr> clientsMan_; diff --git a/src/common/graph/Response.h b/src/common/graph/Response.h index 4d1beae3cdb..6af5820d83f 100644 --- a/src/common/graph/Response.h +++ b/src/common/graph/Response.h @@ -176,6 +176,9 @@ X(E_USER_CANCEL, -3052) \ X(E_TASK_EXECUTION_FAILED, -3053) \ \ + X(E_PLAN_IS_KILLED, -3060) \ + X(E_CLIENT_SERVER_INCOMPATIBLE, -3061) \ + \ X(E_UNKNOWN, -8000) namespace nebula { diff --git a/src/graph/context/test/CMakeLists.txt b/src/graph/context/test/CMakeLists.txt index a4ac8309df2..fcf2cb5a08d 100644 --- a/src/graph/context/test/CMakeLists.txt +++ b/src/graph/context/test/CMakeLists.txt @@ -42,6 +42,7 @@ SET(CONTEXT_TEST_LIBS $ $ $ + $ ) nebula_add_test( diff --git a/src/graph/executor/test/CMakeLists.txt b/src/graph/executor/test/CMakeLists.txt index b97672192c0..4244415bb18 100644 --- a/src/graph/executor/test/CMakeLists.txt +++ b/src/graph/executor/test/CMakeLists.txt @@ -50,6 +50,7 @@ SET(EXEC_QUERY_TEST_OBJS $ $ $ + $ ) SET(EXEC_QUERY_TEST_LIBS diff --git a/src/graph/optimizer/test/CMakeLists.txt b/src/graph/optimizer/test/CMakeLists.txt index 222c8835e28..1ff93fc2374 100644 --- a/src/graph/optimizer/test/CMakeLists.txt +++ b/src/graph/optimizer/test/CMakeLists.txt @@ -45,6 +45,7 @@ set(OPTIMIZER_TEST_LIB $ $ $ + $ ) nebula_add_test( diff --git a/src/graph/planner/test/CMakeLists.txt b/src/graph/planner/test/CMakeLists.txt index 997010c4511..e586d57febb 100644 --- a/src/graph/planner/test/CMakeLists.txt +++ b/src/graph/planner/test/CMakeLists.txt @@ -49,6 +49,7 @@ nebula_add_test( $ $ $ + $ LIBRARIES gtest ${PROXYGEN_LIBRARIES} diff --git a/src/graph/service/GraphFlags.cpp b/src/graph/service/GraphFlags.cpp index 10591b38687..6018bde637a 100644 --- a/src/graph/service/GraphFlags.cpp +++ b/src/graph/service/GraphFlags.cpp @@ -6,6 +6,8 @@ #include "graph/service/GraphFlags.h" +#include "version/Version.h" + DEFINE_int32(port, 3699, "Nebula Graph daemon's listen port"); DEFINE_int32(client_idle_timeout_secs, 0, @@ -65,3 +67,8 @@ DEFINE_bool(disable_octal_escape_char, " in next version to ensure compatibility with cypher."); DEFINE_bool(enable_experimental_feature, false, "Whether to enable experimental feature"); + +DEFINE_bool(enable_client_white_list, true, "Turn on/off the client white list."); +DEFINE_string(client_white_list, + nebula::getOriginVersion() + ":2.5.0:2.5.1:2.6.0", + "A white list for different client versions, seperate with colon."); diff --git a/src/graph/service/GraphFlags.h b/src/graph/service/GraphFlags.h index 40b9fd5bd71..21b6a769e78 100644 --- a/src/graph/service/GraphFlags.h +++ b/src/graph/service/GraphFlags.h @@ -48,4 +48,6 @@ DECLARE_string(local_ip); DECLARE_bool(enable_experimental_feature); +DECLARE_bool(enable_client_white_list); +DECLARE_string(client_white_list); #endif // GRAPH_GRAPHFLAGS_H_ diff --git a/src/graph/service/GraphService.cpp b/src/graph/service/GraphService.cpp index f09c7423e23..bad422047b6 100644 --- a/src/graph/service/GraphService.cpp +++ b/src/graph/service/GraphService.cpp @@ -184,5 +184,22 @@ bool GraphService::auth(const std::string& username, const std::string& password return false; } +folly::Future GraphService::future_verifyClientVersion( + const cpp2::VerifyClientVersionReq& req) { + std::unordered_set whiteList; + folly::splitTo( + ":", FLAGS_client_white_list, std::inserter(whiteList, whiteList.begin())); + cpp2::VerifyClientVersionResp resp; + if (FLAGS_enable_client_white_list && whiteList.find(req.get_version()) == whiteList.end()) { + resp.set_error_code(nebula::cpp2::ErrorCode::E_CLIENT_SERVER_INCOMPATIBLE); + resp.set_error_msg(folly::stringPrintf( + "Graph client version(%s) is not accepted, current graph client white list: %s.", + req.get_version().c_str(), + FLAGS_client_white_list.c_str())); + } else { + resp.set_error_code(nebula::cpp2::ErrorCode::SUCCEEDED); + } + return folly::makeFuture(std::move(resp)); +} } // namespace graph } // namespace nebula diff --git a/src/graph/service/GraphService.h b/src/graph/service/GraphService.h index 76dc0f811b1..634d821fb9a 100644 --- a/src/graph/service/GraphService.h +++ b/src/graph/service/GraphService.h @@ -39,6 +39,9 @@ class GraphService final : public cpp2::GraphServiceSvIf { folly::Future future_executeJson(int64_t sessionId, const std::string& stmt) override; + folly::Future future_verifyClientVersion( + const cpp2::VerifyClientVersionReq& req) override; + private: bool auth(const std::string& username, const std::string& password); diff --git a/src/graph/util/test/CMakeLists.txt b/src/graph/util/test/CMakeLists.txt index 2076f613254..a3f01a7aac7 100644 --- a/src/graph/util/test/CMakeLists.txt +++ b/src/graph/util/test/CMakeLists.txt @@ -44,6 +44,7 @@ nebula_add_test( $ $ $ + $ LIBRARIES gtest gtest_main diff --git a/src/interface/common.thrift b/src/interface/common.thrift index e571729514b..71ba8b0714b 100644 --- a/src/interface/common.thrift +++ b/src/interface/common.thrift @@ -34,6 +34,8 @@ cpp_include "common/datatypes/GeographyOps-inl.h" * */ +const binary (cpp.type = "char const *") version = "2.6.0" + typedef i32 (cpp.type = "nebula::GraphSpaceID") GraphSpaceID typedef i32 (cpp.type = "nebula::PartitionID") PartitionID typedef i32 (cpp.type = "nebula::TagID") TagID @@ -409,5 +411,7 @@ enum ErrorCode { E_OUTDATED_EDGE = -3072, E_WRITE_WRITE_CONFLICT = -3073, + E_CLIENT_SERVER_INCOMPATIBLE = -3061, + E_UNKNOWN = -8000, } (cpp.enum_strict) diff --git a/src/interface/graph.thrift b/src/interface/graph.thrift index 2a6268bc39d..08412492830 100644 --- a/src/interface/graph.thrift +++ b/src/interface/graph.thrift @@ -99,6 +99,17 @@ struct AuthResponse { } (cpp.type = "nebula::AuthResponse") +struct VerifyClientVersionResp { + 1: required common.ErrorCode error_code; + 2: optional binary error_msg; +} + + +struct VerifyClientVersionReq { + 1: required binary version = common.version; +} + + service GraphService { AuthResponse authenticate(1: binary username, 2: binary password) @@ -108,4 +119,6 @@ service GraphService { // Same as execute(), but response will be a json string binary executeJson(1: i64 sessionId, 2: binary stmt) + + VerifyClientVersionResp verifyClientVersion(1: VerifyClientVersionReq req) } diff --git a/src/interface/meta.thrift b/src/interface/meta.thrift index c84ef0193ec..17ed13578a9 100644 --- a/src/interface/meta.thrift +++ b/src/interface/meta.thrift @@ -1184,6 +1184,17 @@ struct GetMetaDirInfoResp { struct GetMetaDirInfoReq { } +struct VerifyClientVersionResp { + 1: common.ErrorCode code, + 2: common.HostAddr leader, + 3: optional binary error_msg; +} + + +struct VerifyClientVersionReq { + 1: required binary version = common.version; +} + service MetaService { ExecResp createSpace(1: CreateSpaceReq req); ExecResp dropSpace(1: DropSpaceReq req); @@ -1294,4 +1305,6 @@ service MetaService { ListClusterInfoResp listCluster(1: ListClusterInfoReq req); GetMetaDirInfoResp getMetaDirInfo(1: GetMetaDirInfoReq req); + + VerifyClientVersionResp verifyClientVersion(1: VerifyClientVersionReq req) } diff --git a/src/meta/CMakeLists.txt b/src/meta/CMakeLists.txt index 6fb07b41669..ea9f436d611 100644 --- a/src/meta/CMakeLists.txt +++ b/src/meta/CMakeLists.txt @@ -59,6 +59,7 @@ nebula_add_library( processors/admin/RestoreProcessor.cpp processors/admin/ListClusterInfoProcessor.cpp processors/admin/GetMetaDirInfoProcessor.cpp + processors/admin/VerifyClientVersionProcessor.cpp processors/config/RegConfigProcessor.cpp processors/config/GetConfigProcessor.cpp processors/config/ListConfigsProcessor.cpp diff --git a/src/meta/MetaServiceHandler.cpp b/src/meta/MetaServiceHandler.cpp index 76d3ca0009f..d00c5185be8 100644 --- a/src/meta/MetaServiceHandler.cpp +++ b/src/meta/MetaServiceHandler.cpp @@ -17,6 +17,7 @@ #include "meta/processors/admin/ListClusterInfoProcessor.h" #include "meta/processors/admin/ListSnapshotsProcessor.h" #include "meta/processors/admin/RestoreProcessor.h" +#include "meta/processors/admin/VerifyClientVersionProcessor.h" #include "meta/processors/config/GetConfigProcessor.h" #include "meta/processors/config/ListConfigsProcessor.h" #include "meta/processors/config/RegConfigProcessor.h" @@ -579,5 +580,11 @@ folly::Future MetaServiceHandler::future_killQuery(const cpp2::K auto* processor = KillQueryProcessor::instance(kvstore_); RETURN_FUTURE(processor); } + +folly::Future MetaServiceHandler::future_verifyClientVersion( + const cpp2::VerifyClientVersionReq& req) { + auto* processor = VerifyClientVersionProcessor::instance(kvstore_); + RETURN_FUTURE(processor); +} } // namespace meta } // namespace nebula diff --git a/src/meta/MetaServiceHandler.h b/src/meta/MetaServiceHandler.h index bafec070efe..0d8093846c6 100644 --- a/src/meta/MetaServiceHandler.h +++ b/src/meta/MetaServiceHandler.h @@ -243,6 +243,9 @@ class MetaServiceHandler final : public cpp2::MetaServiceSvIf { folly::Future future_killQuery(const cpp2::KillQueryReq& req) override; + folly::Future future_verifyClientVersion( + const cpp2::VerifyClientVersionReq& req) override; + private: kvstore::KVStore* kvstore_ = nullptr; ClusterID clusterId_{0}; diff --git a/src/meta/processors/admin/VerifyClientVersionProcessor.cpp b/src/meta/processors/admin/VerifyClientVersionProcessor.cpp new file mode 100644 index 00000000000..5ef5a213e2d --- /dev/null +++ b/src/meta/processors/admin/VerifyClientVersionProcessor.cpp @@ -0,0 +1,34 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#include "meta/processors/admin/VerifyClientVersionProcessor.h" + +#include "version/Version.h" + +DEFINE_bool(enable_client_white_list, true, "Turn on/off the client white list."); +DEFINE_string(client_white_list, + nebula::getOriginVersion() + ":2.5.0:2.5.1:2.6.0", + "A white list for different client versions, seperate with colon."); + +namespace nebula { +namespace meta { +void VerifyClientVersionProcessor::process(const cpp2::VerifyClientVersionReq& req) { + std::unordered_set whiteList; + folly::splitTo( + ":", FLAGS_client_white_list, std::inserter(whiteList, whiteList.begin())); + if (FLAGS_enable_client_white_list && whiteList.find(req.get_version()) == whiteList.end()) { + resp_.set_code(nebula::cpp2::ErrorCode::E_CLIENT_SERVER_INCOMPATIBLE); + resp_.set_error_msg(folly::stringPrintf( + "Meta client version(%s) is not accepted, current meta client white list: %s.", + req.get_version().c_str(), + FLAGS_client_white_list.c_str())); + } else { + resp_.set_code(nebula::cpp2::ErrorCode::SUCCEEDED); + } + onFinished(); +} +} // namespace meta +} // namespace nebula diff --git a/src/meta/processors/admin/VerifyClientVersionProcessor.h b/src/meta/processors/admin/VerifyClientVersionProcessor.h new file mode 100644 index 00000000000..f049d8f75ee --- /dev/null +++ b/src/meta/processors/admin/VerifyClientVersionProcessor.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2021 vesoft inc. All rights reserved. + * + * This source code is licensed under Apache 2.0 License, + * attached with Common Clause Condition 1.0, found in the LICENSES directory. + */ + +#ifndef META_VERIFYCLIENTVERSIONPROCESSOR_H_ +#define META_VERIFYCLIENTVERSIONPROCESSOR_H_ + +#include "meta/processors/BaseProcessor.h" + +namespace nebula { +namespace meta { +class VerifyClientVersionProcessor final : public BaseProcessor { + public: + static VerifyClientVersionProcessor* instance(kvstore::KVStore* kvstore) { + return new VerifyClientVersionProcessor(kvstore); + } + + void process(const cpp2::VerifyClientVersionReq& req); + + private: + explicit VerifyClientVersionProcessor(kvstore::KVStore* kvstore) + : BaseProcessor(kvstore) {} +}; +} // namespace meta +} // namespace nebula +#endif // META_VERIFYCLIENTVERSIONPROCESSOR_H_ diff --git a/src/meta/test/MetaClientTest.cpp b/src/meta/test/MetaClientTest.cpp index e6d555f398e..f49609a89c0 100644 --- a/src/meta/test/MetaClientTest.cpp +++ b/src/meta/test/MetaClientTest.cpp @@ -16,12 +16,15 @@ #include "common/meta/GflagsManager.h" #include "common/meta/ServerBasedSchemaManager.h" #include "common/network/NetworkUtils.h" +#include "interface/gen-cpp2/common_constants.h" #include "meta/MetaServiceUtils.h" #include "meta/test/TestUtils.h" #include "mock/MockCluster.h" DECLARE_int32(heartbeat_interval_secs); DECLARE_string(rocksdb_db_options); +DECLARE_bool(enable_client_white_list); +DECLARE_string(client_white_list); namespace nebula { namespace meta { @@ -2080,6 +2083,40 @@ TEST(MetaClientTest, ListenerTest) { } } +TEST(MetaClientTest, VerifyClientTest) { + FLAGS_heartbeat_interval_secs = 1; + fs::TempDir rootPath("/tmp/VerifyClientTest.XXXXXX"); + + mock::MockCluster cluster; + cluster.startMeta(rootPath.path()); + cluster.initMetaClient(); + auto* client = cluster.metaClient_.get(); + + FLAGS_enable_client_white_list = true; + { + FLAGS_client_white_list = nebula::cpp2::common_constants::version(); + auto status = client->verifyVersion(); + EXPECT_TRUE(status.ok()); + } + { + FLAGS_client_white_list = ""; + auto status = client->verifyVersion(); + EXPECT_FALSE(status.ok()); + } + { + FLAGS_client_white_list = "1.0.0:1.2.0:"; + auto status = client->verifyVersion(); + EXPECT_FALSE(status.ok()); + } + { + FLAGS_enable_client_white_list = false; + FLAGS_client_white_list = "1.0.0:1.2.0:"; + auto status = client->verifyVersion(); + EXPECT_TRUE(status.ok()); + } + FLAGS_enable_client_white_list = false; +} + TEST(MetaClientTest, RocksdbOptionsTest) { FLAGS_heartbeat_interval_secs = 1; fs::TempDir rootPath("/tmp/RocksdbOptionsTest.XXXXXX"); diff --git a/src/parser/test/CMakeLists.txt b/src/parser/test/CMakeLists.txt index c90ee40a187..89d1f367c35 100644 --- a/src/parser/test/CMakeLists.txt +++ b/src/parser/test/CMakeLists.txt @@ -44,6 +44,7 @@ set(PARSER_TEST_LIBS $ $ $ + $ ) nebula_add_test( diff --git a/src/version/Version.cpp.in b/src/version/Version.cpp.in index c4187744c4d..82f956efe6e 100644 --- a/src/version/Version.cpp.in +++ b/src/version/Version.cpp.in @@ -31,4 +31,11 @@ std::string versionString(bool verbose) { return version; } +std::string getOriginVersion() { +#if defined(NEBULA_BUILD_VERSION) + return NEBULA_BUILD_VERSION; +#else + return ""; +#endif +} } // namespace nebula diff --git a/src/version/Version.h b/src/version/Version.h index bf04072cada..51a1f1585d5 100644 --- a/src/version/Version.h +++ b/src/version/Version.h @@ -13,6 +13,7 @@ namespace nebula { std::string gitInfoSha(); std::string versionString(bool verbose = true); +std::string getOriginVersion(); } // namespace nebula diff --git a/tests/conftest.py b/tests/conftest.py index d1bb4c235b5..c4f320ea462 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,6 +14,12 @@ from tests.common.utils import get_conn_pool from tests.common.constants import NB_TMP_PATH, SPACE_TMP_PATH +#from thrift.transport import TSocket +#from thrift.transport import TTransport +#from thrift.protocol import TBinaryProtocol +from nebula2.gclient.net import Connection +from nebula2.graph import GraphService + tests_collected = set() tests_executed = set() data_dir = os.getenv('NEBULA_DATA_DIR') @@ -186,3 +192,13 @@ def workarround_for_class(request, pytestconfig, conn_pool, if request.cls.client is not None: request.cls.cleanup() request.cls.drop_data() + +#@pytest.fixture(scope="class") +#def establish_a_rare_connection(pytestconfig): +# addr = pytestconfig.getoption("address") +# host_addr = addr.split(":") if addr else ["localhost", get_ports()[0]] +# socket = TSocket.TSocket(host_addr[0], host_addr[1]) +# transport = TTransport.TBufferedTransport(socket) +# protocol = TBinaryProtocol.TBinaryProtocol(transport) +# transport.open() +# return GraphService.Client(protocol) diff --git a/tests/tck/conftest.py b/tests/tck/conftest.py index 663273145b0..fc2d8f67685 100644 --- a/tests/tck/conftest.py +++ b/tests/tck/conftest.py @@ -32,6 +32,9 @@ from tests.tck.utils.table import dataset, table from tests.tck.utils.nbv import murmurhash2 +#from nebula2.graph.ttypes import VerifyClientVersionReq +#from nebula2.graph.ttypes import VerifyClientVersionResp + parse = functools.partial(parsers.parse) rparse = functools.partial(parsers.re) example_pattern = re.compile(r"<(\w+)>") @@ -532,3 +535,31 @@ def executing_query_with_params(query, indices, keys, graph_spaces, session, req register_lock.release() ngql = combine_query(query).format(*vals) exec_query(request, ngql, session, graph_spaces) + +#@given(parse("nothing")) +#def nothing(): +# pass +# +#@when(parse("connecting the servers with a compatible client version")) +#def connecting_servers_with_a_compatible_client_version(establish_a_rare_connection, graph_spaces): +# conn = establish_a_rare_connection +# graph_spaces["resp"] = conn.verifyClientVersion(VerifyClientVersionReq()) +# conn._iprot.trans.close() +# +#@then(parse("the connection should be established")) +#def check_client_compatible(graph_spaces): +# resp = graph_spaces["resp"] +# assert resp.error_code == ErrorCode.SUCCEEDED, f'The client was rejected by server: {resp}' +# +#@when(parse("connecting the servers with a client version of {version}")) +#def connecting_servers_with_a_compatible_client_version(version, establish_a_rare_connection, graph_spaces): +# conn = establish_a_rare_connection +# req = VerifyClientVersionReq() +# req.version = version +# graph_spaces["resp"] = conn.verifyClientVersion(req) +# conn._iprot.trans.close() +# +#@then(parse("the connection should be rejected")) +#def check_client_compatible(graph_spaces): +# resp = graph_spaces["resp"] +# assert resp.error_code == ErrorCode.E_CLIENT_SERVER_INCOMPATIBLE, f'The client was not rejected by server: {resp}' diff --git a/tests/tck/features/verify_client_version/VerifyClientVersion.feature b/tests/tck/features/verify_client_version/VerifyClientVersion.feature new file mode 100644 index 00000000000..777c11b9efd --- /dev/null +++ b/tests/tck/features/verify_client_version/VerifyClientVersion.feature @@ -0,0 +1,16 @@ +# Copyright (c) 2021 vesoft inc. All rights reserved. +# +# This source code is licensed under Apache 2.0 License, +# attached with Common Clause Condition 1.0, found in the LICENSES directory. +@skip +Feature: Verify client version + + Scenario: compatible version + Given nothing + When connecting the servers with a compatible client version + Then the connection should be established + + Scenario: incompactible version + Given nothing + When connecting the servers with a client version of 100.0.0 + Then the connection should be rejected