| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| #include <glog/logging.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include <thread> |
| |
| #include "executor/common/transaction_manager.h" |
| #include "interface/rdbc/transaction_constructor.h" |
| #include "platform/config/resdb_config_utils.h" |
| #include "platform/consensus/ordering/pbft/consensus_manager_pbft.h" |
| #include "platform/networkstrate/service_network.h" |
| #include "platform/test/proto/resdb_test.pb.h" |
| |
| namespace resdb { |
| |
| using ::testing::ElementsAreArray; |
| using ::testing::Test; |
| |
| const std::string test_dir = std::string(getenv("TEST_SRCDIR")) + "/" + |
| std::string(getenv("TEST_WORKSPACE")) + |
| "/platform/test/"; |
| |
| class ResDBTestClient : public TransactionConstructor { |
| public: |
| ResDBTestClient(const ResDBConfig& config) : TransactionConstructor(config) {} |
| |
| int Set(int seq) { |
| TestRequest request; |
| request.set_seq(seq); |
| TestResponse response; |
| return SendRequest(request, &response); |
| } |
| }; |
| |
| class ResDBTestManager : public TransactionManager { |
| public: |
| ResDBTestManager(const ResDBConfig& config) : config_(config) {} |
| std::vector<int> GetSeqs() { return seqs_; } |
| |
| protected: |
| std::unique_ptr<std::string> ExecuteData(const std::string& request) { |
| TestRequest test_request; |
| // TestResponse test_response; |
| if (!test_request.ParseFromString(request)) { |
| LOG(ERROR) << "parse data fail"; |
| return nullptr; |
| } |
| seqs_.push_back(test_request.seq()); |
| return nullptr; |
| } |
| |
| ResDBConfig config_; |
| std::vector<int> seqs_; |
| }; |
| |
| class ResDBTest : public Test { |
| public: |
| void StartServer() {} |
| |
| void StartOneServer(int server_id) { |
| ResDBConfig config = GetConfig(server_id); |
| config.SetTestMode(true); |
| auto executor = std::make_unique<ResDBTestManager>(config); |
| executors_.push_back(executor.get()); |
| server_.push_back(std::make_unique<ServiceNetwork>( |
| config, |
| std::make_unique<ConsensusManagerPBFT>(config, std::move(executor)))); |
| server_thread_.push_back(std::thread( |
| [&](ServiceNetwork* server) { server->Run(); }, server_.back().get())); |
| } |
| |
| void WaitAllServerStarted() { |
| for (auto& server : server_) { |
| while (true) { |
| std::unique_lock<std::mutex> lk(mutex_); |
| cv_.wait_for(lk, std::chrono::microseconds(1000), |
| [&] { return server->ServiceIsReady(); }); |
| if (server->ServiceIsReady()) { |
| break; |
| } |
| } |
| } |
| } |
| |
| void WaitExecutorDone(int received_num) { |
| for (auto executor : executors_) { |
| while (static_cast<int>(executor->GetSeqs().size()) < received_num) { |
| usleep(10000); |
| } |
| } |
| } |
| |
| void Stop() { |
| for (auto& server : server_) { |
| server->Stop(); |
| } |
| for (auto& th : server_thread_) { |
| th.join(); |
| } |
| server_.clear(); |
| } |
| |
| std::string GetPrivateKey(int id) { |
| return test_dir + std::string("test_data/node") + std::to_string(id) + |
| ".key.pri"; |
| } |
| |
| std::string GetCertFile(int id) { |
| return test_dir + std::string("test_data/cert_") + std::to_string(id) + |
| ".cert"; |
| } |
| |
| std::string GetConfiFile() { return test_dir + "test_data/server.config"; } |
| |
| ResDBConfig GetConfig( |
| int id, std::optional<ReplicaInfo> replica_info = std::nullopt) { |
| return *GenerateResDBConfig(GetConfiFile(), GetPrivateKey(id), |
| GetCertFile(id), replica_info); |
| } |
| |
| protected: |
| std::mutex mutex_; |
| std::condition_variable cv_; |
| std::vector<ResDBTestManager*> executors_; |
| std::vector<std::unique_ptr<ServiceNetwork>> server_; |
| std::vector<std::thread> server_thread_; |
| }; |
| |
| TEST_F(ResDBTest, TestPBFTService) { |
| for (int i = 1; i <= 4; ++i) { |
| StartOneServer(i); |
| } |
| WaitAllServerStarted(); |
| int client_id = 5; |
| ReplicaInfo client_info = GenerateReplicaInfo(client_id, "127.0.0.1", 80000); |
| auto config = GetConfig(client_id, client_info); |
| ResDBTestClient client(config); |
| EXPECT_EQ(client.Set(1), 0); |
| |
| WaitExecutorDone(1); |
| |
| for (auto executor : executors_) { |
| EXPECT_THAT(executor->GetSeqs(), ElementsAreArray({1})); |
| } |
| |
| Stop(); |
| } |
| |
| } // namespace resdb |