blob: 2be262af8bf05873512d3877997bba3525845dd6 [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
26namespace apache { namespace thrift { namespace test {
27
28class ParentHandler : virtual public ParentServiceIf {
29 public:
30 ParentHandler(const boost::shared_ptr<EventLog>& log) :
31 triggerMonitor(&mutex_),
32 generation_(0),
33 wait_(false),
34 log_(log) { }
35
36 int32_t incrementGeneration() {
37 concurrency::Guard g(mutex_);
38 log_->append(EventLog::ET_CALL_INCREMENT_GENERATION, 0, 0);
39 return ++generation_;
40 }
41
42 int32_t getGeneration() {
43 concurrency::Guard g(mutex_);
44 log_->append(EventLog::ET_CALL_GET_GENERATION, 0, 0);
45 return generation_;
46 }
47
48 void addString(const std::string& s) {
49 concurrency::Guard g(mutex_);
50 log_->append(EventLog::ET_CALL_ADD_STRING, 0, 0);
51 strings_.push_back(s);
52 }
53
54 void getStrings(std::vector<std::string>& _return) {
55 concurrency::Guard g(mutex_);
56 log_->append(EventLog::ET_CALL_GET_STRINGS, 0, 0);
57 _return = strings_;
58 }
59
60 void getDataWait(std::string& _return, int32_t length) {
61 concurrency::Guard g(mutex_);
62 log_->append(EventLog::ET_CALL_GET_DATA_WAIT, 0, 0);
63
64 blockUntilTriggered();
65
66 _return.append(length, 'a');
67 }
68
69 void onewayWait() {
70 concurrency::Guard g(mutex_);
71 log_->append(EventLog::ET_CALL_ONEWAY_WAIT, 0, 0);
72
73 blockUntilTriggered();
74 }
75
76 void exceptionWait(const std::string& message) {
77 concurrency::Guard g(mutex_);
78 log_->append(EventLog::ET_CALL_EXCEPTION_WAIT, 0, 0);
79
80 blockUntilTriggered();
81
82 MyError e;
83 e.message = message;
84 throw e;
85 }
86
87 void unexpectedExceptionWait(const std::string& message) {
88 concurrency::Guard g(mutex_);
89 log_->append(EventLog::ET_CALL_UNEXPECTED_EXCEPTION_WAIT, 0, 0);
90
91 blockUntilTriggered();
92
93 MyError e;
94 e.message = message;
95 throw e;
96 }
97
98 /**
99 * After prepareTriggeredCall() is invoked, calls to any of the *Wait()
100 * functions won't return until triggerPendingCalls() is invoked
101 *
102 * This has to be a separate function invoked by the main test thread
103 * in order to to avoid race conditions.
104 */
105 void prepareTriggeredCall() {
106 concurrency::Guard g(mutex_);
107 wait_ = true;
108 }
109
110 /**
111 * Wake up all calls waiting in blockUntilTriggered()
112 */
113 void triggerPendingCalls() {
114 concurrency::Guard g(mutex_);
115 wait_ = false;
116 triggerMonitor.notifyAll();
117 }
118
119 protected:
120 /**
121 * blockUntilTriggered() won't return until triggerPendingCalls() is invoked
122 * in another thread.
123 *
124 * This should only be called when already holding mutex_.
125 */
126 void blockUntilTriggered() {
127 while (wait_) {
128 triggerMonitor.waitForever();
129 }
130
131 // Log an event when we return
132 log_->append(EventLog::ET_WAIT_RETURN, 0, 0);
133 }
134
135 concurrency::Mutex mutex_;
136 concurrency::Monitor triggerMonitor;
137 int32_t generation_;
138 bool wait_;
139 std::vector<std::string> strings_;
140 boost::shared_ptr<EventLog> log_;
141};
142
143class ChildHandler : public ParentHandler, virtual public ChildServiceIf {
144 public:
145 ChildHandler(const boost::shared_ptr<EventLog>& log) :
146 ParentHandler(log),
147 value_(0) {}
148
149 int32_t setValue(int32_t value) {
150 concurrency::Guard g(mutex_);
151 log_->append(EventLog::ET_CALL_SET_VALUE, 0, 0);
152
153 int32_t oldValue = value_;
154 value_ = value;
155 return oldValue;
156 }
157
158 int32_t getValue() {
159 concurrency::Guard g(mutex_);
160 log_->append(EventLog::ET_CALL_GET_VALUE, 0, 0);
161
162 return value_;
163 }
164
165 protected:
166 int32_t value_;
167};
168
169struct ConnContext {
170 public:
171 ConnContext(boost::shared_ptr<protocol::TProtocol> in,
172 boost::shared_ptr<protocol::TProtocol> out,
173 uint32_t id) :
174 input(in),
175 output(out),
176 id(id) {}
177
178 boost::shared_ptr<protocol::TProtocol> input;
179 boost::shared_ptr<protocol::TProtocol> output;
180 uint32_t id;
181};
182
183struct CallContext {
184 public:
185 CallContext(ConnContext *context, uint32_t id, const std::string& name) :
186 connContext(context),
187 name(name),
188 id(id) {}
189
190 ConnContext *connContext;
191 std::string name;
192 uint32_t id;
193};
194
195class ServerEventHandler : public server::TServerEventHandler {
196 public:
197 ServerEventHandler(const boost::shared_ptr<EventLog>& log) :
198 nextId_(1),
199 log_(log) {}
200
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,
212 boost::shared_ptr<protocol::TProtocol>input,
213 boost::shared_ptr<protocol::TProtocol>output) {
214 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
228 virtual void processContext(
229 void* serverContext,
230 boost::shared_ptr<transport::TTransport> transport) {
231 // TODO: We currently don't test the behavior of the processContext()
232 // calls. The various server implementations call processContext() at
233 // slightly different times, and it is too annoying to try and account for
234 // their various differences.
235 //
236 // TThreadedServer, TThreadPoolServer, and TSimpleServer usually wait until
237 // they see the first byte of a request before calling processContext().
238 // However, they don't wait for the first byte of the very first request,
239 // and instead immediately call processContext() before any data is
240 // received.
241 //
242 // TNonblockingServer always waits until receiving the full request before
243 // calling processContext().
244#if 0
245 ConnContext* context = reinterpret_cast<ConnContext*>(serverContext);
246 log_->append(EventLog::ET_PROCESS, context->id, 0);
247#endif
248 }
249
250 protected:
251 uint32_t nextId_;
252 boost::shared_ptr<EventLog> log_;
253};
254
255class ProcessorEventHandler : public TProcessorEventHandler {
256 public:
257 ProcessorEventHandler(const boost::shared_ptr<EventLog>& log) :
258 nextId_(1),
259 log_(log) {}
260
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
267 log_->append(EventLog::ET_CALL_STARTED, connContext->id, context->id,
268 fnName);
269 return context;
270 }
271
272 void freeContext(void* ctx, const char* fnName) {
273 CallContext* context = reinterpret_cast<CallContext*>(ctx);
274 checkName(context, fnName);
275 log_->append(EventLog::ET_CALL_FINISHED, context->connContext->id,
276 context->id, fnName);
277 delete context;
278 }
279
280 void preRead(void* ctx, const char* fnName) {
281 CallContext* context = reinterpret_cast<CallContext*>(ctx);
282 checkName(context, fnName);
283 log_->append(EventLog::ET_PRE_READ, context->connContext->id, context->id,
284 fnName);
285 }
286
287 void postRead(void* ctx, const char* fnName, uint32_t bytes) {
288 CallContext* context = reinterpret_cast<CallContext*>(ctx);
289 checkName(context, fnName);
290 log_->append(EventLog::ET_POST_READ, context->connContext->id, context->id,
291 fnName);
292 }
293
294 void preWrite(void* ctx, const char* fnName) {
295 CallContext* context = reinterpret_cast<CallContext*>(ctx);
296 checkName(context, fnName);
297 log_->append(EventLog::ET_PRE_WRITE, context->connContext->id, context->id,
298 fnName);
299 }
300
301 void postWrite(void* ctx, const char* fnName, uint32_t bytes) {
302 CallContext* context = reinterpret_cast<CallContext*>(ctx);
303 checkName(context, fnName);
304 log_->append(EventLog::ET_POST_WRITE, context->connContext->id,
305 context->id, fnName);
306 }
307
308 void asyncComplete(void* ctx, const char* fnName) {
309 CallContext* context = reinterpret_cast<CallContext*>(ctx);
310 checkName(context, fnName);
311 log_->append(EventLog::ET_ASYNC_COMPLETE, context->connContext->id,
312 context->id, fnName);
313 }
314
315 void handlerError(void* ctx, const char* fnName) {
316 CallContext* context = reinterpret_cast<CallContext*>(ctx);
317 checkName(context, fnName);
318 log_->append(EventLog::ET_HANDLER_ERROR, context->connContext->id,
319 context->id, fnName);
320 }
321
322 protected:
323 void checkName(const CallContext* context, const char* fnName) {
324 // Note: we can't use BOOST_CHECK_EQUAL here, since the handler runs in a
325 // different thread from the test functions. Just abort if the names are
326 // different
327 if (context->name != fnName) {
328 fprintf(stderr, "call context name mismatch: \"%s\" != \"%s\"\n",
329 context->name.c_str(), fnName);
330 fflush(stderr);
331 abort();
332 }
333 }
334
335 uint32_t nextId_;
336 boost::shared_ptr<EventLog> log_;
337};
338
339}}} // apache::thrift::test
340
341#endif // _THRIFT_PROCESSOR_TEST_HANDLERS_H_