2012-05-10 09:01:45 +00:00
|
|
|
/*
|
|
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
|
|
|
* or more contributor license agreements. See the NOTICE file
|
|
|
|
|
* distributed with this work for additional information
|
|
|
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
|
|
|
* to you under the Apache License, Version 2.0 (the
|
|
|
|
|
* "License"); you may not use this file except in compliance
|
|
|
|
|
* with the License. You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing,
|
|
|
|
|
* software distributed under the License is distributed on an
|
|
|
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
|
|
|
* KIND, either express or implied. See the License for the
|
|
|
|
|
* specific language governing permissions and limitations
|
|
|
|
|
* under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This file contains tests that ensure TProcessorEventHandler and
|
|
|
|
|
* TServerEventHandler are invoked properly by the various server
|
|
|
|
|
* implementations.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
|
|
2019-01-11 22:13:12 +08:00
|
|
|
#include <thrift/concurrency/ThreadFactory.h>
|
2012-05-10 09:01:45 +00:00
|
|
|
#include <thrift/concurrency/Monitor.h>
|
|
|
|
|
#include <thrift/protocol/TBinaryProtocol.h>
|
|
|
|
|
#include <thrift/server/TThreadedServer.h>
|
|
|
|
|
#include <thrift/server/TThreadPoolServer.h>
|
|
|
|
|
#include <thrift/server/TNonblockingServer.h>
|
|
|
|
|
#include <thrift/server/TSimpleServer.h>
|
|
|
|
|
#include <thrift/transport/TSocket.h>
|
2017-08-06 16:36:36 -07:00
|
|
|
#include <thrift/transport/TNonblockingServerSocket.h>
|
2012-05-10 09:01:45 +00:00
|
|
|
|
2012-05-11 10:12:39 +00:00
|
|
|
#include "EventLog.h"
|
|
|
|
|
#include "ServerThread.h"
|
|
|
|
|
#include "Handlers.h"
|
2012-05-10 09:01:45 +00:00
|
|
|
#include "gen-cpp/ChildService.h"
|
|
|
|
|
|
|
|
|
|
using namespace apache::thrift;
|
|
|
|
|
using namespace apache::thrift::concurrency;
|
|
|
|
|
using namespace apache::thrift::protocol;
|
|
|
|
|
using namespace apache::thrift::server;
|
|
|
|
|
using namespace apache::thrift::test;
|
2017-08-05 12:23:54 -04:00
|
|
|
using namespace apache::thrift::transport;
|
|
|
|
|
using std::string;
|
|
|
|
|
using std::vector;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Traits classes that encapsulate how to create various types of servers.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class TSimpleServerTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef TSimpleServer ServerType;
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TSimpleServer> createServer(
|
|
|
|
|
const std::shared_ptr<TProcessor>& processor,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint16_t port,
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<TTransportFactory>& transportFactory,
|
|
|
|
|
const std::shared_ptr<TProtocolFactory>& protocolFactory) {
|
|
|
|
|
std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
|
|
|
|
|
return std::shared_ptr<TSimpleServer>(
|
2014-11-13 15:33:38 +01:00
|
|
|
new TSimpleServer(processor, socket, transportFactory, protocolFactory));
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TThreadedServerTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef TThreadedServer ServerType;
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TThreadedServer> createServer(
|
|
|
|
|
const std::shared_ptr<TProcessor>& processor,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint16_t port,
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<TTransportFactory>& transportFactory,
|
|
|
|
|
const std::shared_ptr<TProtocolFactory>& protocolFactory) {
|
|
|
|
|
std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
|
|
|
|
|
return std::shared_ptr<TThreadedServer>(
|
2014-11-13 15:33:38 +01:00
|
|
|
new TThreadedServer(processor, socket, transportFactory, protocolFactory));
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TThreadPoolServerTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef TThreadPoolServer ServerType;
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TThreadPoolServer> createServer(
|
|
|
|
|
const std::shared_ptr<TProcessor>& processor,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint16_t port,
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<TTransportFactory>& transportFactory,
|
|
|
|
|
const std::shared_ptr<TProtocolFactory>& protocolFactory) {
|
|
|
|
|
std::shared_ptr<TServerSocket> socket(new TServerSocket(port));
|
2012-05-10 09:01:45 +00:00
|
|
|
|
2019-01-11 22:13:12 +08:00
|
|
|
std::shared_ptr<ThreadFactory> threadFactory(new ThreadFactory);
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(8);
|
2012-05-10 09:01:45 +00:00
|
|
|
threadManager->threadFactory(threadFactory);
|
|
|
|
|
threadManager->start();
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
return std::shared_ptr<TThreadPoolServer>(
|
2014-11-13 15:33:38 +01:00
|
|
|
new TThreadPoolServer(processor, socket, transportFactory, protocolFactory, threadManager));
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TNonblockingServerTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef TNonblockingServer ServerType;
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TNonblockingServer> createServer(
|
|
|
|
|
const std::shared_ptr<TProcessor>& processor,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint16_t port,
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<TTransportFactory>& transportFactory,
|
|
|
|
|
const std::shared_ptr<TProtocolFactory>& protocolFactory) {
|
2012-05-10 09:01:45 +00:00
|
|
|
// TNonblockingServer automatically uses TFramedTransport.
|
|
|
|
|
// Raise an exception if the supplied transport factory is not a
|
|
|
|
|
// TFramedTransportFactory
|
2019-01-29 15:48:12 +01:00
|
|
|
auto* framedFactory
|
2014-11-13 15:33:38 +01:00
|
|
|
= dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
|
2019-01-29 15:48:12 +01:00
|
|
|
if (framedFactory == nullptr) {
|
2012-05-10 09:01:45 +00:00
|
|
|
throw TException("TNonblockingServer must use TFramedTransport");
|
|
|
|
|
}
|
2017-08-05 12:23:54 -04:00
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TNonblockingServerSocket> socket(new TNonblockingServerSocket(port));
|
2019-01-11 22:13:12 +08:00
|
|
|
std::shared_ptr<ThreadFactory> threadFactory(new ThreadFactory);
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(8);
|
2012-05-10 09:01:45 +00:00
|
|
|
threadManager->threadFactory(threadFactory);
|
|
|
|
|
threadManager->start();
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
return std::shared_ptr<TNonblockingServer>(
|
2017-08-06 16:36:36 -07:00
|
|
|
new TNonblockingServer(processor, protocolFactory, socket, threadManager));
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TNonblockingServerNoThreadsTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef TNonblockingServer ServerType;
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TNonblockingServer> createServer(
|
|
|
|
|
const std::shared_ptr<TProcessor>& processor,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint16_t port,
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<TTransportFactory>& transportFactory,
|
|
|
|
|
const std::shared_ptr<TProtocolFactory>& protocolFactory) {
|
2012-05-10 09:01:45 +00:00
|
|
|
// TNonblockingServer automatically uses TFramedTransport.
|
|
|
|
|
// Raise an exception if the supplied transport factory is not a
|
|
|
|
|
// TFramedTransportFactory
|
2019-01-29 15:48:12 +01:00
|
|
|
auto* framedFactory
|
2014-11-13 15:33:38 +01:00
|
|
|
= dynamic_cast<TFramedTransportFactory*>(transportFactory.get());
|
2019-01-29 15:48:12 +01:00
|
|
|
if (framedFactory == nullptr) {
|
2012-05-10 09:01:45 +00:00
|
|
|
throw TException("TNonblockingServer must use TFramedTransport");
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TNonblockingServerSocket> socket(new TNonblockingServerSocket(port));
|
2012-05-10 09:01:45 +00:00
|
|
|
// Use a NULL ThreadManager
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<ThreadManager> threadManager;
|
|
|
|
|
return std::shared_ptr<TNonblockingServer>(
|
2017-08-06 16:36:36 -07:00
|
|
|
new TNonblockingServer(processor, protocolFactory, socket, threadManager));
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Traits classes for controlling if we instantiate templated or generic
|
|
|
|
|
* protocol factories, processors, clients, etc.
|
|
|
|
|
*
|
|
|
|
|
* The goal is to allow the outer test code to select which server type is
|
|
|
|
|
* being tested, and whether or not we are testing the templated classes, or
|
|
|
|
|
* the generic classes.
|
|
|
|
|
*
|
|
|
|
|
* Each specific test case can control whether we create a child or parent
|
|
|
|
|
* server, and whether we use TFramedTransport or TBufferedTransport.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class UntemplatedTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef TBinaryProtocolFactory ProtocolFactory;
|
|
|
|
|
typedef TBinaryProtocol Protocol;
|
|
|
|
|
|
|
|
|
|
typedef ParentServiceProcessor ParentProcessor;
|
|
|
|
|
typedef ChildServiceProcessor ChildProcessor;
|
|
|
|
|
typedef ParentServiceClient ParentClient;
|
|
|
|
|
typedef ChildServiceClient ChildClient;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TemplatedTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef TBinaryProtocolFactoryT<TBufferBase> ProtocolFactory;
|
|
|
|
|
typedef TBinaryProtocolT<TBufferBase> Protocol;
|
|
|
|
|
|
|
|
|
|
typedef ParentServiceProcessorT<Protocol> ParentProcessor;
|
|
|
|
|
typedef ChildServiceProcessorT<Protocol> ChildProcessor;
|
|
|
|
|
typedef ParentServiceClientT<Protocol> ParentClient;
|
|
|
|
|
typedef ChildServiceClientT<Protocol> ChildClient;
|
|
|
|
|
};
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename TemplateTraits_>
|
2012-05-10 09:01:45 +00:00
|
|
|
class ParentServiceTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef typename TemplateTraits_::ParentProcessor Processor;
|
|
|
|
|
typedef typename TemplateTraits_::ParentClient Client;
|
|
|
|
|
typedef ParentHandler Handler;
|
|
|
|
|
|
|
|
|
|
typedef typename TemplateTraits_::ProtocolFactory ProtocolFactory;
|
|
|
|
|
typedef typename TemplateTraits_::Protocol Protocol;
|
|
|
|
|
};
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename TemplateTraits_>
|
2012-05-10 09:01:45 +00:00
|
|
|
class ChildServiceTraits {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef typename TemplateTraits_::ChildProcessor Processor;
|
|
|
|
|
typedef typename TemplateTraits_::ChildClient Client;
|
|
|
|
|
typedef ChildHandler Handler;
|
|
|
|
|
|
|
|
|
|
typedef typename TemplateTraits_::ProtocolFactory ProtocolFactory;
|
|
|
|
|
typedef typename TemplateTraits_::Protocol Protocol;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// TODO: It would be nicer if the TTransportFactory types defined a typedef,
|
|
|
|
|
// to allow us to figure out the exact transport type without having to pass it
|
|
|
|
|
// in as a separate template parameter here.
|
|
|
|
|
//
|
|
|
|
|
// It would also be niec if they used covariant return types. Unfortunately,
|
|
|
|
|
// since they return shared_ptr instead of raw pointers, covariant return types
|
|
|
|
|
// won't work.
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits_,
|
|
|
|
|
typename ServiceTraits_,
|
|
|
|
|
typename TransportFactory_ = TFramedTransportFactory,
|
|
|
|
|
typename Transport_ = TFramedTransport>
|
2012-05-10 09:01:45 +00:00
|
|
|
class ServiceState : public ServerState {
|
2014-11-13 15:33:38 +01:00
|
|
|
public:
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef typename ServiceTraits_::Processor Processor;
|
|
|
|
|
typedef typename ServiceTraits_::Client Client;
|
|
|
|
|
typedef typename ServiceTraits_::Handler Handler;
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
ServiceState()
|
|
|
|
|
: port_(0),
|
2012-05-10 09:01:45 +00:00
|
|
|
log_(new EventLog),
|
|
|
|
|
handler_(new Handler(log_)),
|
|
|
|
|
processor_(new Processor(handler_)),
|
|
|
|
|
transportFactory_(new TransportFactory_),
|
|
|
|
|
protocolFactory_(new typename ServiceTraits_::ProtocolFactory),
|
|
|
|
|
serverEventHandler_(new ServerEventHandler(log_)),
|
|
|
|
|
processorEventHandler_(new ProcessorEventHandler(log_)) {
|
|
|
|
|
processor_->setEventHandler(processorEventHandler_);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-29 15:48:12 +01:00
|
|
|
std::shared_ptr<TServer> createServer(uint16_t port) override {
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerTraits_ serverTraits;
|
2014-11-13 15:33:38 +01:00
|
|
|
return serverTraits.createServer(processor_, port, transportFactory_, protocolFactory_);
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
2019-01-29 15:48:12 +01:00
|
|
|
std::shared_ptr<TServerEventHandler> getServerEventHandler() override { return serverEventHandler_; }
|
2012-05-10 09:01:45 +00:00
|
|
|
|
2019-01-29 15:48:12 +01:00
|
|
|
void bindSuccessful(uint16_t port) override { port_ = port; }
|
2012-05-10 09:01:45 +00:00
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
uint16_t getPort() const { return port_; }
|
2012-05-10 09:01:45 +00:00
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<EventLog>& getLog() const { return log_; }
|
2012-05-10 09:01:45 +00:00
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<Handler>& getHandler() const { return handler_; }
|
2012-05-10 09:01:45 +00:00
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<Client> createClient() {
|
2012-05-10 09:01:45 +00:00
|
|
|
typedef typename ServiceTraits_::Protocol Protocol;
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port_));
|
|
|
|
|
std::shared_ptr<Transport_> transport(new Transport_(socket));
|
|
|
|
|
std::shared_ptr<Protocol> protocol(new Protocol(transport));
|
2012-05-10 09:01:45 +00:00
|
|
|
transport->open();
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<Client> client(new Client(protocol));
|
2012-05-10 09:01:45 +00:00
|
|
|
return client;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
private:
|
2012-05-10 09:01:45 +00:00
|
|
|
uint16_t port_;
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<EventLog> log_;
|
|
|
|
|
std::shared_ptr<Handler> handler_;
|
|
|
|
|
std::shared_ptr<Processor> processor_;
|
|
|
|
|
std::shared_ptr<TTransportFactory> transportFactory_;
|
|
|
|
|
std::shared_ptr<TProtocolFactory> protocolFactory_;
|
|
|
|
|
std::shared_ptr<TServerEventHandler> serverEventHandler_;
|
|
|
|
|
std::shared_ptr<TProcessorEventHandler> processorEventHandler_;
|
2012-05-10 09:01:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check that there are no more events in the log
|
|
|
|
|
*/
|
2019-01-05 16:35:14 +08:00
|
|
|
void checkNoEvents(const std::shared_ptr<EventLog>& log) {
|
2012-05-10 09:01:45 +00:00
|
|
|
// Wait for an event with a very short timeout period. We don't expect
|
|
|
|
|
// anything to be present, so we will normally wait for the full timeout.
|
|
|
|
|
// On the other hand, a non-zero timeout is nice since it does give a short
|
|
|
|
|
// window for events to arrive in case there is a problem.
|
|
|
|
|
Event event = log->waitForEvent(10);
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_LOG_END, event.type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check for the events that should be logged when a new connection is created.
|
|
|
|
|
*
|
|
|
|
|
* Returns the connection ID allocated by the server.
|
|
|
|
|
*/
|
2019-01-05 16:35:14 +08:00
|
|
|
uint32_t checkNewConnEvents(const std::shared_ptr<EventLog>& log) {
|
2012-05-10 09:01:45 +00:00
|
|
|
// Check for an ET_CONN_CREATED event
|
2016-11-12 15:16:30 -05:00
|
|
|
Event event = log->waitForEvent(2500);
|
2012-05-10 09:01:45 +00:00
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CONN_CREATED, event.type);
|
|
|
|
|
|
|
|
|
|
// Some servers call the processContext() hook immediately.
|
|
|
|
|
// Others (TNonblockingServer) only call it once a full request is received.
|
|
|
|
|
// We don't check for it yet, to allow either behavior.
|
|
|
|
|
|
|
|
|
|
return event.connectionId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check for the events that should be logged when a connection is closed.
|
|
|
|
|
*/
|
2019-01-05 16:35:14 +08:00
|
|
|
void checkCloseEvents(const std::shared_ptr<EventLog>& log, uint32_t connId) {
|
2012-05-10 09:01:45 +00:00
|
|
|
// Check for an ET_CONN_DESTROYED event
|
|
|
|
|
Event event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CONN_DESTROYED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
|
|
|
|
|
// Make sure there are no more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check for the events that should be logged when a call is received
|
|
|
|
|
* and the handler is invoked.
|
|
|
|
|
*
|
|
|
|
|
* It does not check for anything after the handler invocation.
|
|
|
|
|
*
|
|
|
|
|
* Returns the call ID allocated by the server.
|
|
|
|
|
*/
|
2019-01-05 16:35:14 +08:00
|
|
|
uint32_t checkCallHandlerEvents(const std::shared_ptr<EventLog>& log,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint32_t connId,
|
|
|
|
|
EventType callType,
|
|
|
|
|
const string& callName) {
|
|
|
|
|
// Call started
|
|
|
|
|
Event event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CALL_STARTED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
uint32_t callId = event.callId;
|
|
|
|
|
|
|
|
|
|
// Pre-read
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_PRE_READ, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// Post-read
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_POST_READ, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// Handler invocation
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(callType, event.type);
|
|
|
|
|
// The handler doesn't have any connection or call context,
|
|
|
|
|
// so the connectionId and callId in this event aren't valid
|
|
|
|
|
|
|
|
|
|
return callId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check for the events that should be after a handler returns.
|
|
|
|
|
*/
|
2019-01-05 16:35:14 +08:00
|
|
|
void checkCallPostHandlerEvents(const std::shared_ptr<EventLog>& log,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint32_t connId,
|
|
|
|
|
uint32_t callId,
|
|
|
|
|
const string& callName) {
|
|
|
|
|
// Pre-write
|
|
|
|
|
Event event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_PRE_WRITE, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// Post-write
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_POST_WRITE, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// Call finished
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// It is acceptable for servers to call processContext() again immediately
|
|
|
|
|
// to start waiting on the next request. However, some servers wait before
|
|
|
|
|
// getting either a partial request or the full request before calling
|
|
|
|
|
// processContext(). We don't check for the next call to processContext()
|
|
|
|
|
// yet.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check for the events that should be logged when a call is made.
|
|
|
|
|
*
|
|
|
|
|
* This just calls checkCallHandlerEvents() followed by
|
|
|
|
|
* checkCallPostHandlerEvents().
|
|
|
|
|
*
|
|
|
|
|
* Returns the call ID allocated by the server.
|
|
|
|
|
*/
|
2019-01-05 16:35:14 +08:00
|
|
|
uint32_t checkCallEvents(const std::shared_ptr<EventLog>& log,
|
2012-05-10 09:01:45 +00:00
|
|
|
uint32_t connId,
|
|
|
|
|
EventType callType,
|
|
|
|
|
const string& callName) {
|
|
|
|
|
uint32_t callId = checkCallHandlerEvents(log, connId, callType, callName);
|
|
|
|
|
checkCallPostHandlerEvents(log, connId, callId, callName);
|
|
|
|
|
|
|
|
|
|
return callId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Test functions
|
|
|
|
|
*/
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename State_>
|
2019-01-05 16:35:14 +08:00
|
|
|
void testParentService(const std::shared_ptr<State_>& state) {
|
|
|
|
|
std::shared_ptr<typename State_::Client> client = state->createClient();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
int32_t gen = client->getGeneration();
|
|
|
|
|
int32_t newGen = client->incrementGeneration();
|
|
|
|
|
BOOST_CHECK_EQUAL(gen + 1, newGen);
|
|
|
|
|
newGen = client->getGeneration();
|
|
|
|
|
BOOST_CHECK_EQUAL(gen + 1, newGen);
|
|
|
|
|
|
|
|
|
|
client->addString("foo");
|
|
|
|
|
client->addString("bar");
|
|
|
|
|
client->addString("asdf");
|
|
|
|
|
|
|
|
|
|
vector<string> strings;
|
|
|
|
|
client->getStrings(strings);
|
|
|
|
|
BOOST_REQUIRE_EQUAL(3, strings.size());
|
|
|
|
|
BOOST_REQUIRE_EQUAL("foo", strings[0]);
|
|
|
|
|
BOOST_REQUIRE_EQUAL("bar", strings[1]);
|
|
|
|
|
BOOST_REQUIRE_EQUAL("asdf", strings[2]);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename State_>
|
2019-01-05 16:35:14 +08:00
|
|
|
void testChildService(const std::shared_ptr<State_>& state) {
|
|
|
|
|
std::shared_ptr<typename State_::Client> client = state->createClient();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Test calling some of the parent methids via the a child client
|
|
|
|
|
int32_t gen = client->getGeneration();
|
|
|
|
|
int32_t newGen = client->incrementGeneration();
|
|
|
|
|
BOOST_CHECK_EQUAL(gen + 1, newGen);
|
|
|
|
|
newGen = client->getGeneration();
|
|
|
|
|
BOOST_CHECK_EQUAL(gen + 1, newGen);
|
|
|
|
|
|
|
|
|
|
// Test some of the child methods
|
|
|
|
|
client->setValue(10);
|
|
|
|
|
BOOST_CHECK_EQUAL(10, client->getValue());
|
|
|
|
|
BOOST_CHECK_EQUAL(10, client->setValue(99));
|
|
|
|
|
BOOST_CHECK_EQUAL(99, client->getValue());
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits, typename TemplateTraits>
|
2012-05-10 09:01:45 +00:00
|
|
|
void testBasicService() {
|
2014-11-13 15:33:38 +01:00
|
|
|
typedef ServiceState<ServerTraits, ParentServiceTraits<TemplateTraits> > State;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Start the server
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<State> state(new State);
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerThread serverThread(state, true);
|
|
|
|
|
|
|
|
|
|
testParentService(state);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits, typename TemplateTraits>
|
2012-05-10 09:01:45 +00:00
|
|
|
void testInheritedService() {
|
2014-11-13 15:33:38 +01:00
|
|
|
typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Start the server
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<State> state(new State);
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerThread serverThread(state, true);
|
|
|
|
|
|
|
|
|
|
testParentService(state);
|
|
|
|
|
testChildService(state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test to make sure that the TServerEventHandler and TProcessorEventHandler
|
|
|
|
|
* methods are invoked in the correct order with the actual events.
|
|
|
|
|
*/
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits, typename TemplateTraits>
|
2012-05-10 09:01:45 +00:00
|
|
|
void testEventSequencing() {
|
|
|
|
|
// We use TBufferedTransport for this test, instead of TFramedTransport.
|
|
|
|
|
// This way the server will start processing data as soon as it is received,
|
|
|
|
|
// instead of waiting for the full request. This is necessary so we can
|
|
|
|
|
// separate the preRead() and postRead() events.
|
2014-11-13 15:33:38 +01:00
|
|
|
typedef ServiceState<ServerTraits,
|
|
|
|
|
ChildServiceTraits<TemplateTraits>,
|
|
|
|
|
TBufferedTransportFactory,
|
|
|
|
|
TBufferedTransport> State;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Start the server
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<State> state(new State);
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerThread serverThread(state, true);
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<EventLog>& log = state->getLog();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Make sure we're at the end of the log
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
state->getHandler()->prepareTriggeredCall();
|
|
|
|
|
|
|
|
|
|
// Make sure createContext() is called after a connection has been
|
|
|
|
|
// established. We open a plain socket instead of creating a client.
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", state->getPort()));
|
2012-05-10 09:01:45 +00:00
|
|
|
socket->open();
|
|
|
|
|
|
|
|
|
|
// Make sure the proper events occurred after a new connection
|
|
|
|
|
uint32_t connId = checkNewConnEvents(log);
|
|
|
|
|
|
|
|
|
|
// Send a message header. We manually construct the request so that we
|
|
|
|
|
// can test the timing for the preRead() call.
|
|
|
|
|
string requestName = "getDataWait";
|
|
|
|
|
string eventName = "ParentService.getDataWait";
|
2019-01-29 15:48:12 +01:00
|
|
|
auto seqid = int32_t(time(nullptr));
|
2012-05-10 09:01:45 +00:00
|
|
|
TBinaryProtocol protocol(socket);
|
|
|
|
|
protocol.writeMessageBegin(requestName, T_CALL, seqid);
|
|
|
|
|
socket->flush();
|
|
|
|
|
|
|
|
|
|
// Make sure we saw the call started and pre-read events
|
|
|
|
|
Event event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CALL_STARTED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(eventName, event.message);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
uint32_t callId = event.callId;
|
|
|
|
|
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_PRE_READ, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(eventName, event.message);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
|
|
|
|
|
// Make sure there are no new events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Send the rest of the request
|
|
|
|
|
protocol.writeStructBegin("ParentService_getDataNotified_pargs");
|
|
|
|
|
protocol.writeFieldBegin("length", apache::thrift::protocol::T_I32, 1);
|
2014-11-13 15:33:38 +01:00
|
|
|
protocol.writeI32(8 * 1024 * 1024);
|
2012-05-10 09:01:45 +00:00
|
|
|
protocol.writeFieldEnd();
|
|
|
|
|
protocol.writeFieldStop();
|
|
|
|
|
protocol.writeStructEnd();
|
|
|
|
|
protocol.writeMessageEnd();
|
|
|
|
|
socket->writeEnd();
|
|
|
|
|
socket->flush();
|
|
|
|
|
|
|
|
|
|
// We should then see postRead()
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_POST_READ, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(eventName, event.message);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
|
|
|
|
|
// Then the handler should be invoked
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CALL_GET_DATA_WAIT, event.type);
|
|
|
|
|
|
|
|
|
|
// The handler won't respond until we notify it.
|
|
|
|
|
// Make sure there are no more events.
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Notify the handler that it should return
|
|
|
|
|
// We just use a global lock for now, since it is easiest
|
|
|
|
|
state->getHandler()->triggerPendingCalls();
|
|
|
|
|
|
|
|
|
|
// The handler will log a separate event before it returns
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
|
|
|
|
|
|
|
|
|
|
// We should then see preWrite()
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_PRE_WRITE, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(eventName, event.message);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
|
|
|
|
|
// We requested more data than can be buffered, and we aren't reading it,
|
|
|
|
|
// so the server shouldn't be able to finish its write yet.
|
|
|
|
|
// Make sure there are no more events.
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Read the response header
|
2017-08-05 12:23:54 -04:00
|
|
|
string responseName;
|
2012-05-10 09:01:45 +00:00
|
|
|
int32_t responseSeqid = 0;
|
|
|
|
|
apache::thrift::protocol::TMessageType responseType;
|
|
|
|
|
protocol.readMessageBegin(responseName, responseType, responseSeqid);
|
|
|
|
|
BOOST_CHECK_EQUAL(responseSeqid, seqid);
|
|
|
|
|
BOOST_CHECK_EQUAL(requestName, responseName);
|
|
|
|
|
BOOST_CHECK_EQUAL(responseType, T_REPLY);
|
|
|
|
|
// Read the body. We just ignore it for now.
|
|
|
|
|
protocol.skip(T_STRUCT);
|
|
|
|
|
|
|
|
|
|
// Now that we have read, the server should have finished sending the data
|
|
|
|
|
// and called the postWrite() handler
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_POST_WRITE, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(eventName, event.message);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
|
|
|
|
|
// Call finished should be last
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(eventName, event.message);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
|
|
|
|
|
// There should be no more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Close the connection, and make sure we get a connection destroyed event
|
|
|
|
|
socket->close();
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CONN_DESTROYED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
|
|
|
|
|
// There should be no more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits, typename TemplateTraits>
|
2012-05-10 09:01:45 +00:00
|
|
|
void testSeparateConnections() {
|
2014-11-13 15:33:38 +01:00
|
|
|
typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Start the server
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<State> state(new State);
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerThread serverThread(state, true);
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<EventLog>& log = state->getLog();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Create a client
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<typename State::Client> client1 = state->createClient();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Make sure the expected events were logged
|
|
|
|
|
uint32_t client1Id = checkNewConnEvents(log);
|
|
|
|
|
|
|
|
|
|
// Create a second client
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<typename State::Client> client2 = state->createClient();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Make sure the expected events were logged
|
|
|
|
|
uint32_t client2Id = checkNewConnEvents(log);
|
|
|
|
|
|
|
|
|
|
// The two connections should have different IDs
|
|
|
|
|
BOOST_CHECK_NE(client1Id, client2Id);
|
|
|
|
|
|
|
|
|
|
// Make a call, and check for the proper events
|
|
|
|
|
int32_t value = 5;
|
|
|
|
|
client1->setValue(value);
|
2014-11-13 15:33:38 +01:00
|
|
|
uint32_t call1
|
|
|
|
|
= checkCallEvents(log, client1Id, EventLog::ET_CALL_SET_VALUE, "ChildService.setValue");
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Make a call with client2
|
|
|
|
|
int32_t v = client2->getValue();
|
|
|
|
|
BOOST_CHECK_EQUAL(value, v);
|
2014-11-13 15:33:38 +01:00
|
|
|
checkCallEvents(log, client2Id, EventLog::ET_CALL_GET_VALUE, "ChildService.getValue");
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Make another call with client1
|
|
|
|
|
v = client1->getValue();
|
|
|
|
|
BOOST_CHECK_EQUAL(value, v);
|
2014-11-13 15:33:38 +01:00
|
|
|
uint32_t call2
|
|
|
|
|
= checkCallEvents(log, client1Id, EventLog::ET_CALL_GET_VALUE, "ChildService.getValue");
|
2012-05-10 09:01:45 +00:00
|
|
|
BOOST_CHECK_NE(call1, call2);
|
|
|
|
|
|
|
|
|
|
// Close the second client, and check for the appropriate events
|
|
|
|
|
client2.reset();
|
|
|
|
|
checkCloseEvents(log, client2Id);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits, typename TemplateTraits>
|
2012-05-10 09:01:45 +00:00
|
|
|
void testOnewayCall() {
|
2014-11-13 15:33:38 +01:00
|
|
|
typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Start the server
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<State> state(new State);
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerThread serverThread(state, true);
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<EventLog>& log = state->getLog();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Create a client
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<typename State::Client> client = state->createClient();
|
2012-05-10 09:01:45 +00:00
|
|
|
uint32_t connId = checkNewConnEvents(log);
|
|
|
|
|
|
|
|
|
|
// Make a oneway call
|
|
|
|
|
// It should return immediately, even though the server's handler
|
|
|
|
|
// won't return right away
|
|
|
|
|
state->getHandler()->prepareTriggeredCall();
|
|
|
|
|
client->onewayWait();
|
|
|
|
|
string callName = "ParentService.onewayWait";
|
2014-11-13 15:33:38 +01:00
|
|
|
uint32_t callId = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_ONEWAY_WAIT, callName);
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// There shouldn't be any more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Trigger the handler to return
|
|
|
|
|
state->getHandler()->triggerPendingCalls();
|
|
|
|
|
|
|
|
|
|
// The handler will log an ET_WAIT_RETURN event when it wakes up
|
|
|
|
|
Event event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
|
|
|
|
|
|
|
|
|
|
// Now we should see the async complete event, then call finished
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_ASYNC_COMPLETE, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// Destroy the client, and check for connection closed events
|
|
|
|
|
client.reset();
|
|
|
|
|
checkCloseEvents(log, connId);
|
|
|
|
|
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits, typename TemplateTraits>
|
2012-05-10 09:01:45 +00:00
|
|
|
void testExpectedError() {
|
2014-11-13 15:33:38 +01:00
|
|
|
typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Start the server
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<State> state(new State);
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerThread serverThread(state, true);
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<EventLog>& log = state->getLog();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Create a client
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<typename State::Client> client = state->createClient();
|
2012-05-10 09:01:45 +00:00
|
|
|
uint32_t connId = checkNewConnEvents(log);
|
|
|
|
|
|
|
|
|
|
// Send the exceptionWait() call
|
|
|
|
|
state->getHandler()->prepareTriggeredCall();
|
|
|
|
|
string message = "test 1234 test";
|
|
|
|
|
client->send_exceptionWait(message);
|
|
|
|
|
string callName = "ParentService.exceptionWait";
|
2014-11-13 15:33:38 +01:00
|
|
|
uint32_t callId = checkCallHandlerEvents(log, connId, EventLog::ET_CALL_EXCEPTION_WAIT, callName);
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// There shouldn't be any more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Trigger the handler to return
|
|
|
|
|
state->getHandler()->triggerPendingCalls();
|
|
|
|
|
|
|
|
|
|
// The handler will log an ET_WAIT_RETURN event when it wakes up
|
|
|
|
|
Event event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
|
|
|
|
|
|
|
|
|
|
// Now receive the response
|
|
|
|
|
try {
|
|
|
|
|
client->recv_exceptionWait();
|
|
|
|
|
BOOST_FAIL("expected MyError to be thrown");
|
|
|
|
|
} catch (const MyError& e) {
|
|
|
|
|
BOOST_CHECK_EQUAL(message, e.message);
|
2015-05-18 17:58:36 +02:00
|
|
|
// Check if std::exception::what() is handled properly
|
2017-08-05 12:23:54 -04:00
|
|
|
size_t message_pos = string(e.what()).find("TException - service has thrown: MyError");
|
|
|
|
|
BOOST_CHECK_NE(message_pos, string::npos);
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now we should see the events for a normal call finish
|
|
|
|
|
checkCallPostHandlerEvents(log, connId, callId, callName);
|
|
|
|
|
|
|
|
|
|
// There shouldn't be any more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Destroy the client, and check for connection closed events
|
|
|
|
|
client.reset();
|
|
|
|
|
checkCloseEvents(log, connId);
|
|
|
|
|
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
template <typename ServerTraits, typename TemplateTraits>
|
2012-05-10 09:01:45 +00:00
|
|
|
void testUnexpectedError() {
|
2014-11-13 15:33:38 +01:00
|
|
|
typedef ServiceState<ServerTraits, ChildServiceTraits<TemplateTraits> > State;
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Start the server
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<State> state(new State);
|
2012-05-10 09:01:45 +00:00
|
|
|
ServerThread serverThread(state, true);
|
|
|
|
|
|
2019-01-05 16:35:14 +08:00
|
|
|
const std::shared_ptr<EventLog>& log = state->getLog();
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// Create a client
|
2019-01-05 16:35:14 +08:00
|
|
|
std::shared_ptr<typename State::Client> client = state->createClient();
|
2012-05-10 09:01:45 +00:00
|
|
|
uint32_t connId = checkNewConnEvents(log);
|
|
|
|
|
|
|
|
|
|
// Send the unexpectedExceptionWait() call
|
|
|
|
|
state->getHandler()->prepareTriggeredCall();
|
|
|
|
|
string message = "1234 test 5678";
|
|
|
|
|
client->send_unexpectedExceptionWait(message);
|
|
|
|
|
string callName = "ParentService.unexpectedExceptionWait";
|
2014-11-13 15:33:38 +01:00
|
|
|
uint32_t callId
|
|
|
|
|
= checkCallHandlerEvents(log, connId, EventLog::ET_CALL_UNEXPECTED_EXCEPTION_WAIT, callName);
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// There shouldn't be any more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Trigger the handler to return
|
|
|
|
|
state->getHandler()->triggerPendingCalls();
|
|
|
|
|
|
|
|
|
|
// The handler will log an ET_WAIT_RETURN event when it wakes up
|
|
|
|
|
Event event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_WAIT_RETURN, event.type);
|
|
|
|
|
|
|
|
|
|
// Now receive the response
|
|
|
|
|
try {
|
|
|
|
|
client->recv_unexpectedExceptionWait();
|
|
|
|
|
BOOST_FAIL("expected TApplicationError to be thrown");
|
2015-07-15 11:34:47 -05:00
|
|
|
} catch (const TApplicationException&) {
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now we should see a handler error event
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_HANDLER_ERROR, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// pre-write and post-write events aren't generated after a handler error
|
|
|
|
|
// (Even for non-oneway calls where a response is written.)
|
|
|
|
|
//
|
|
|
|
|
// A call finished event is logged when the call context is destroyed
|
|
|
|
|
event = log->waitForEvent();
|
|
|
|
|
BOOST_CHECK_EQUAL(EventLog::ET_CALL_FINISHED, event.type);
|
|
|
|
|
BOOST_CHECK_EQUAL(connId, event.connectionId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callId, event.callId);
|
|
|
|
|
BOOST_CHECK_EQUAL(callName, event.message);
|
|
|
|
|
|
|
|
|
|
// There shouldn't be any more events
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
|
|
|
|
|
// Destroy the client, and check for connection closed events
|
|
|
|
|
client.reset();
|
|
|
|
|
checkCloseEvents(log, connId);
|
|
|
|
|
|
|
|
|
|
checkNoEvents(log);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Macro to define simple tests that can be used with all server types
|
2014-11-13 15:33:38 +01:00
|
|
|
#define DEFINE_SIMPLE_TESTS(Server, Template) \
|
|
|
|
|
BOOST_AUTO_TEST_CASE(Server##_##Template##_basicService) { \
|
|
|
|
|
testBasicService<Server##Traits, Template##Traits>(); \
|
|
|
|
|
} \
|
|
|
|
|
BOOST_AUTO_TEST_CASE(Server##_##Template##_inheritedService) { \
|
|
|
|
|
testInheritedService<Server##Traits, Template##Traits>(); \
|
|
|
|
|
} \
|
|
|
|
|
BOOST_AUTO_TEST_CASE(Server##_##Template##_oneway) { \
|
|
|
|
|
testOnewayCall<Server##Traits, Template##Traits>(); \
|
|
|
|
|
} \
|
|
|
|
|
BOOST_AUTO_TEST_CASE(Server##_##Template##_exception) { \
|
|
|
|
|
testExpectedError<Server##Traits, Template##Traits>(); \
|
|
|
|
|
} \
|
|
|
|
|
BOOST_AUTO_TEST_CASE(Server##_##Template##_unexpectedException) { \
|
|
|
|
|
testUnexpectedError<Server##Traits, Template##Traits>(); \
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tests that require the server to process multiple connections concurrently
|
|
|
|
|
// (i.e., not TSimpleServer)
|
2014-11-13 15:33:38 +01:00
|
|
|
#define DEFINE_CONCURRENT_SERVER_TESTS(Server, Template) \
|
|
|
|
|
BOOST_AUTO_TEST_CASE(Server##_##Template##_separateConnections) { \
|
|
|
|
|
testSeparateConnections<Server##Traits, Template##Traits>(); \
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The testEventSequencing() test manually generates a request for the server,
|
|
|
|
|
// and doesn't work with TFramedTransport. Therefore we can't test it with
|
|
|
|
|
// TNonblockingServer.
|
2014-11-13 15:33:38 +01:00
|
|
|
#define DEFINE_NOFRAME_TESTS(Server, Template) \
|
|
|
|
|
BOOST_AUTO_TEST_CASE(Server##_##Template##_eventSequencing) { \
|
|
|
|
|
testEventSequencing<Server##Traits, Template##Traits>(); \
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
#define DEFINE_TNONBLOCKINGSERVER_TESTS(Server, Template) \
|
|
|
|
|
DEFINE_SIMPLE_TESTS(Server, Template) \
|
2012-05-10 09:01:45 +00:00
|
|
|
DEFINE_CONCURRENT_SERVER_TESTS(Server, Template)
|
|
|
|
|
|
2014-11-13 15:33:38 +01:00
|
|
|
#define DEFINE_ALL_SERVER_TESTS(Server, Template) \
|
|
|
|
|
DEFINE_SIMPLE_TESTS(Server, Template) \
|
|
|
|
|
DEFINE_CONCURRENT_SERVER_TESTS(Server, Template) \
|
2012-05-10 09:01:45 +00:00
|
|
|
DEFINE_NOFRAME_TESTS(Server, Template)
|
|
|
|
|
|
|
|
|
|
DEFINE_ALL_SERVER_TESTS(TThreadedServer, Templated)
|
|
|
|
|
DEFINE_ALL_SERVER_TESTS(TThreadedServer, Untemplated)
|
|
|
|
|
DEFINE_ALL_SERVER_TESTS(TThreadPoolServer, Templated)
|
|
|
|
|
DEFINE_ALL_SERVER_TESTS(TThreadPoolServer, Untemplated)
|
|
|
|
|
|
|
|
|
|
DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServer, Templated)
|
|
|
|
|
DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServer, Untemplated)
|
|
|
|
|
DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads, Templated)
|
|
|
|
|
DEFINE_TNONBLOCKINGSERVER_TESTS(TNonblockingServerNoThreads, Untemplated)
|
|
|
|
|
|
2014-10-22 23:26:01 +02:00
|
|
|
DEFINE_SIMPLE_TESTS(TSimpleServer, Templated)
|
|
|
|
|
DEFINE_SIMPLE_TESTS(TSimpleServer, Untemplated)
|
|
|
|
|
DEFINE_NOFRAME_TESTS(TSimpleServer, Templated)
|
|
|
|
|
DEFINE_NOFRAME_TESTS(TSimpleServer, Untemplated)
|
2012-05-10 09:01:45 +00:00
|
|
|
|
|
|
|
|
// TODO: We should test TEventServer in the future.
|
|
|
|
|
// For now, it is known not to work correctly with TProcessorEventHandler.
|
2016-01-04 23:05:19 +01:00
|
|
|
#ifdef BOOST_TEST_DYN_LINK
|
|
|
|
|
bool init_unit_test_suite() {
|
2017-08-05 12:23:54 -04:00
|
|
|
::boost::unit_test::framework::master_test_suite().p_name.value = "ProcessorTest";
|
2016-01-04 23:05:19 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc, char* argv[] ) {
|
|
|
|
|
return ::boost::unit_test::unit_test_main(&init_unit_test_suite,argc,argv);
|
|
|
|
|
}
|
|
|
|
|
#else
|
2017-08-05 12:23:54 -04:00
|
|
|
::boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
|
2014-11-06 19:32:59 +01:00
|
|
|
THRIFT_UNUSED_VARIABLE(argc);
|
|
|
|
|
THRIFT_UNUSED_VARIABLE(argv);
|
2017-08-05 12:23:54 -04:00
|
|
|
::boost::unit_test::framework::master_test_suite().p_name.value = "ProcessorTest";
|
2020-06-03 17:24:38 +08:00
|
|
|
return nullptr;
|
2012-05-10 09:01:45 +00:00
|
|
|
}
|
2016-01-04 23:05:19 +01:00
|
|
|
#endif
|