LogCabin
RPC/ServiceMock.h
Go to the documentation of this file.
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 */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines