blob: d894107dd9aba70d90f4ccc4281f815ed2862515 [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
59 void getDataWait(std::string& _return, int32_t length) {
60 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
142class ChildHandler : public ParentHandler, virtual public ChildServiceIf {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100143public:
144 ChildHandler(const boost::shared_ptr<EventLog>& log) : ParentHandler(log), value_(0) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000145
146 int32_t setValue(int32_t value) {
147 concurrency::Guard g(mutex_);
148 log_->append(EventLog::ET_CALL_SET_VALUE, 0, 0);
149
150 int32_t oldValue = value_;
151 value_ = value;
152 return oldValue;
153 }
154
155 int32_t getValue() {
156 concurrency::Guard g(mutex_);
157 log_->append(EventLog::ET_CALL_GET_VALUE, 0, 0);
158
159 return value_;
160 }
161
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100162protected:
Roger Meier2be7f242012-05-10 09:01:45 +0000163 int32_t value_;
164};
165
166struct ConnContext {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100167public:
Roger Meier2be7f242012-05-10 09:01:45 +0000168 ConnContext(boost::shared_ptr<protocol::TProtocol> in,
169 boost::shared_ptr<protocol::TProtocol> out,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100170 uint32_t id)
171 : input(in), output(out), id(id) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000172
173 boost::shared_ptr<protocol::TProtocol> input;
174 boost::shared_ptr<protocol::TProtocol> output;
175 uint32_t id;
176};
177
178struct CallContext {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100179public:
180 CallContext(ConnContext* context, uint32_t id, const std::string& name)
181 : connContext(context), name(name), id(id) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000182
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100183 ConnContext* connContext;
Roger Meier2be7f242012-05-10 09:01:45 +0000184 std::string name;
185 uint32_t id;
186};
187
188class ServerEventHandler : public server::TServerEventHandler {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100189public:
190 ServerEventHandler(const boost::shared_ptr<EventLog>& log) : nextId_(1), log_(log) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000191
192 virtual void preServe() {}
193
194 virtual void* createContext(boost::shared_ptr<protocol::TProtocol> input,
195 boost::shared_ptr<protocol::TProtocol> output) {
196 ConnContext* context = new ConnContext(input, output, nextId_);
197 ++nextId_;
198 log_->append(EventLog::ET_CONN_CREATED, context->id, 0);
199 return context;
200 }
201
202 virtual void deleteContext(void* serverContext,
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100203 boost::shared_ptr<protocol::TProtocol> input,
204 boost::shared_ptr<protocol::TProtocol> output) {
Roger Meier2be7f242012-05-10 09:01:45 +0000205 ConnContext* context = reinterpret_cast<ConnContext*>(serverContext);
206
207 if (input != context->input) {
208 abort();
209 }
210 if (output != context->output) {
211 abort();
212 }
213
214 log_->append(EventLog::ET_CONN_DESTROYED, context->id, 0);
215
216 delete context;
217 }
218
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100219 virtual void processContext(void* serverContext,
220 boost::shared_ptr<transport::TTransport> transport) {
221// TODO: We currently don't test the behavior of the processContext()
222// calls. The various server implementations call processContext() at
223// slightly different times, and it is too annoying to try and account for
224// their various differences.
225//
226// TThreadedServer, TThreadPoolServer, and TSimpleServer usually wait until
227// they see the first byte of a request before calling processContext().
228// However, they don't wait for the first byte of the very first request,
229// and instead immediately call processContext() before any data is
230// received.
231//
232// TNonblockingServer always waits until receiving the full request before
233// calling processContext().
Roger Meier2be7f242012-05-10 09:01:45 +0000234#if 0
235 ConnContext* context = reinterpret_cast<ConnContext*>(serverContext);
236 log_->append(EventLog::ET_PROCESS, context->id, 0);
Konrad Grochowskib3f5ffc2014-11-06 19:32:59 +0100237#else
238 THRIFT_UNUSED_VARIABLE(serverContext);
239 THRIFT_UNUSED_VARIABLE(transport);
Roger Meier2be7f242012-05-10 09:01:45 +0000240#endif
241 }
242
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100243protected:
Roger Meier2be7f242012-05-10 09:01:45 +0000244 uint32_t nextId_;
245 boost::shared_ptr<EventLog> log_;
246};
247
248class ProcessorEventHandler : public TProcessorEventHandler {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100249public:
250 ProcessorEventHandler(const boost::shared_ptr<EventLog>& log) : nextId_(1), log_(log) {}
Roger Meier2be7f242012-05-10 09:01:45 +0000251
252 void* getContext(const char* fnName, void* serverContext) {
253 ConnContext* connContext = reinterpret_cast<ConnContext*>(serverContext);
254
255 CallContext* context = new CallContext(connContext, nextId_, fnName);
256 ++nextId_;
257
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100258 log_->append(EventLog::ET_CALL_STARTED, connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000259 return context;
260 }
261
262 void freeContext(void* ctx, const char* fnName) {
263 CallContext* context = reinterpret_cast<CallContext*>(ctx);
264 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100265 log_->append(EventLog::ET_CALL_FINISHED, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000266 delete context;
267 }
268
269 void preRead(void* ctx, const char* fnName) {
270 CallContext* context = reinterpret_cast<CallContext*>(ctx);
271 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100272 log_->append(EventLog::ET_PRE_READ, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000273 }
274
275 void postRead(void* ctx, const char* fnName, uint32_t bytes) {
Konrad Grochowskib3f5ffc2014-11-06 19:32:59 +0100276 THRIFT_UNUSED_VARIABLE(bytes);
Roger Meier2be7f242012-05-10 09:01:45 +0000277 CallContext* context = reinterpret_cast<CallContext*>(ctx);
278 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100279 log_->append(EventLog::ET_POST_READ, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000280 }
281
282 void preWrite(void* ctx, const char* fnName) {
283 CallContext* context = reinterpret_cast<CallContext*>(ctx);
284 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100285 log_->append(EventLog::ET_PRE_WRITE, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000286 }
287
288 void postWrite(void* ctx, const char* fnName, uint32_t bytes) {
Konrad Grochowskib3f5ffc2014-11-06 19:32:59 +0100289 THRIFT_UNUSED_VARIABLE(bytes);
Roger Meier2be7f242012-05-10 09:01:45 +0000290 CallContext* context = reinterpret_cast<CallContext*>(ctx);
291 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100292 log_->append(EventLog::ET_POST_WRITE, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000293 }
294
295 void asyncComplete(void* ctx, const char* fnName) {
296 CallContext* context = reinterpret_cast<CallContext*>(ctx);
297 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100298 log_->append(EventLog::ET_ASYNC_COMPLETE, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000299 }
300
301 void handlerError(void* ctx, const char* fnName) {
302 CallContext* context = reinterpret_cast<CallContext*>(ctx);
303 checkName(context, fnName);
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100304 log_->append(EventLog::ET_HANDLER_ERROR, context->connContext->id, context->id, fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000305 }
306
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100307protected:
Roger Meier2be7f242012-05-10 09:01:45 +0000308 void checkName(const CallContext* context, const char* fnName) {
309 // Note: we can't use BOOST_CHECK_EQUAL here, since the handler runs in a
310 // different thread from the test functions. Just abort if the names are
311 // different
312 if (context->name != fnName) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100313 fprintf(stderr,
314 "call context name mismatch: \"%s\" != \"%s\"\n",
315 context->name.c_str(),
316 fnName);
Roger Meier2be7f242012-05-10 09:01:45 +0000317 fflush(stderr);
318 abort();
319 }
320 }
321
322 uint32_t nextId_;
323 boost::shared_ptr<EventLog> log_;
324};
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100325}
326}
327} // apache::thrift::test
Roger Meier2be7f242012-05-10 09:01:45 +0000328
329#endif // _THRIFT_PROCESSOR_TEST_HANDLERS_H_