#include <config.h>
-#include <client_exchange.h>
+#include <radius.h>
#include <testutils/gtest_utils.h>
#include <testutils/test_to_element.h>
#include <attribute_test.h>
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::radius;
+using namespace isc::tcp;
using namespace isc::test;
using namespace std;
using namespace std::chrono;
namespace {
-// Verify the async constructor.
-TEST(TestTcpExchange, factory) {
+// Verify the factory with TCP.
+TEST(TestTcpExchange, tcpFactory) {
ExchangePtr exchange;
IOServicePtr io_service;
MessagePtr msg;
// No message.
EXPECT_THROW_MSG(Exchange::create(io_service, msg, 0, servers,
- Exchange::Handler()),
+ Exchange::Handler(), PW_PROTO_TCP),
BadValue, "null request");
// No servers.
string secret = "foobar";
ASSERT_NO_THROW_LOG(msg.reset(new Message(code, 0, auth, secret, attrs)));
EXPECT_THROW_MSG(Exchange::create(io_service, msg, 0, servers,
- Exchange::Handler()),
+ Exchange::Handler(), PW_PROTO_TCP),
BadValue, "no server");
// No handler.
ASSERT_TRUE(server);
servers.push_back(server);
EXPECT_THROW_MSG(Exchange::create(io_service, msg, 0, servers,
- Exchange::Handler()),
+ Exchange::Handler(), PW_PROTO_TCP),
BadValue, "null handler");
- // No IO service.
+ // No error (note that the IOservice is unused).
auto handler = [] (const ExchangePtr) { };
- EXPECT_THROW_MSG(Exchange::create(io_service, msg, 0, servers, handler),
- BadValue, "null IO service");
+ ASSERT_NO_THROW_LOG(exchange = Exchange::create(io_service, msg, 0,
+ servers, handler,
+ PW_PROTO_TCP));
+
+ // Check exchange.
+ ASSERT_TRUE(exchange);
+ // getId returns a random value.
+ EXPECT_EQ(ERROR_RC, exchange->getRC());
+ MessagePtr request = exchange->getRequest();
+ ASSERT_TRUE(request);
+ EXPECT_EQ(request, msg);
+ MessagePtr response = exchange->getResponse();
+ EXPECT_FALSE(response);
+
+ // Verify it is an TCP Exchange.
+ EXPECT_TRUE(boost::dynamic_pointer_cast<TcpExchange>(exchange));
+}
- // No error.
- io_service.reset(new IOService());
+// Verify the factory with TLS.
+TEST(TestTcpExchange, tlsFactory) {
+ ExchangePtr exchange;
+ IOServicePtr io_service;
+ MessagePtr msg;
+ Servers servers;
+
+ // No message.
+ EXPECT_THROW_MSG(Exchange::create(io_service, msg, 0, servers,
+ Exchange::Handler(), PW_PROTO_TLS),
+ BadValue, "null request");
+
+ // No servers.
+ uint8_t code = PW_ACCOUNTING_REQUEST;
+ vector<uint8_t> auth;
+ AttributesPtr attrs;
+ string secret = "foobar";
+ ASSERT_NO_THROW_LOG(msg.reset(new Message(code, 0, auth, secret, attrs)));
+ EXPECT_THROW_MSG(Exchange::create(io_service, msg, 0, servers,
+ Exchange::Handler(), PW_PROTO_TLS),
+ BadValue, "no server");
+
+ // No handler.
+ ServerPtr server;
+ IOAddress addr("127.0.0.1");
+ TlsContextPtr tls_context;
+ ASSERT_NO_THROW_LOG(TlsContext::configure(tls_context,
+ TlsRole::CLIENT,
+ TEST_CA_DIR,
+ TEST_CA_DIR "/kea-client.crt",
+ TEST_CA_DIR "/kea-client.key"));
+ ASSERT_NO_THROW_LOG(server.reset(new Server(addr, 11646, addr, tls_context,
+ secret, 0)));
+ ASSERT_TRUE(server);
+ servers.push_back(server);
+ EXPECT_THROW_MSG(Exchange::create(io_service, msg, 0, servers,
+ Exchange::Handler(), PW_PROTO_TLS),
+ BadValue, "null handler");
+
+ // No error (note that the IOservice is unused).
+ auto handler = [] (const ExchangePtr) { };
ASSERT_NO_THROW_LOG(exchange = Exchange::create(io_service, msg, 0,
- servers, handler));
+ servers, handler,
+ PW_PROTO_TLS));
// Check exchange.
ASSERT_TRUE(exchange);
MessagePtr response = exchange->getResponse();
EXPECT_FALSE(response);
- // As a best practice, call any remaining handlers.
- io_service->stopAndPoll();
+ // Verify it is an TCP Exchange.
+ EXPECT_TRUE(boost::dynamic_pointer_cast<TcpExchange>(exchange));
}
-#if 0
/// Test Exchange class.
-class TestExchange : public UdpExchange {
+class TestExchange : public TcpExchange {
public:
/// Constructor.
///
- TestExchange(const asiolink::IOServicePtr io_service,
- const MessagePtr& request,
+ TestExchange(const MessagePtr& request,
unsigned maxretries,
const Servers& servers,
Exchange::Handler handler)
- : UdpExchange(io_service, request, maxretries, servers, handler) {
+ : TcpExchange(request, maxretries, servers, handler) {
}
/// Visible members.
using Exchange::identifier_;
using Exchange::sync_;
using Exchange::rc_;
+ using Exchange::sent_;
using Exchange::received_;
- using UdpExchange::started_;
- using UdpExchange::terminated_;
- using UdpExchange::start_time_;
- using UdpExchange::socket_;
- using UdpExchange::ep_;
- using UdpExchange::timer_;
- using UdpExchange::server_;
- using UdpExchange::idx_;
- using UdpExchange::sent_;
- using UdpExchange::buffer_;
- using UdpExchange::size_;
- using UdpExchange::retries_;
- using UdpExchange::postponed_;
+ using TcpExchange::start_time_;
+ using TcpExchange::server_;
/// Visible methods.
- using UdpExchange::buildRequest;
- using UdpExchange::open;
- using UdpExchange::receivedHandler;
+ using TcpExchange::buildRequest;
};
/// Type of shared pointers to test exchange objets.
typedef boost::shared_ptr<TestExchange> TestExchangePtr;
-
/// Test fixture for testing code of exchange class.
-class ExchangeTest : public radius::test::AttributeTest {
+class TcpExchangeTest : public radius::test::AttributeTest {
public:
// Constructor.
- ExchangeTest()
- : radius::test::AttributeTest (), io_service_(new IOService()),
+ TcpExchangeTest()
+ : radius::test::AttributeTest (), impl_(RadiusImpl::instance()),
+ io_service_(new IOService()),
code_(0), secret_("foobar"), addr_("127.0.0.1"),
port_(11460), timeout_(10), deadtime_(0), maxretries_(3),
called_(false),
handler_([this] (const ExchangePtr) { called_ = true; }) {
+ impl_.reset();
+ impl_.setIOService(io_service_);
+ impl_.setIOContext(io_service_);
+ impl_.proto_ = PW_PROTO_TCP;
+ impl_.tcp_client_.reset(new TcpClient(io_service_, false, 0));
}
// Destructor.
- virtual ~ExchangeTest() {
+ virtual ~TcpExchangeTest() {
if (exchange_) {
exchange_->shutdown();
}
servers_.clear();
- // As a best practice, call any remaining handlers before destroying the
- // IO context.
+ impl_.tcp_client_.reset();
+ // As a best practice, call any remaining handlers before
+ // destroying the IO context.
io_service_->stopAndPoll();
exchange_.reset();
// Create exchange.
void createExchange() {
- ASSERT_NO_THROW_LOG(exchange_.reset(new TestExchange(io_service_,
- request_,
+ ASSERT_NO_THROW_LOG(exchange_.reset(new TestExchange(request_,
maxretries_,
servers_,
handler_)));
ASSERT_TRUE(exchange_);
}
+ /// @brief Radius implementation.
+ RadiusImpl& impl_;
+
// IO service.
IOServicePtr io_service_;
};
// Verify the buildRequest method.
-TEST_F(ExchangeTest, buildRequest) {
+TEST_F(TcpExchangeTest, buildRequest) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
createExchange();
-
- // server_ is required.
- EXPECT_THROW_MSG(exchange_->buildRequest(), Unexpected, "no server");
- exchange_->server_ = servers_[0];
EXPECT_NO_THROW_LOG(exchange_->buildRequest());
// Check the to-be-sent message.
}
// Verify the buildRequest method for accounting and IPv6.
-TEST_F(ExchangeTest, buildRequest6) {
+TEST_F(TcpExchangeTest, buildRequest6) {
code_ = PW_ACCOUNTING_REQUEST;
createRequest();
addr_ = IOAddress("::1");
addServer();
createExchange();
-
- // server_ is required.
- EXPECT_THROW_MSG(exchange_->buildRequest(), Unexpected, "no server");
- exchange_->server_ = servers_[0];
EXPECT_NO_THROW_LOG(exchange_->buildRequest());
// Check the to-be-sent message.
<< "got: " << attrs->toText() << "\n";
}
+#if 0
// Verify exchange initial state and start.
-TEST_F(ExchangeTest, start) {
+TEST_F(TcpExchangeTest, start) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open in the initial case.
-TEST_F(ExchangeTest, openInit) {
+TEST_F(TcpExchangeTest, openInit) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open with next server being null.
-TEST_F(ExchangeTest, openNullServer) {
+TEST_F(TcpExchangeTest, openNullServer) {
code_ = PW_ACCESS_REQUEST;
createRequest();
ServerPtr null_server;
}
// Verify open with next server in hold-down state.
-TEST_F(ExchangeTest, openPostpone) {
+TEST_F(TcpExchangeTest, openPostpone) {
code_ = PW_ACCESS_REQUEST;
createRequest();
deadtime_ = 60;
}
// Verify open in second pass with no postponed servers.
-TEST_F(ExchangeTest, openNoPostponed) {
+TEST_F(TcpExchangeTest, openNoPostponed) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open in second pass with bad postponed index.
-TEST_F(ExchangeTest, openBadPostponed) {
+TEST_F(TcpExchangeTest, openBadPostponed) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open in second pass with null postponed server.
-TEST_F(ExchangeTest, openNullPostponed) {
+TEST_F(TcpExchangeTest, openNullPostponed) {
code_ = PW_ACCESS_REQUEST;
createRequest();
ServerPtr null_server;
}
// Verify open in second pass.
-TEST_F(ExchangeTest, openPostponed) {
+TEST_F(TcpExchangeTest, openPostponed) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open with error in send.
-TEST_F(ExchangeTest, openSendError) {
+TEST_F(TcpExchangeTest, openSendError) {
// Make the request encode to fail with too large message.
send_attrs_.reset(new Attributes());
string msg = "too too too too too too too too too too too too ";
}
// Verify open puts on timeout a server on hold-down.
-TEST_F(ExchangeTest, openHoldsDown) {
+TEST_F(TcpExchangeTest, openHoldsDown) {
code_ = PW_ACCESS_REQUEST;
createRequest();
deadtime_ = 60;
}
// Verify open tries next server after last retry.
-TEST_F(ExchangeTest, openNextServer) {
+TEST_F(TcpExchangeTest, openNextServer) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open terminates after the last retry of the last server.
-TEST_F(ExchangeTest, openLastServer) {
+TEST_F(TcpExchangeTest, openLastServer) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open in second pass tries next postponed server after last retry.
-TEST_F(ExchangeTest, openNextPostponedServer) {
+TEST_F(TcpExchangeTest, openNextPostponedServer) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
// Verify open in second pass terminates after the last retry of the last
// postponed server.
-TEST_F(ExchangeTest, openLastPostponedServer) {
+TEST_F(TcpExchangeTest, openLastPostponedServer) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open retries.
-TEST_F(ExchangeTest, openRetry) {
+TEST_F(TcpExchangeTest, openRetry) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify open with error in retry.
-TEST_F(ExchangeTest, openRetryError) {
+TEST_F(TcpExchangeTest, openRetryError) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify receivedHandler with null exchange.
-TEST_F(ExchangeTest, receivedHandlerNull) {
+TEST_F(TcpExchangeTest, receivedHandlerNull) {
auto no_error = boost::system::error_code();
EXPECT_THROW_MSG(TestExchange::receivedHandler(TestExchangePtr(), no_error, 0),
Unexpected,
}
// Verify receivedHandler on error.
-TEST_F(ExchangeTest, receivedHandlerError) {
+TEST_F(TcpExchangeTest, receivedHandlerError) {
code_ = PW_ACCESS_REQUEST;
createRequest();
addServer();
}
// Verify receivedHandler removes servers from hold-down.
-TEST_F(ExchangeTest, receivedHandlerNoHoldDown) {
+TEST_F(TcpExchangeTest, receivedHandlerNoHoldDown) {
code_ = PW_ACCESS_REQUEST;
createRequest();
deadtime_ = 60;