blob: c90993a345a4bbb7a34f22326e8858973628b96e [file] [log] [blame]
Roger Meier2be7f242012-05-10 09:01:45 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19#ifndef _THRIFT_PROCESSOR_TEST_HANDLERS_H_
20#define _THRIFT_PROCESSOR_TEST_HANDLERS_H_ 1
21
Roger Meier2b1a5282012-05-11 10:12:39 +000022#include "EventLog.h"
Roger Meier2be7f242012-05-10 09:01:45 +000023#include "gen-cpp/ParentService.h"
24#include "gen-cpp/ChildService.h"
25
Konrad Grochowski16a23a62014-11-13 15:33:38 +010026namespace apache {
27namespace thrift {
28namespace test {
Roger Meier2be7f242012-05-10 09:01:45 +000029
30class ParentHandler : virtual public ParentServiceIf {
Konrad Grochowski16a23a62014-11-13 15:33:38 +010031public:
32 ParentHandler(const boost::shared_ptr<EventLog>& log)
33 : triggerMonitor(&mutex_), generation_(0), wait_(false), log_(log) {}
Roger Meier2be7f242012-05-10 09:01:45 +000034
35 int32_t incrementGeneration() {
36 concurrency::Guard g(mutex_);
37 log_->append(EventLog::ET_CALL_INCREMENT_GENERATION, 0, 0);
38 return ++generation_;
39 }
40
41 int32_t getGeneration() {
42 concurrency::Guard g(mutex_);
43 log_->append(EventLog::ET_CALL_GET_GENERATION, 0, 0);
44 return generation_;
45 }
46
47 void addString(const std::string& s) {
48 concurrency::Guard g(mutex_);
49 log_->append(EventLog::ET_CALL_ADD_STRING, 0, 0);
50 strings_.push_back(s);
51 }
52
53 void getStrings(std::vector<std::string>& _return) {
54 concurrency::Guard g(mutex_);
55 log_->append(EventLog::ET_CALL_GET_STRINGS, 0, 0);
56 _return = strings_;
57 }
58
ben-craigfae08e72015-07-15 11:34:47 -050059 void getDataWait(std::string& _return, const int32_t length) {
Roger Meier2be7f242012-05-10 09:01:45 +000060 concurrency::Guard g(mutex_);
61 log_->append(EventLog::ET_CALL_GET_DATA_WAIT, 0, 0);
62
63 blockUntilTriggered();
64
65 _return.append(length, 'a');
66 }
67
68 void onewayWait() {
69 concurrency::Guard g(mutex_);
70 log_->append(EventLog::ET_CALL_ONEWAY_WAIT, 0, 0);
71
72 blockUntilTriggered();
73 }
74
75 void exceptionWait(const std::string& message) {
76 concurrency::Guard g(mutex_);
77 log_->append(EventLog::ET_CALL_EXCEPTION_WAIT, 0, 0);
78
79 blockUntilTriggered();
80
81 MyError e;
82 e.message = message;
83 throw e;
84 }
85
86 void unexpectedExceptionWait(const std::string& message) {
87 concurrency::Guard g(mutex_);
88 log_->append(EventLog::ET_CALL_UNEXPECTED_EXCEPTION_WAIT, 0, 0);
89
90 blockUntilTriggered();
91
92 MyError e;
93 e.message = message;
94 throw e;
95 }
96
97 /**
98 * After prepareTriggeredCall() is invoked, calls to any of the *Wait()
99 * functions won't return until triggerPendingCalls() is invoked
100 *
101 * This has to be a separate function invoked by the main test thread
102 * in order to to avoid race conditions.
103 */
104 void prepareTriggeredCall() {
105 concurrency::Guard g(mutex_);
106 wait_ = true;
107 }
108
109 /**
110 * Wake up all calls waiting in blockUntilTriggered()
111 */
112 void triggerPendingCalls() {
113 concurrency::Guard g(mutex_);
114 wait_ = false;
115 triggerMonitor.notifyAll();
116 }
117
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100118protected:
Roger Meier2be7f242012-05-10 09:01:45 +0000119 /**
120 * blockUntilTriggered() won't return until triggerPendingCalls() is invoked
121 * in another thread.
122 *
123 * This should only be called when already holding mutex_.
124 */
125 void blockUntilTriggered() {
126 while (wait_) {
127 triggerMonitor.waitForever();
128 }
129
130 // Log an event when we return
131 log_->append(EventLog::ET_WAIT_RETURN, 0, 0);
132 }
133
134 concurrency::Mutex mutex_;
135 concurrency::Monitor triggerMonitor;
136 int32_t generation_;
137 bool wait_;
138 std::vector<std::string> strings_;
139 boost::shared_ptr<EventLog> log_;
140};
141
ben-craigfae08e72015-07-15 11:34:47 -0500142#ifdef _WIN32
143 #pragma warning( push )
144 #pragma warning (disable : 4250 ) //inheriting methods via dominance
145#endif;
146
Roger Meier2be7f242012-05-10 09:01:45 +0000147class ChildHandler : public ParentHandler, virtual public ChildServiceIf {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100148public:
149 ChildHandler(const boost::shared_ptr<EventLog>& log) : ParentHandler(log), value_(0) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000150
ben-craigfae08e72015-07-15 11:34:47 -0500151 int32_t setValue(const int32_t value) {
Roger Meier2be7f242012-05-10 09:01:45 +0000152 concurrency::Guard g(mutex_);
153 log_->append(EventLog::ET_CALL_SET_VALUE, 0, 0);
154
155 int32_t oldValue = value_;
156 value_ = value;
157 return oldValue;
158 }
159
160 int32_t getValue() {
161 concurrency::Guard g(mutex_);
162 log_->append(EventLog::ET_CALL_GET_VALUE, 0, 0);
163
164 return value_;
165 }
166
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100167protected:
Roger Meier2be7f242012-05-10 09:01:45 +0000168 int32_t value_;
169};
170
ben-craigfae08e72015-07-15 11:34:47 -0500171#ifdef _WIN32
172 #pragma warning( pop )
173#endif
174
Roger Meier2be7f242012-05-10 09:01:45 +0000175struct ConnContext {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100176public:
Roger Meier2be7f242012-05-10 09:01:45 +0000177 ConnContext(boost::shared_ptr<protocol::TProtocol> in,
178 boost::shared_ptr<protocol::TProtocol> out,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100179 uint32_t id)
180 : input(in), output(out), id(id) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000181
182 boost::shared_ptr<protocol::TProtocol> input;
183 boost::shared_ptr<protocol::TProtocol> output;
184 uint32_t id;
185};
186
187struct CallContext {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100188public:
189 CallContext(ConnContext* context, uint32_t id, const std::string& name)
190 : connContext(context), name(name), id(id) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000191
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100192 ConnContext* connContext;
Roger Meier2be7f242012-05-10 09:01:45 +0000193 std::string name;
194 uint32_t id;
195};
196
197class ServerEventHandler : public server::TServerEventHandler {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100198public:
199 ServerEventHandler(const boost::shared_ptr<EventLog>& log) : nextId_(1), log_(log) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000200
201 virtual void preServe() {}
202
203 virtual void* createContext(boost::shared_ptr<protocol::TProtocol> input,
204 boost::shared_ptr<protocol::TProtocol> output) {
205 ConnContext* context = new ConnContext(input, output, nextId_);
206 ++nextId_;
207 log_->append(EventLog::ET_CONN_CREATED, context->id, 0);
208 return context;
209 }
210
211 virtual void deleteContext(void* serverContext,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100212 boost::shared_ptr<protocol::TProtocol> input,
213 boost::shared_ptr<protocol::TProtocol> output) {
Roger Meier2be7f242012-05-10 09:01:45 +0000214 ConnContext* context = reinterpret_cast<ConnContext*>(serverContext);
215
216 if (input != context->input) {
217 abort();
218 }
219 if (output != context->output) {
220 abort();
221 }
222
223 log_->append(EventLog::ET_CONN_DESTROYED, context->id, 0);
224
225 delete context;
226 }
227
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100228 virtual void processContext(void* serverContext,
229 boost::shared_ptr<transport::TTransport> transport) {
230// TODO: We currently don't test the behavior of the processContext()
231// calls. The various server implementations call processContext() at
232// slightly different times, and it is too annoying to try and account for
233// their various differences.
234//
235// TThreadedServer, TThreadPoolServer, and TSimpleServer usually wait until
236// they see the first byte of a request before calling processContext().
237// However, they don't wait for the first byte of the very first request,
238// and instead immediately call processContext() before any data is
239// received.
240//
241// TNonblockingServer always waits until receiving the full request before
242// calling processContext().
Roger Meier2be7f242012-05-10 09:01:45 +0000243#if 0
244 ConnContext* context = reinterpret_cast<ConnContext*>(serverContext);
245 log_->append(EventLog::ET_PROCESS, context->id, 0);
Konrad Grochowskib3f5ffc2014-11-06 19:32:59 +0100246#else
247 THRIFT_UNUSED_VARIABLE(serverContext);
248 THRIFT_UNUSED_VARIABLE(transport);
Roger Meier2be7f242012-05-10 09:01:45 +0000249#endif
250 }
251
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100252protected:
Roger Meier2be7f242012-05-10 09:01:45 +0000253 uint32_t nextId_;
254 boost::shared_ptr<EventLog> log_;
255};
256
257class ProcessorEventHandler : public TProcessorEventHandler {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100258public:
259 ProcessorEventHandler(const boost::shared_ptr<EventLog>& log) : nextId_(1), log_(log) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000260
261 void* getContext(const char* fnName, void* serverContext) {
262 ConnContext* connContext = reinterpret_cast<ConnContext*>(serverContext);
263
264 CallContext* context = new CallContext(connContext, nextId_, fnName);
265 ++nextId_;
266
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100267 log_->append(EventLog::ET_CALL_STARTED, connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000268 return context;
269 }
270
271 void freeContext(void* ctx, const char* fnName) {
272 CallContext* context = reinterpret_cast<CallContext*>(ctx);
273 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100274 log_->append(EventLog::ET_CALL_FINISHED, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000275 delete context;
276 }
277
278 void preRead(void* ctx, const char* fnName) {
279 CallContext* context = reinterpret_cast<CallContext*>(ctx);
280 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100281 log_->append(EventLog::ET_PRE_READ, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000282 }
283
284 void postRead(void* ctx, const char* fnName, uint32_t bytes) {
Konrad Grochowskib3f5ffc2014-11-06 19:32:59 +0100285 THRIFT_UNUSED_VARIABLE(bytes);
Roger Meier2be7f242012-05-10 09:01:45 +0000286 CallContext* context = reinterpret_cast<CallContext*>(ctx);
287 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100288 log_->append(EventLog::ET_POST_READ, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000289 }
290
291 void preWrite(void* ctx, const char* fnName) {
292 CallContext* context = reinterpret_cast<CallContext*>(ctx);
293 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100294 log_->append(EventLog::ET_PRE_WRITE, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000295 }
296
297 void postWrite(void* ctx, const char* fnName, uint32_t bytes) {
Konrad Grochowskib3f5ffc2014-11-06 19:32:59 +0100298 THRIFT_UNUSED_VARIABLE(bytes);
Roger Meier2be7f242012-05-10 09:01:45 +0000299 CallContext* context = reinterpret_cast<CallContext*>(ctx);
300 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100301 log_->append(EventLog::ET_POST_WRITE, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000302 }
303
304 void asyncComplete(void* ctx, const char* fnName) {
305 CallContext* context = reinterpret_cast<CallContext*>(ctx);
306 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100307 log_->append(EventLog::ET_ASYNC_COMPLETE, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000308 }
309
310 void handlerError(void* ctx, const char* fnName) {
311 CallContext* context = reinterpret_cast<CallContext*>(ctx);
312 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100313 log_->append(EventLog::ET_HANDLER_ERROR, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000314 }
315
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100316protected:
Roger Meier2be7f242012-05-10 09:01:45 +0000317 void checkName(const CallContext* context, const char* fnName) {
318 // Note: we can't use BOOST_CHECK_EQUAL here, since the handler runs in a
319 // different thread from the test functions. Just abort if the names are
320 // different
321 if (context->name != fnName) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100322 fprintf(stderr,
323 "call context name mismatch: \"%s\" != \"%s\"\n",
324 context->name.c_str(),
325 fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000326 fflush(stderr);
327 abort();
328 }
329 }
330
331 uint32_t nextId_;
332 boost::shared_ptr<EventLog> log_;
333};
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100334}
335}
336} // apache::thrift::test
Roger Meier2be7f242012-05-10 09:01:45 +0000337
338#endif // _THRIFT_PROCESSOR_TEST_HANDLERS_H_