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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * This file contains tests that ensure TProcessorEventHandler and
22 * TServerEventHandler are invoked properly by the various server
26 #include <boost/test/unit_test.hpp>
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>
39 #include "ServerThread.h"
41 #include "gen-cpp/ChildService.h"
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
;
53 * Traits classes that encapsulate how to create various types of servers.
56 class TSimpleServerTraits
{
58 typedef TSimpleServer ServerType
;
60 std::shared_ptr
<TSimpleServer
> createServer(
61 const std::shared_ptr
<TProcessor
>& processor
,
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
));
71 class TThreadedServerTraits
{
73 typedef TThreadedServer ServerType
;
75 std::shared_ptr
<TThreadedServer
> createServer(
76 const std::shared_ptr
<TProcessor
>& processor
,
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
));
86 class TThreadPoolServerTraits
{
88 typedef TThreadPoolServer ServerType
;
90 std::shared_ptr
<TThreadPoolServer
> createServer(
91 const std::shared_ptr
<TProcessor
>& processor
,
93 const std::shared_ptr
<TTransportFactory
>& transportFactory
,
94 const std::shared_ptr
<TProtocolFactory
>& protocolFactory
) {
95 std::shared_ptr
<TServerSocket
> socket(new TServerSocket(port
));
97 std::shared_ptr
<ThreadFactory
> threadFactory(new ThreadFactory
);
98 std::shared_ptr
<ThreadManager
> threadManager
= ThreadManager::newSimpleThreadManager(8);
99 threadManager
->threadFactory(threadFactory
);
100 threadManager
->start();
102 return std::shared_ptr
<TThreadPoolServer
>(
103 new TThreadPoolServer(processor
, socket
, transportFactory
, protocolFactory
, threadManager
));
107 class TNonblockingServerTraits
{
109 typedef TNonblockingServer ServerType
;
111 std::shared_ptr
<TNonblockingServer
> createServer(
112 const std::shared_ptr
<TProcessor
>& processor
,
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
120 = dynamic_cast<TFramedTransportFactory
*>(transportFactory
.get());
121 if (framedFactory
== nullptr) {
122 throw TException("TNonblockingServer must use TFramedTransport");
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();
131 return std::shared_ptr
<TNonblockingServer
>(
132 new TNonblockingServer(processor
, protocolFactory
, socket
, threadManager
));
136 class TNonblockingServerNoThreadsTraits
{
138 typedef TNonblockingServer ServerType
;
140 std::shared_ptr
<TNonblockingServer
> createServer(
141 const std::shared_ptr
<TProcessor
>& processor
,
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
149 = dynamic_cast<TFramedTransportFactory
*>(transportFactory
.get());
150 if (framedFactory
== nullptr) {
151 throw TException("TNonblockingServer must use TFramedTransport");
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
));
163 * Traits classes for controlling if we instantiate templated or generic
164 * protocol factories, processors, clients, etc.
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.
170 * Each specific test case can control whether we create a child or parent
171 * server, and whether we use TFramedTransport or TBufferedTransport.
174 class UntemplatedTraits
{
176 typedef TBinaryProtocolFactory ProtocolFactory
;
177 typedef TBinaryProtocol Protocol
;
179 typedef ParentServiceProcessor ParentProcessor
;
180 typedef ChildServiceProcessor ChildProcessor
;
181 typedef ParentServiceClient ParentClient
;
182 typedef ChildServiceClient ChildClient
;
185 class TemplatedTraits
{
187 typedef TBinaryProtocolFactoryT
<TBufferBase
> ProtocolFactory
;
188 typedef TBinaryProtocolT
<TBufferBase
> Protocol
;
190 typedef ParentServiceProcessorT
<Protocol
> ParentProcessor
;
191 typedef ChildServiceProcessorT
<Protocol
> ChildProcessor
;
192 typedef ParentServiceClientT
<Protocol
> ParentClient
;
193 typedef ChildServiceClientT
<Protocol
> ChildClient
;
196 template <typename TemplateTraits_
>
197 class ParentServiceTraits
{
199 typedef typename
TemplateTraits_::ParentProcessor Processor
;
200 typedef typename
TemplateTraits_::ParentClient Client
;
201 typedef ParentHandler Handler
;
203 typedef typename
TemplateTraits_::ProtocolFactory ProtocolFactory
;
204 typedef typename
TemplateTraits_::Protocol Protocol
;
207 template <typename TemplateTraits_
>
208 class ChildServiceTraits
{
210 typedef typename
TemplateTraits_::ChildProcessor Processor
;
211 typedef typename
TemplateTraits_::ChildClient Client
;
212 typedef ChildHandler Handler
;
214 typedef typename
TemplateTraits_::ProtocolFactory ProtocolFactory
;
215 typedef typename
TemplateTraits_::Protocol Protocol
;
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.
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
225 template <typename ServerTraits_
,
226 typename ServiceTraits_
,
227 typename TransportFactory_
= TFramedTransportFactory
,
228 typename Transport_
= TFramedTransport
>
229 class ServiceState
: public ServerState
{
231 typedef typename
ServiceTraits_::Processor Processor
;
232 typedef typename
ServiceTraits_::Client Client
;
233 typedef typename
ServiceTraits_::Handler Handler
;
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_
);
247 std::shared_ptr
<TServer
> createServer(uint16_t port
) override
{
248 ServerTraits_ serverTraits
;
249 return serverTraits
.createServer(processor_
, port
, transportFactory_
, protocolFactory_
);
252 std::shared_ptr
<TServerEventHandler
> getServerEventHandler() override
{ return serverEventHandler_
; }
254 void bindSuccessful(uint16_t port
) override
{ port_
= port
; }
256 uint16_t getPort() const { return port_
; }
258 const std::shared_ptr
<EventLog
>& getLog() const { return log_
; }
260 const std::shared_ptr
<Handler
>& getHandler() const { return handler_
; }
262 std::shared_ptr
<Client
> createClient() {
263 typedef typename
ServiceTraits_::Protocol Protocol
;
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
));
270 std::shared_ptr
<Client
> client(new Client(protocol
));
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_
;
286 * Check that there are no more events in the 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
);
298 * Check for the events that should be logged when a new connection is created.
300 * Returns the connection ID allocated by the server.
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
);
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.
311 return event
.connectionId
;
315 * Check for the events that should be logged when a connection is closed.
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
);
323 // Make sure there are no more events
328 * Check for the events that should be logged when a call is received
329 * and the handler is invoked.
331 * It does not check for anything after the handler invocation.
333 * Returns the call ID allocated by the server.
335 uint32_t checkCallHandlerEvents(const std::shared_ptr
<EventLog
>& log
,
338 const string
& callName
) {
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
;
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
);
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
);
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
370 * Check for the events that should be after a handler returns.
372 void checkCallPostHandlerEvents(const std::shared_ptr
<EventLog
>& log
,
375 const string
& callName
) {
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
);
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
);
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
);
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()
405 * Check for the events that should be logged when a call is made.
407 * This just calls checkCallHandlerEvents() followed by
408 * checkCallPostHandlerEvents().
410 * Returns the call ID allocated by the server.
412 uint32_t checkCallEvents(const std::shared_ptr
<EventLog
>& log
,
415 const string
& callName
) {
416 uint32_t callId
= checkCallHandlerEvents(log
, connId
, callType
, callName
);
417 checkCallPostHandlerEvents(log
, connId
, callId
, callName
);
426 template <typename State_
>
427 void testParentService(const std::shared_ptr
<State_
>& state
) {
428 std::shared_ptr
<typename
State_::Client
> client
= state
->createClient();
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
);
436 client
->addString("foo");
437 client
->addString("bar");
438 client
->addString("asdf");
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]);
448 template <typename State_
>
449 void testChildService(const std::shared_ptr
<State_
>& state
) {
450 std::shared_ptr
<typename
State_::Client
> client
= state
->createClient();
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
);
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());
466 template <typename ServerTraits
, typename TemplateTraits
>
467 void testBasicService() {
468 typedef ServiceState
<ServerTraits
, ParentServiceTraits
<TemplateTraits
> > State
;
471 std::shared_ptr
<State
> state(new State
);
472 ServerThread
serverThread(state
, true);
474 testParentService(state
);
477 template <typename ServerTraits
, typename TemplateTraits
>
478 void testInheritedService() {
479 typedef ServiceState
<ServerTraits
, ChildServiceTraits
<TemplateTraits
> > State
;
482 std::shared_ptr
<State
> state(new State
);
483 ServerThread
serverThread(state
, true);
485 testParentService(state
);
486 testChildService(state
);
490 * Test to make sure that the TServerEventHandler and TProcessorEventHandler
491 * methods are invoked in the correct order with the actual events.
493 template <typename ServerTraits
, typename TemplateTraits
>
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
;
505 std::shared_ptr
<State
> state(new State
);
506 ServerThread
serverThread(state
, true);
508 const std::shared_ptr
<EventLog
>& log
= state
->getLog();
510 // Make sure we're at the end of the log
513 state
->getHandler()->prepareTriggeredCall();
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()));
520 // Make sure the proper events occurred after a new connection
521 uint32_t connId
= checkNewConnEvents(log
);
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
);
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
;
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
);
545 // Make sure there are no new events
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();
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
);
566 // Then the handler should be invoked
567 event
= log
->waitForEvent();
568 BOOST_CHECK_EQUAL(EventLog::ET_CALL_GET_DATA_WAIT
, event
.type
);
570 // The handler won't respond until we notify it.
571 // Make sure there are no more events.
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();
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
);
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
);
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.
594 // Read the response header
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
);
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
);
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
);
620 // There should be no more events
623 // Close the connection, and make sure we get a connection destroyed event
625 event
= log
->waitForEvent();
626 BOOST_CHECK_EQUAL(EventLog::ET_CONN_DESTROYED
, event
.type
);
627 BOOST_CHECK_EQUAL(connId
, event
.connectionId
);
629 // There should be no more events
633 template <typename ServerTraits
, typename TemplateTraits
>
634 void testSeparateConnections() {
635 typedef ServiceState
<ServerTraits
, ChildServiceTraits
<TemplateTraits
> > State
;
638 std::shared_ptr
<State
> state(new State
);
639 ServerThread
serverThread(state
, true);
641 const std::shared_ptr
<EventLog
>& log
= state
->getLog();
644 std::shared_ptr
<typename
State::Client
> client1
= state
->createClient();
646 // Make sure the expected events were logged
647 uint32_t client1Id
= checkNewConnEvents(log
);
649 // Create a second client
650 std::shared_ptr
<typename
State::Client
> client2
= state
->createClient();
652 // Make sure the expected events were logged
653 uint32_t client2Id
= checkNewConnEvents(log
);
655 // The two connections should have different IDs
656 BOOST_CHECK_NE(client1Id
, client2Id
);
658 // Make a call, and check for the proper events
660 client1
->setValue(value
);
662 = checkCallEvents(log
, client1Id
, EventLog::ET_CALL_SET_VALUE
, "ChildService.setValue");
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");
669 // Make another call with client1
670 v
= client1
->getValue();
671 BOOST_CHECK_EQUAL(value
, v
);
673 = checkCallEvents(log
, client1Id
, EventLog::ET_CALL_GET_VALUE
, "ChildService.getValue");
674 BOOST_CHECK_NE(call1
, call2
);
676 // Close the second client, and check for the appropriate events
678 checkCloseEvents(log
, client2Id
);
681 template <typename ServerTraits
, typename TemplateTraits
>
682 void testOnewayCall() {
683 typedef ServiceState
<ServerTraits
, ChildServiceTraits
<TemplateTraits
> > State
;
686 std::shared_ptr
<State
> state(new State
);
687 ServerThread
serverThread(state
, true);
689 const std::shared_ptr
<EventLog
>& log
= state
->getLog();
692 std::shared_ptr
<typename
State::Client
> client
= state
->createClient();
693 uint32_t connId
= checkNewConnEvents(log
);
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
);
703 // There shouldn't be any more events
706 // Trigger the handler to return
707 state
->getHandler()->triggerPendingCalls();
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
);
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
);
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
);
726 // Destroy the client, and check for connection closed events
728 checkCloseEvents(log
, connId
);
733 template <typename ServerTraits
, typename TemplateTraits
>
734 void testExpectedError() {
735 typedef ServiceState
<ServerTraits
, ChildServiceTraits
<TemplateTraits
> > State
;
738 std::shared_ptr
<State
> state(new State
);
739 ServerThread
serverThread(state
, true);
741 const std::shared_ptr
<EventLog
>& log
= state
->getLog();
744 std::shared_ptr
<typename
State::Client
> client
= state
->createClient();
745 uint32_t connId
= checkNewConnEvents(log
);
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
);
754 // There shouldn't be any more events
757 // Trigger the handler to return
758 state
->getHandler()->triggerPendingCalls();
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
);
764 // Now receive the response
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
);
775 // Now we should see the events for a normal call finish
776 checkCallPostHandlerEvents(log
, connId
, callId
, callName
);
778 // There shouldn't be any more events
781 // Destroy the client, and check for connection closed events
783 checkCloseEvents(log
, connId
);
788 template <typename ServerTraits
, typename TemplateTraits
>
789 void testUnexpectedError() {
790 typedef ServiceState
<ServerTraits
, ChildServiceTraits
<TemplateTraits
> > State
;
793 std::shared_ptr
<State
> state(new State
);
794 ServerThread
serverThread(state
, true);
796 const std::shared_ptr
<EventLog
>& log
= state
->getLog();
799 std::shared_ptr
<typename
State::Client
> client
= state
->createClient();
800 uint32_t connId
= checkNewConnEvents(log
);
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";
808 = checkCallHandlerEvents(log
, connId
, EventLog::ET_CALL_UNEXPECTED_EXCEPTION_WAIT
, callName
);
810 // There shouldn't be any more events
813 // Trigger the handler to return
814 state
->getHandler()->triggerPendingCalls();
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
);
820 // Now receive the response
822 client
->recv_unexpectedExceptionWait();
823 BOOST_FAIL("expected TApplicationError to be thrown");
824 } catch (const TApplicationException
&) {
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
);
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.)
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
);
844 // There shouldn't be any more events
847 // Destroy the client, and check for connection closed events
849 checkCloseEvents(log
, connId
);
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>(); \
859 BOOST_AUTO_TEST_CASE(Server##_##Template##_inheritedService) { \
860 testInheritedService<Server##Traits, Template##Traits>(); \
862 BOOST_AUTO_TEST_CASE(Server##_##Template##_oneway) { \
863 testOnewayCall<Server##Traits, Template##Traits>(); \
865 BOOST_AUTO_TEST_CASE(Server##_##Template##_exception) { \
866 testExpectedError<Server##Traits, Template##Traits>(); \
868 BOOST_AUTO_TEST_CASE(Server##_##Template##_unexpectedException) { \
869 testUnexpectedError<Server##Traits, Template##Traits>(); \
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>(); \
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>(); \
887 #define DEFINE_TNONBLOCKINGSERVER_TESTS(Server, Template) \
888 DEFINE_SIMPLE_TESTS(Server, Template) \
889 DEFINE_CONCURRENT_SERVER_TESTS(Server, Template)
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)
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
)
901 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServer
, Templated
)
902 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServer
, Untemplated
)
903 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads
, Templated
)
904 DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads
, Untemplated
)
906 DEFINE_SIMPLE_TESTS(TSimpleServer
, Templated
)
907 DEFINE_SIMPLE_TESTS(TSimpleServer
, Untemplated
)
908 DEFINE_NOFRAME_TESTS(TSimpleServer
, Templated
)
909 DEFINE_NOFRAME_TESTS(TSimpleServer
, Untemplated
)
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";
919 int main( int argc
, char* argv
[] ) {
920 return ::boost::unit_test::unit_test_main(&init_unit_test_suite
,argc
,argv
);
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";