LogCabin
|
00001 /* Copyright (c) 2012 Stanford University 00002 * 00003 * Permission to use, copy, modify, and distribute this software for any 00004 * purpose with or without fee is hereby granted, provided that the above 00005 * copyright notice and this permission notice appear in all copies. 00006 * 00007 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES 00008 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 00009 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR 00010 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 00011 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 00012 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 00013 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00014 */ 00015 00016 #include <cinttypes> 00017 #include <google/protobuf/message.h> 00018 #include <memory> 00019 #include <queue> 00020 00021 #include "Core/ProtoBuf.h" 00022 #include "RPC/Service.h" 00023 #include "RPC/ServerRPC.h" 00024 00025 #ifndef LOGCABIN_RPC_SERVICEMOCK_H 00026 #define LOGCABIN_RPC_SERVICEMOCK_H 00027 00028 namespace LogCabin { 00029 namespace RPC { 00030 00031 /** 00032 * This class is used to mock out a Service for testing a client that sends 00033 * RPCs. 00034 */ 00035 class ServiceMock : public RPC::Service { 00036 public: 00037 typedef google::protobuf::Message Message; 00038 00039 /** 00040 * The base class for RPC handlers. These are called when the matching 00041 * request arrives and act on the request, for example, by replying to it. 00042 */ 00043 class Handler { 00044 virtual ~Handler() {} 00045 virtual void handleRPC(ServerRPC serverRPC) = 0; 00046 }; 00047 00048 private: 00049 /// See closeSession(). 00050 class CloseSession : public Handler { 00051 void handleRPC(ServerRPC serverRPC) { 00052 serverRPC.closeSession(); 00053 } 00054 }; 00055 00056 /// See reply(). 00057 class Reply : public Handler { 00058 explicit Reply(const Message& response) 00059 : response(Core::ProtoBuf::copy(response)) { 00060 } 00061 void handleRPC(ServerRPC serverRPC) { 00062 serverRPC.reply(*response); 00063 } 00064 std::unique_ptr<Message> response; 00065 }; 00066 00067 /// See serviceSpecificError(). 00068 class ServiceSpecificError : public Handler { 00069 explicit ServiceSpecificError(const Message& response) 00070 : response(Core::ProtoBuf::copy(response)) { 00071 } 00072 void handleRPC(ServerRPC serverRPC) { 00073 serverRPC.returnError(*response); 00074 } 00075 std::unique_ptr<Message> response; 00076 }; 00077 00078 /// See rejectInvalidRequest(). 00079 class RejectInvalidRequest : public Handler { 00080 void handleRPC(ServerRPC serverRPC) { 00081 serverRPC.rejectInvalidRequest(); 00082 } 00083 }; 00084 00085 public: 00086 00087 /** 00088 * Constructor. 00089 */ 00090 ServiceMock() 00091 : responseQueue() 00092 { 00093 } 00094 00095 /** 00096 * Destructor. Makes sure no more requests are expected. 00097 */ 00098 ~ServiceMock() { 00099 EXPECT_EQ(0U, responseQueue.size()); 00100 } 00101 00102 /** 00103 * Remove previously expected requests. 00104 */ 00105 void clear() { 00106 responseQueue = std::queue<Expected>(); 00107 } 00108 00109 /** 00110 * Close the client's session when the specified request arrives (in FIFO 00111 * order). 00112 */ 00113 void closeSession(uint16_t opCode, const Message& request) { 00114 expect(opCode, request, std::make_shared<CloseSession>()); 00115 } 00116 00117 /** 00118 * Reply normally to the client when the specified request arrives (in FIFO 00119 * order). 00120 */ 00121 void reply(uint16_t opCode, const Message& request, 00122 const Message& response) { 00123 expect(opCode, request, std::make_shared<Reply>(response)); 00124 } 00125 00126 /** 00127 * Reply with a service-specific error to the client when the specified 00128 * request arrives (in FIFO order). 00129 */ 00130 void serviceSpecificError(uint16_t opCode, const Message& request, 00131 const Message& response) { 00132 expect(opCode, request, 00133 std::make_shared<ServiceSpecificError>(response)); 00134 } 00135 00136 /** 00137 * Reject the client's RPC as an invalid request when the specified request 00138 * arrives (in FIFO order). 00139 */ 00140 void rejectInvalidRequest(uint16_t opCode, const Message& request) { 00141 expect(opCode, request, std::make_shared<RejectInvalidRequest>()); 00142 } 00143 00144 /** 00145 * Call a custom handler when the request arrives. 00146 */ 00147 void runArbitraryCode(uint16_t opCode, 00148 const Message& request, 00149 std::shared_ptr<Handler> response) { 00150 expect(opCode, request, response); 00151 } 00152 00153 /** 00154 * This is called by the Server. 00155 */ 00156 void handleRPC(RPC::ServerRPC serverRPC); 00157 00158 std::string getName() const; 00159 00160 private: 00161 /** 00162 * Call the Handler when the specified request arrives (in FIFO order). 00163 */ 00164 void expect(uint16_t opCode, 00165 const Message& request, 00166 std::shared_ptr<Handler> response); 00167 00168 /// See #responseQueue. 00169 struct Expected { 00170 Expected(uint16_t opCode, 00171 std::unique_ptr<Message> request, 00172 std::shared_ptr<Handler> response); 00173 Expected(Expected&& other); 00174 Expected& operator=(Expected&& other); 00175 /// The op code expected from the client. 00176 uint16_t opCode; 00177 /// The request message expected from the client. 00178 std::unique_ptr<Message> request; 00179 /// Code to respond to the client or close its session, etc. 00180 std::shared_ptr<Handler> response; 00181 }; 00182 00183 /** 00184 * A FIFO queue of requests to expect from clients and their associated 00185 * handlers. 00186 */ 00187 std::queue<Expected> responseQueue; 00188 }; 00189 00190 } // namespace LogCabin::RPC 00191 } // namespace LogCabin 00192 00193 #endif /* LOGCABIN_RPC_SERVICEMOCK_H */