LogCabin
|
00001 /* Copyright (c) 2012 Stanford University 00002 * Copyright (c) 2014 Diego Ongaro 00003 * 00004 * Permission to use, copy, modify, and distribute this software for any 00005 * purpose with or without fee is hereby granted, provided that the above 00006 * copyright notice and this permission notice appear in all copies. 00007 * 00008 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00009 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00010 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00011 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00012 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00013 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00014 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 */ 00016 00017 #include <gtest/gtest.h> 00018 00019 #include "Core/Debug.h" 00020 #include "Client/LeaderRPCMock.h" 00021 #include "Core/ProtoBuf.h" 00022 00023 namespace LogCabin { 00024 namespace Client { 00025 00026 LeaderRPCMock::LeaderRPCMock() 00027 : requestLog() 00028 , responseQueue() 00029 { 00030 } 00031 00032 LeaderRPCMock::~LeaderRPCMock() 00033 { 00034 } 00035 00036 void 00037 LeaderRPCMock::expect(OpCode opCode, 00038 const google::protobuf::Message& response) 00039 { 00040 MessagePtr responseCopy(response.New()); 00041 responseCopy->CopyFrom(response); 00042 responseQueue.push({opCode, std::move(responseCopy)}); 00043 } 00044 00045 LeaderRPCMock::MessagePtr 00046 LeaderRPCMock::popRequest() 00047 { 00048 MessagePtr request = std::move(requestLog.at(0).second); 00049 requestLog.pop_front(); 00050 return std::move(request); 00051 } 00052 00053 LeaderRPCMock::Status 00054 LeaderRPCMock::call(OpCode opCode, 00055 const google::protobuf::Message& request, 00056 google::protobuf::Message& response, 00057 TimePoint timeout) 00058 { 00059 if (timeout < Clock::now()) 00060 return Status::TIMEOUT; 00061 Call c(*this); 00062 c.start(opCode, request, timeout); 00063 c.wait(response, timeout); 00064 return Status::OK; 00065 } 00066 00067 LeaderRPCMock::Call::Call(LeaderRPCMock& leaderRPC) 00068 : leaderRPC(leaderRPC) 00069 , canceled(false) 00070 { 00071 } 00072 00073 void 00074 LeaderRPCMock::Call::start(OpCode opCode, 00075 const google::protobuf::Message& request, 00076 TimePoint timeout) 00077 { 00078 MessagePtr requestCopy(request.New()); 00079 requestCopy->CopyFrom(request); 00080 leaderRPC.requestLog.push_back({opCode, std::move(requestCopy)}); 00081 EXPECT_LT(0U, leaderRPC.responseQueue.size()) 00082 << "The client sent an unexpected RPC:\n" 00083 << request.GetTypeName() << ":\n" 00084 << Core::ProtoBuf::dumpString(request); 00085 if (leaderRPC.responseQueue.empty()) 00086 throw std::runtime_error("unexpected RPC"); 00087 auto& opCodeMsgPair = leaderRPC.responseQueue.front(); 00088 EXPECT_EQ(opCode, opCodeMsgPair.first); 00089 } 00090 00091 void 00092 LeaderRPCMock::Call::cancel() 00093 { 00094 canceled = true; 00095 } 00096 00097 LeaderRPCMock::Call::Status 00098 LeaderRPCMock::Call::wait(google::protobuf::Message& response, 00099 TimePoint timeout) 00100 { 00101 if (canceled) { 00102 leaderRPC.responseQueue.pop(); 00103 return Status::RETRY; 00104 } 00105 auto& opCodeMsgPair = leaderRPC.responseQueue.front(); 00106 response.CopyFrom(*opCodeMsgPair.second); 00107 leaderRPC.responseQueue.pop(); 00108 return Status::OK; 00109 } 00110 00111 std::unique_ptr<LeaderRPCBase::Call> 00112 LeaderRPCMock::makeCall() 00113 { 00114 return std::unique_ptr<LeaderRPCBase::Call>(new Call(*this)); 00115 } 00116 00117 } // namespace LogCabin::Client 00118 } // namespace LogCabin