1 /*
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
20 /*
21 * This file contains tests that ensure TProcessorEventHandler and
22 * TServerEventHandler are invoked properly by the various server
23 * implementations.
24 */
25
26 #include <boost/test/unit_test.hpp>
27
28 #include <thrift/concurrency/ThreadFactory.h>
29 #include <thrift/concurrency/Monitor.h>
30 #include <thrift/protocol/TBinaryProtocol.h>
31 #include <thrift/server/TThreadedServer.h>
32 #include <thrift/server/TThreadPoolServer.h>
33 #include <thrift/server/TNonblockingServer.h>
34 #include <thrift/server/TSimpleServer.h>
35 #include <thrift/transport/TSocket.h>
36 #include <thrift/transport/TNonblockingServerSocket.h>
37
38 #include "EventLog.h"
39 #include "ServerThread.h"
40 #include "Handlers.h"
41 #include "gen-cpp/ChildService.h"
42
43 using namespace apache::thrift;
44 using namespace apache::thrift::concurrency;
45 using namespace apache::thrift::protocol;
46 using namespace apache::thrift::server;
47 using namespace apache::thrift::test;
48 using namespace apache::thrift::transport;
49 using std::string;
50 using std::vector;
51
52 /*
53 * Traits classes that encapsulate how to create various types of servers.
54 */
55
56 class TSimpleServerTraits {
57 public:
58 typedef TSimpleServer ServerType;
59
createServer(const std::shared_ptr<TProcessor> & processor,uint16_t port,const std::shared_ptr<TTransportFactory> & transportFactory,const std::shared_ptr<TProtocolFactory> & protocolFactory)60 std::shared_ptr<TSimpleServer> createServer(
61 const std::shared_ptr<TProcessor>& processor,
62 uint16_t port,
63 const std::shared_ptr<TTransportFactory>& transportFactory,
64 const std::shared_ptr<TProtocolFactory>& protocolFactory) {
65 std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
66 return std::shared_ptr<TSimpleServer>(
67 new TSimpleServer(processor, socket, transportFactory, protocolFactory));
68 }
69 };
70
71 class TThreadedServerTraits {
72 public:
73 typedef TThreadedServer ServerType;
74
createServer(const std::shared_ptr<TProcessor> & processor,uint16_t port,const std::shared_ptr<TTransportFactory> & transportFactory,const std::shared_ptr<TProtocolFactory> & protocolFactory)75 std::shared_ptr<TThreadedServer> createServer(
76 const std::shared_ptr<TProcessor>& processor,
77 uint16_t port,
78 const std::shared_ptr<TTransportFactory>& transportFactory,
79 const std::shared_ptr<TProtocolFactory>& protocolFactory) {
80 std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
81 return std::shared_ptr<TThreadedServer>(
82 new TThreadedServer(processor, socket, transportFactory, protocolFactory));
83 }
84 };
85
86 class TThreadPoolServerTraits {
87 public:
88 typedef TThreadPoolServer ServerType;
89
createServer(const std::shared_ptr<TProcessor> & processor,uint16_t port,const std::shared_ptr<TTransportFactory> & transportFactory,const std::shared_ptr<TProtocolFactory> & protocolFactory)90 std::shared_ptr<TThreadPoolServer> createServer(
91 const std::shared_ptr<TProcessor>& processor,
92 uint16_t port,
93 const std::shared_ptr<TTransportFactory>& transportFactory,
94 const std::shared_ptr<TProtocolFactory>& protocolFactory) {
95 std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
96
97 std::shared_ptr<ThreadFactory> threadFactory(new ThreadFactory);
98 std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(8);
99 threadManager->threadFactory(threadFactory);
100 threadManager->start();
101
102 return std::shared_ptr<TThreadPoolServer>(
103 new TThreadPoolServer(processor, socket, transportFactory, protocolFactory, threadManager));
104 }
105 };
106
107 class TNonblockingServerTraits {
108 public:
109 typedef TNonblockingServer ServerType;
110
createServer(const std::shared_ptr<TProcessor> & processor,uint16_t port,const std::shared_ptr<TTransportFactory> & transportFactory,const std::shared_ptr<TProtocolFactory> & protocolFactory)111 std::shared_ptr<TNonblockingServer> createServer(
112 const std::shared_ptr<TProcessor>& processor,
113 uint16_t port,
114 const std::shared_ptr<TTransportFactory>& transportFactory,
115 const std::shared_ptr<TProtocolFactory>& protocolFactory) {
116 // TNonblockingServer automatically uses TFramedTransport.
117 // Raise an exception if the supplied transport factory is not a
118 // TFramedTransportFactory
119 auto* framedFactory
120 = dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
121 if (framedFactory == nullptr) {
122 throw TException("TNonblockingServer must use TFramedTransport");
123 }
124
125 std::shared_ptr<TNonblockingServerSocket> socket(new TNonblockingServerSocket(port));
126 std::shared_ptr<ThreadFactory> threadFactory(new ThreadFactory);
127 std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(8);
128 threadManager->threadFactory(threadFactory);
129 threadManager->start();
130
131 return std::shared_ptr<TNonblockingServer>(
132 new TNonblockingServer(processor, protocolFactory, socket, threadManager));
133 }
134 };
135
136 class TNonblockingServerNoThreadsTraits {
137 public:
138 typedef TNonblockingServer ServerType;
139
createServer(const std::shared_ptr<TProcessor> & processor,uint16_t port,const std::shared_ptr<TTransportFactory> & transportFactory,const std::shared_ptr<TProtocolFactory> & protocolFactory)140 std::shared_ptr<TNonblockingServer> createServer(
141 const std::shared_ptr<TProcessor>& processor,
142 uint16_t port,
143 const std::shared_ptr<TTransportFactory>& transportFactory,
144 const std::shared_ptr<TProtocolFactory>& protocolFactory) {
145 // TNonblockingServer automatically uses TFramedTransport.
146 // Raise an exception if the supplied transport factory is not a
147 // TFramedTransportFactory
148 auto* framedFactory
149 = dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
150 if (framedFactory == nullptr) {
151 throw TException("TNonblockingServer must use TFramedTransport");
152 }
153
154 std::shared_ptr<TNonblockingServerSocket> socket(new TNonblockingServerSocket(port));
155 // Use a NULL ThreadManager
156 std::shared_ptr<ThreadManager> threadManager;
157 return std::shared_ptr<TNonblockingServer>(
158 new TNonblockingServer(processor, protocolFactory, socket, threadManager));
159 }
160 };
161
162 /*
163 * Traits classes for controlling if we instantiate templated or generic
164 * protocol factories, processors, clients, etc.
165 *
166 * The goal is to allow the outer test code to select which server type is
167 * being tested, and whether or not we are testing the templated classes, or
168 * the generic classes.
169 *
170 * Each specific test case can control whether we create a child or parent
171 * server, and whether we use TFramedTransport or TBufferedTransport.
172 */
173
174 class UntemplatedTraits {
175 public:
176 typedef TBinaryProtocolFactory ProtocolFactory;
177 typedef TBinaryProtocol Protocol;
178
179 typedef ParentServiceProcessor ParentProcessor;
180 typedef ChildServiceProcessor ChildProcessor;
181 typedef ParentServiceClient ParentClient;
182 typedef ChildServiceClient ChildClient;
183 };
184
185 class TemplatedTraits {
186 public:
187 typedef TBinaryProtocolFactoryT<TBufferBase> ProtocolFactory;
188 typedef TBinaryProtocolT<TBufferBase> Protocol;
189
190 typedef ParentServiceProcessorT<Protocol> ParentProcessor;
191 typedef ChildServiceProcessorT<Protocol> ChildProcessor;
192 typedef ParentServiceClientT<Protocol> ParentClient;
193 typedef ChildServiceClientT<Protocol> ChildClient;
194 };
195
196 template <typename TemplateTraits_>
197 class ParentServiceTraits {
198 public:
199 typedef typename TemplateTraits_::ParentProcessor Processor;
200 typedef typename TemplateTraits_::ParentClient Client;
201 typedef ParentHandler Handler;
202
203 typedef typename TemplateTraits_::ProtocolFactory ProtocolFactory;
204 typedef typename TemplateTraits_::Protocol Protocol;
205 };
206
207 template <typename TemplateTraits_>
208 class ChildServiceTraits {
209 public:
210 typedef typename TemplateTraits_::ChildProcessor Processor;
211 typedef typename TemplateTraits_::ChildClient Client;
212 typedef ChildHandler Handler;
213
214 typedef typename TemplateTraits_::ProtocolFactory ProtocolFactory;
215 typedef typename TemplateTraits_::Protocol Protocol;
216 };
217
218 // TODO: It would be nicer if the TTransportFactory types defined a typedef,
219 // to allow us to figure out the exact transport type without having to pass it
220 // in as a separate template parameter here.
221 //
222 // It would also be niec if they used covariant return types. Unfortunately,
223 // since they return shared_ptr instead of raw pointers, covariant return types
224 // won't work.
225 template <typename ServerTraits_,
226 typename ServiceTraits_,
227 typename TransportFactory_ = TFramedTransportFactory,
228 typename Transport_ = TFramedTransport>
229 class ServiceState : public ServerState {
230 public:
231 typedef typename ServiceTraits_::Processor Processor;
232 typedef typename ServiceTraits_::Client Client;
233 typedef typename ServiceTraits_::Handler Handler;
234
ServiceState()235 ServiceState()
236 : port_(0),
237 log_(new EventLog),
238 handler_(new Handler(log_)),
239 processor_(new Processor(handler_)),
240 transportFactory_(new TransportFactory_),
241 protocolFactory_(new typename ServiceTraits_::ProtocolFactory),
242 serverEventHandler_(new ServerEventHandler(log_)),
243 processorEventHandler_(new ProcessorEventHandler(log_)) {
244 processor_->setEventHandler(processorEventHandler_);
245 }
246
createServer(uint16_t port)247 std::shared_ptr<TServer> createServer(uint16_t port) override {
248 ServerTraits_ serverTraits;
249 return serverTraits.createServer(processor_, port, transportFactory_, protocolFactory_);
250 }
251
getServerEventHandler()252 std::shared_ptr<TServerEventHandler> getServerEventHandler() override { return serverEventHandler_; }
253
bindSuccessful(uint16_t port)254 void bindSuccessful(uint16_t port) override { port_ = port; }
255
getPort() const256 uint16_t getPort() const { return port_; }
257
getLog() const258 const std::shared_ptr<EventLog>& getLog() const { return log_; }
259
getHandler() const260 const std::shared_ptr<Handler>& getHandler() const { return handler_; }
261
createClient()262 std::shared_ptr<Client> createClient() {
263 typedef typename ServiceTraits_::Protocol Protocol;
264
265 std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port_));
266 std::shared_ptr<Transport_> transport(new Transport_(socket));
267 std::shared_ptr<Protocol> protocol(new Protocol(transport));
268 transport->open();
269
270 std::shared_ptr<Client> client(new Client(protocol));
271 return client;
272 }
273
274 private:
275 uint16_t port_;
276 std::shared_ptr<EventLog> log_;
277 std::shared_ptr<Handler> handler_;
278 std::shared_ptr<Processor> processor_;
279 std::shared_ptr<TTransportFactory> transportFactory_;
280 std::shared_ptr<TProtocolFactory> protocolFactory_;
281 std::shared_ptr<TServerEventHandler> serverEventHandler_;
282 std::shared_ptr<TProcessorEventHandler> processorEventHandler_;
283 };
284
285 /**
286 * Check that there are no more events in the log
287 */
checkNoEvents(const std::shared_ptr<EventLog> & log)288 void checkNoEvents(const std::shared_ptr<EventLog>& log) {
289 // Wait for an event with a very short timeout period. We don't expect
290 // anything to be present, so we will normally wait for the full timeout.
291 // On the other hand, a non-zero timeout is nice since it does give a short
292 // window for events to arrive in case there is a problem.
293 Event event = log->waitForEvent(10);
294 BOOST_CHECK_EQUAL(EventLog::ET_LOG_END, event.type);
295 }
296
297 /**
298 * Check for the events that should be logged when a new connection is created.
299 *
300 * Returns the connection ID allocated by the server.
301 */
checkNewConnEvents(const std::shared_ptr<EventLog> & log)302 uint32_t checkNewConnEvents(const std::shared_ptr<EventLog>& log) {
303 // Check for an ET_CONN_CREATED event
304 Event event = log->waitForEvent(2500);
305 BOOST_CHECK_EQUAL(EventLog::ET_CONN_CREATED, event.type);
306
307 // Some servers call the processContext() hook immediately.
308 // Others (TNonblockingServer) only call it once a full request is received.
309 // We don't check for it yet, to allow either behavior.
310
311 return event.connectionId;
312 }
313
314 /**
315 * Check for the events that should be logged when a connection is closed.
316 */
checkCloseEvents(const std::shared_ptr<EventLog> & log,uint32_t connId)317 void checkCloseEvents(const std::shared_ptr<EventLog>& log, uint32_t connId) {
318 // Check for an ET_CONN_DESTROYED event
319 Event event = log->waitForEvent();
320 BOOST_CHECK_EQUAL(EventLog::ET_CONN_DESTROYED, event.type);
321 BOOST_CHECK_EQUAL(connId, event.connectionId);
322
323 // Make sure there are no more events
324 checkNoEvents(log);
325 }
326
327 /**
328 * Check for the events that should be logged when a call is received
329 * and the handler is invoked.
330 *
331 * It does not check for anything after the handler invocation.
332 *
333 * Returns the call ID allocated by the server.
334 */
checkCallHandlerEvents(const std::shared_ptr<EventLog> & log,uint32_t connId,EventType callType,const string & callName)335 uint32_t checkCallHandlerEvents(const std::shared_ptr<EventLog>& log,
336 uint32_t connId,
337 EventType callType,
338 const string& callName) {
339 // Call started
340 Event event = log->waitForEvent();
341 BOOST_CHECK_EQUAL(EventLog::ET_CALL_STARTED, event.type);
342 BOOST_CHECK_EQUAL(connId, event.connectionId);
343 BOOST_CHECK_EQUAL(callName, event.message);
344 uint32_t callId = event.callId;
345
346 // Pre-read
347 event = log->waitForEvent();
348 BOOST_CHECK_EQUAL(EventLog::ET_PRE_READ, event.type);
349 BOOST_CHECK_EQUAL(connId, event.connectionId);
350 BOOST_CHECK_EQUAL(callId, event.callId);
351 BOOST_CHECK_EQUAL(callName, event.message);
352
353 // Post-read
354 event = log->waitForEvent();
355 BOOST_CHECK_EQUAL(EventLog::ET_POST_READ, event.type);
356 BOOST_CHECK_EQUAL(connId, event.connectionId);
357 BOOST_CHECK_EQUAL(callId, event.callId);
358 BOOST_CHECK_EQUAL(callName, event.message);
359
360 // Handler invocation
361 event = log->waitForEvent();
362 BOOST_CHECK_EQUAL(callType, event.type);
363 // The handler doesn't have any connection or call context,
364 // so the connectionId and callId in this event aren't valid
365
366 return callId;
367 }
368
369 /**
370 * Check for the events that should be after a handler returns.
371 */
checkCallPostHandlerEvents(const std::shared_ptr<EventLog> & log,uint32_t connId,uint32_t callId,const string & callName)372 void checkCallPostHandlerEvents(const std::shared_ptr<EventLog>& log,
373 uint32_t connId,
374 uint32_t callId,
375 const string& callName) {
376 // Pre-write
377 Event event = log->waitForEvent();
378 BOOST_CHECK_EQUAL(EventLog::ET_PRE_WRITE, event.type);
379 BOOST_CHECK_EQUAL(connId, event.connectionId);
380 BOOST_CHECK_EQUAL(callId, event.callId);
381 BOOST_CHECK_EQUAL(callName, event.message);
382
383 // Post-write
384 event = log->waitForEvent();
385 BOOST_CHECK_EQUAL(EventLog::ET_POST_WRITE, event.type);
386 BOOST_CHECK_EQUAL(connId, event.connectionId);
387 BOOST_CHECK_EQUAL(callId, event.callId);
388 BOOST_CHECK_EQUAL(callName, event.message);
389
390 // Call finished
391 event = log->waitForEvent();
392 BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
393 BOOST_CHECK_EQUAL(connId, event.connectionId);
394 BOOST_CHECK_EQUAL(callId, event.callId);
395 BOOST_CHECK_EQUAL(callName, event.message);
396
397 // It is acceptable for servers to call processContext() again immediately
398 // to start waiting on the next request. However, some servers wait before
399 // getting either a partial request or the full request before calling
400 // processContext(). We don't check for the next call to processContext()
401 // yet.
402 }
403
404 /**
405 * Check for the events that should be logged when a call is made.
406 *
407 * This just calls checkCallHandlerEvents() followed by
408 * checkCallPostHandlerEvents().
409 *
410 * Returns the call ID allocated by the server.
411 */
checkCallEvents(const std::shared_ptr<EventLog> & log,uint32_t connId,EventType callType,const string & callName)412 uint32_t checkCallEvents(const std::shared_ptr<EventLog>& log,
413 uint32_t connId,
414 EventType callType,
415 const string& callName) {
416 uint32_t callId = checkCallHandlerEvents(log, connId, callType, callName);
417 checkCallPostHandlerEvents(log, connId, callId, callName);
418
419 return callId;
420 }
421
422 /*
423 * Test functions
424 */
425
426 template <typename State_>
testParentService(const std::shared_ptr<State_> & state)427 void testParentService(const std::shared_ptr<State_>& state) {
428 std::shared_ptr<typename State_::Client> client = state->createClient();
429
430 int32_t gen = client->getGeneration();
431 int32_t newGen = client->incrementGeneration();
432 BOOST_CHECK_EQUAL(gen + 1, newGen);
433 newGen = client->getGeneration();
434 BOOST_CHECK_EQUAL(gen + 1, newGen);
435
436 client->addString("foo");
437 client->addString("bar");
438 client->addString("asdf");
439
440 vector<string> strings;
441 client->getStrings(strings);
442 BOOST_REQUIRE_EQUAL(3, strings.size());
443 BOOST_REQUIRE_EQUAL("foo", strings[0]);
444 BOOST_REQUIRE_EQUAL("bar", strings[1]);
445 BOOST_REQUIRE_EQUAL("asdf", strings[2]);
446 }
447
448 template <typename State_>
testChildService(const std::shared_ptr<State_> & state)449 void testChildService(const std::shared_ptr<State_>& state) {
450 std::shared_ptr<typename State_::Client> client = state->createClient();
451
452 // Test calling some of the parent methids via the a child client
453 int32_t gen = client->getGeneration();
454 int32_t newGen = client->incrementGeneration();
455 BOOST_CHECK_EQUAL(gen + 1, newGen);
456 newGen = client->getGeneration();
457 BOOST_CHECK_EQUAL(gen + 1, newGen);
458
459 // Test some of the child methods
460 client->setValue(10);
461 BOOST_CHECK_EQUAL(10, client->getValue());
462 BOOST_CHECK_EQUAL(10, client->setValue(99));
463 BOOST_CHECK_EQUAL(99, client->getValue());
464 }
465
466 template <typename ServerTraits, typename TemplateTraits>
testBasicService()467 void testBasicService() {
468 typedef ServiceState<ServerTraits, ParentServiceTraits<TemplateTraits> > State;
469
470 // Start the server
471 std::shared_ptr<State> state(new State);
472 ServerThread serverThread(state, true);
473
474 testParentService(state);
475 }
476
477 template <typename ServerTraits, typename TemplateTraits>
testInheritedService()478 void testInheritedService() {
479 typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
480
481 // Start the server
482 std::shared_ptr<State> state(new State);
483 ServerThread serverThread(state, true);
484
485 testParentService(state);
486 testChildService(state);
487 }
488
489 /**
490 * Test to make sure that the TServerEventHandler and TProcessorEventHandler
491 * methods are invoked in the correct order with the actual events.
492 */
493 template <typename ServerTraits, typename TemplateTraits>
testEventSequencing()494 void testEventSequencing() {
495 // We use TBufferedTransport for this test, instead of TFramedTransport.
496 // This way the server will start processing data as soon as it is received,
497 // instead of waiting for the full request. This is necessary so we can
498 // separate the preRead() and postRead() events.
499 typedef ServiceState<ServerTraits,
500 ChildServiceTraits<TemplateTraits>,
501 TBufferedTransportFactory,
502 TBufferedTransport> State;
503
504 // Start the server
505 std::shared_ptr<State> state(new State);
506 ServerThread serverThread(state, true);
507
508 const std::shared_ptr<EventLog>& log = state->getLog();
509
510 // Make sure we're at the end of the log
511 checkNoEvents(log);
512
513 state->getHandler()->prepareTriggeredCall();
514
515 // Make sure createContext() is called after a connection has been
516 // established. We open a plain socket instead of creating a client.
517 std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", state->getPort()));
518 socket->open();
519
520 // Make sure the proper events occurred after a new connection
521 uint32_t connId = checkNewConnEvents(log);
522
523 // Send a message header. We manually construct the request so that we
524 // can test the timing for the preRead() call.
525 string requestName = "getDataWait";
526 string eventName = "ParentService.getDataWait";
527 auto seqid = int32_t(time(nullptr));
528 TBinaryProtocol protocol(socket);
529 protocol.writeMessageBegin(requestName, T_CALL, seqid);
530 socket->flush();
531
532 // Make sure we saw the call started and pre-read events
533 Event event = log->waitForEvent();
534 BOOST_CHECK_EQUAL(EventLog::ET_CALL_STARTED, event.type);
535 BOOST_CHECK_EQUAL(eventName, event.message);
536 BOOST_CHECK_EQUAL(connId, event.connectionId);
537 uint32_t callId = event.callId;
538
539 event = log->waitForEvent();
540 BOOST_CHECK_EQUAL(EventLog::ET_PRE_READ, event.type);
541 BOOST_CHECK_EQUAL(eventName, event.message);
542 BOOST_CHECK_EQUAL(connId, event.connectionId);
543 BOOST_CHECK_EQUAL(callId, event.callId);
544
545 // Make sure there are no new events
546 checkNoEvents(log);
547
548 // Send the rest of the request
549 protocol.writeStructBegin("ParentService_getDataNotified_pargs");
550 protocol.writeFieldBegin("length", apache::thrift::protocol::T_I32, 1);
551 protocol.writeI32(8 * 1024 * 1024);
552 protocol.writeFieldEnd();
553 protocol.writeFieldStop();
554 protocol.writeStructEnd();
555 protocol.writeMessageEnd();
556 socket->writeEnd();
557 socket->flush();
558
559 // We should then see postRead()
560 event = log->waitForEvent();
561 BOOST_CHECK_EQUAL(EventLog::ET_POST_READ, event.type);
562 BOOST_CHECK_EQUAL(eventName, event.message);
563 BOOST_CHECK_EQUAL(connId, event.connectionId);
564 BOOST_CHECK_EQUAL(callId, event.callId);
565
566 // Then the handler should be invoked
567 event = log->waitForEvent();
568 BOOST_CHECK_EQUAL(EventLog::ET_CALL_GET_DATA_WAIT, event.type);
569
570 // The handler won't respond until we notify it.
571 // Make sure there are no more events.
572 checkNoEvents(log);
573
574 // Notify the handler that it should return
575 // We just use a global lock for now, since it is easiest
576 state->getHandler()->triggerPendingCalls();
577
578 // The handler will log a separate event before it returns
579 event = log->waitForEvent();
580 BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
581
582 // We should then see preWrite()
583 event = log->waitForEvent();
584 BOOST_CHECK_EQUAL(EventLog::ET_PRE_WRITE, event.type);
585 BOOST_CHECK_EQUAL(eventName, event.message);
586 BOOST_CHECK_EQUAL(connId, event.connectionId);
587 BOOST_CHECK_EQUAL(callId, event.callId);
588
589 // We requested more data than can be buffered, and we aren't reading it,
590 // so the server shouldn't be able to finish its write yet.
591 // Make sure there are no more events.
592 checkNoEvents(log);
593
594 // Read the response header
595 string responseName;
596 int32_t responseSeqid = 0;
597 apache::thrift::protocol::TMessageType responseType;
598 protocol.readMessageBegin(responseName, responseType, responseSeqid);
599 BOOST_CHECK_EQUAL(responseSeqid, seqid);
600 BOOST_CHECK_EQUAL(requestName, responseName);
601 BOOST_CHECK_EQUAL(responseType, T_REPLY);
602 // Read the body. We just ignore it for now.
603 protocol.skip(T_STRUCT);
604
605 // Now that we have read, the server should have finished sending the data
606 // and called the postWrite() handler
607 event = log->waitForEvent();
608 BOOST_CHECK_EQUAL(EventLog::ET_POST_WRITE, event.type);
609 BOOST_CHECK_EQUAL(eventName, event.message);
610 BOOST_CHECK_EQUAL(connId, event.connectionId);
611 BOOST_CHECK_EQUAL(callId, event.callId);
612
613 // Call finished should be last
614 event = log->waitForEvent();
615 BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
616 BOOST_CHECK_EQUAL(eventName, event.message);
617 BOOST_CHECK_EQUAL(connId, event.connectionId);
618 BOOST_CHECK_EQUAL(callId, event.callId);
619
620 // There should be no more events
621 checkNoEvents(log);
622
623 // Close the connection, and make sure we get a connection destroyed event
624 socket->close();
625 event = log->waitForEvent();
626 BOOST_CHECK_EQUAL(EventLog::ET_CONN_DESTROYED, event.type);
627 BOOST_CHECK_EQUAL(connId, event.connectionId);
628
629 // There should be no more events
630 checkNoEvents(log);
631 }
632
633 template <typename ServerTraits, typename TemplateTraits>
testSeparateConnections()634 void testSeparateConnections() {
635 typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
636
637 // Start the server
638 std::shared_ptr<State> state(new State);
639 ServerThread serverThread(state, true);
640
641 const std::shared_ptr<EventLog>& log = state->getLog();
642
643 // Create a client
644 std::shared_ptr<typename State::Client> client1 = state->createClient();
645
646 // Make sure the expected events were logged
647 uint32_t client1Id = checkNewConnEvents(log);
648
649 // Create a second client
650 std::shared_ptr<typename State::Client> client2 = state->createClient();
651
652 // Make sure the expected events were logged
653 uint32_t client2Id = checkNewConnEvents(log);
654
655 // The two connections should have different IDs
656 BOOST_CHECK_NE(client1Id, client2Id);
657
658 // Make a call, and check for the proper events
659 int32_t value = 5;
660 client1->setValue(value);
661 uint32_t call1
662 = checkCallEvents(log, client1Id, EventLog::ET_CALL_SET_VALUE, "ChildService.setValue");
663
664 // Make a call with client2
665 int32_t v = client2->getValue();
666 BOOST_CHECK_EQUAL(value, v);
667 checkCallEvents(log, client2Id, EventLog::ET_CALL_GET_VALUE, "ChildService.getValue");
668
669 // Make another call with client1
670 v = client1->getValue();
671 BOOST_CHECK_EQUAL(value, v);
672 uint32_t call2
673 = checkCallEvents(log, client1Id, EventLog::ET_CALL_GET_VALUE, "ChildService.getValue");
674 BOOST_CHECK_NE(call1, call2);
675
676 // Close the second client, and check for the appropriate events
677 client2.reset();
678 checkCloseEvents(log, client2Id);
679 }
680
681 template <typename ServerTraits, typename TemplateTraits>
testOnewayCall()682 void testOnewayCall() {
683 typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
684
685 // Start the server
686 std::shared_ptr<State> state(new State);
687 ServerThread serverThread(state, true);
688
689 const std::shared_ptr<EventLog>& log = state->getLog();
690
691 // Create a client
692 std::shared_ptr<typename State::Client> client = state->createClient();
693 uint32_t connId = checkNewConnEvents(log);
694
695 // Make a oneway call
696 // It should return immediately, even though the server's handler
697 // won't return right away
698 state->getHandler()->prepareTriggeredCall();
699 client->onewayWait();
700 string callName = "ParentService.onewayWait";
701 uint32_t callId = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_ONEWAY_WAIT, callName);
702
703 // There shouldn't be any more events
704 checkNoEvents(log);
705
706 // Trigger the handler to return
707 state->getHandler()->triggerPendingCalls();
708
709 // The handler will log an ET_WAIT_RETURN event when it wakes up
710 Event event = log->waitForEvent();
711 BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
712
713 // Now we should see the async complete event, then call finished
714 event = log->waitForEvent();
715 BOOST_CHECK_EQUAL(EventLog::ET_ASYNC_COMPLETE, event.type);
716 BOOST_CHECK_EQUAL(connId, event.connectionId);
717 BOOST_CHECK_EQUAL(callId, event.callId);
718 BOOST_CHECK_EQUAL(callName, event.message);
719
720 event = log->waitForEvent();
721 BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
722 BOOST_CHECK_EQUAL(connId, event.connectionId);
723 BOOST_CHECK_EQUAL(callId, event.callId);
724 BOOST_CHECK_EQUAL(callName, event.message);
725
726 // Destroy the client, and check for connection closed events
727 client.reset();
728 checkCloseEvents(log, connId);
729
730 checkNoEvents(log);
731 }
732
733 template <typename ServerTraits, typename TemplateTraits>
testExpectedError()734 void testExpectedError() {
735 typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
736
737 // Start the server
738 std::shared_ptr<State> state(new State);
739 ServerThread serverThread(state, true);
740
741 const std::shared_ptr<EventLog>& log = state->getLog();
742
743 // Create a client
744 std::shared_ptr<typename State::Client> client = state->createClient();
745 uint32_t connId = checkNewConnEvents(log);
746
747 // Send the exceptionWait() call
748 state->getHandler()->prepareTriggeredCall();
749 string message = "test 1234 test";
750 client->send_exceptionWait(message);
751 string callName = "ParentService.exceptionWait";
752 uint32_t callId = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_EXCEPTION_WAIT, callName);
753
754 // There shouldn't be any more events
755 checkNoEvents(log);
756
757 // Trigger the handler to return
758 state->getHandler()->triggerPendingCalls();
759
760 // The handler will log an ET_WAIT_RETURN event when it wakes up
761 Event event = log->waitForEvent();
762 BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
763
764 // Now receive the response
765 try {
766 client->recv_exceptionWait();
767 BOOST_FAIL("expected MyError to be thrown");
768 } catch (const MyError& e) {
769 BOOST_CHECK_EQUAL(message, e.message);
770 // Check if std::exception::what() is handled properly
771 size_t message_pos = string(e.what()).find("TException - service has thrown: MyError");
772 BOOST_CHECK_NE(message_pos, string::npos);
773 }
774
775 // Now we should see the events for a normal call finish
776 checkCallPostHandlerEvents(log, connId, callId, callName);
777
778 // There shouldn't be any more events
779 checkNoEvents(log);
780
781 // Destroy the client, and check for connection closed events
782 client.reset();
783 checkCloseEvents(log, connId);
784
785 checkNoEvents(log);
786 }
787
788 template <typename ServerTraits, typename TemplateTraits>
testUnexpectedError()789 void testUnexpectedError() {
790 typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
791
792 // Start the server
793 std::shared_ptr<State> state(new State);
794 ServerThread serverThread(state, true);
795
796 const std::shared_ptr<EventLog>& log = state->getLog();
797
798 // Create a client
799 std::shared_ptr<typename State::Client> client = state->createClient();
800 uint32_t connId = checkNewConnEvents(log);
801
802 // Send the unexpectedExceptionWait() call
803 state->getHandler()->prepareTriggeredCall();
804 string message = "1234 test 5678";
805 client->send_unexpectedExceptionWait(message);
806 string callName = "ParentService.unexpectedExceptionWait";
807 uint32_t callId
808 = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_UNEXPECTED_EXCEPTION_WAIT, callName);
809
810 // There shouldn't be any more events
811 checkNoEvents(log);
812
813 // Trigger the handler to return
814 state->getHandler()->triggerPendingCalls();
815
816 // The handler will log an ET_WAIT_RETURN event when it wakes up
817 Event event = log->waitForEvent();
818 BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
819
820 // Now receive the response
821 try {
822 client->recv_unexpectedExceptionWait();
823 BOOST_FAIL("expected TApplicationError to be thrown");
824 } catch (const TApplicationException&) {
825 }
826
827 // Now we should see a handler error event
828 event = log->waitForEvent();
829 BOOST_CHECK_EQUAL(EventLog::ET_HANDLER_ERROR, event.type);
830 BOOST_CHECK_EQUAL(connId, event.connectionId);
831 BOOST_CHECK_EQUAL(callId, event.callId);
832 BOOST_CHECK_EQUAL(callName, event.message);
833
834 // pre-write and post-write events aren't generated after a handler error
835 // (Even for non-oneway calls where a response is written.)
836 //
837 // A call finished event is logged when the call context is destroyed
838 event = log->waitForEvent();
839 BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
840 BOOST_CHECK_EQUAL(connId, event.connectionId);
841 BOOST_CHECK_EQUAL(callId, event.callId);
842 BOOST_CHECK_EQUAL(callName, event.message);
843
844 // There shouldn't be any more events
845 checkNoEvents(log);
846
847 // Destroy the client, and check for connection closed events
848 client.reset();
849 checkCloseEvents(log, connId);
850
851 checkNoEvents(log);
852 }
853
854 // Macro to define simple tests that can be used with all server types
855 #define DEFINE_SIMPLE_TESTS(Server, Template) \
856 BOOST_AUTO_TEST_CASE(Server##_##Template##_basicService) { \
857 testBasicService<Server##Traits, Template##Traits>(); \
858 } \
859 BOOST_AUTO_TEST_CASE(Server##_##Template##_inheritedService) { \
860 testInheritedService<Server##Traits, Template##Traits>(); \
861 } \
862 BOOST_AUTO_TEST_CASE(Server##_##Template##_oneway) { \
863 testOnewayCall<Server##Traits, Template##Traits>(); \
864 } \
865 BOOST_AUTO_TEST_CASE(Server##_##Template##_exception) { \
866 testExpectedError<Server##Traits, Template##Traits>(); \
867 } \
868 BOOST_AUTO_TEST_CASE(Server##_##Template##_unexpectedException) { \
869 testUnexpectedError<Server##Traits, Template##Traits>(); \
870 }
871
872 // Tests that require the server to process multiple connections concurrently
873 // (i.e., not TSimpleServer)
874 #define DEFINE_CONCURRENT_SERVER_TESTS(Server, Template) \
875 BOOST_AUTO_TEST_CASE(Server##_##Template##_separateConnections) { \
876 testSeparateConnections<Server##Traits, Template##Traits>(); \
877 }
878
879 // The testEventSequencing() test manually generates a request for the server,
880 // and doesn't work with TFramedTransport. Therefore we can't test it with
881 // TNonblockingServer.
882 #define DEFINE_NOFRAME_TESTS(Server, Template) \
883 BOOST_AUTO_TEST_CASE(Server##_##Template##_eventSequencing) { \
884 testEventSequencing<Server##Traits, Template##Traits>(); \
885 }
886
887 #define DEFINE_TNONBLOCKINGSERVER_TESTS(Server, Template) \
888 DEFINE_SIMPLE_TESTS(Server, Template) \
889 DEFINE_CONCURRENT_SERVER_TESTS(Server, Template)
890
891 #define DEFINE_ALL_SERVER_TESTS(Server, Template) \
892 DEFINE_SIMPLE_TESTS(Server, Template) \
893 DEFINE_CONCURRENT_SERVER_TESTS(Server, Template) \
894 DEFINE_NOFRAME_TESTS(Server, Template)
895
DEFINE_ALL_SERVER_TESTS(TThreadedServer,Templated)896 DEFINE_ALL_SERVER_TESTS(TThreadedServer, Templated)
897 DEFINE_ALL_SERVER_TESTS(TThreadedServer, Untemplated)
898 DEFINE_ALL_SERVER_TESTS(TThreadPoolServer, Templated)
899 DEFINE_ALL_SERVER_TESTS(TThreadPoolServer, Untemplated)
900
901 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServer, Templated)
902 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServer, Untemplated)
903 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads, Templated)
904 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads, Untemplated)
905
906 DEFINE_SIMPLE_TESTS(TSimpleServer, Templated)
907 DEFINE_SIMPLE_TESTS(TSimpleServer, Untemplated)
908 DEFINE_NOFRAME_TESTS(TSimpleServer, Templated)
909 DEFINE_NOFRAME_TESTS(TSimpleServer, Untemplated)
910
911 // TODO: We should test TEventServer in the future.
912 // For now, it is known not to work correctly with TProcessorEventHandler.
913 #ifdef BOOST_TEST_DYN_LINK
914 bool init_unit_test_suite() {
915 ::boost::unit_test::framework::master_test_suite().p_name.value = "ProcessorTest";
916 return true;
917 }
918
main(int argc,char * argv[])919 int main( int argc, char* argv[] ) {
920 return ::boost::unit_test::unit_test_main(&init_unit_test_suite,argc,argv);
921 }
922 #else
923 ::boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
924 THRIFT_UNUSED_VARIABLE(argc);
925 THRIFT_UNUSED_VARIABLE(argv);
926 ::boost::unit_test::framework::master_test_suite().p_name.value = "ProcessorTest";
927 return nullptr;
928 }
929 #endif
930