blob: 4a56e7a723fad712267cb47ff5ab76802d5a76aa [file] [log] [blame]
/* $Id$
*
* 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.
*/
#include <gtest/gtest.h>
#include "capu/os/ServerSocket.h"
#include "capu/os/Thread.h"
#include "capu/os/Socket.h"
#include "capu/os/Mutex.h"
#include "capu/os/CondVar.h"
capu::Mutex mutex;
capu::CondVar cv;
capu::bool_t cond = false;
class RandomPort
{
public:
/**
* Gets a Random Port between 1024 and 10024
*/
static capu::uint16_t get()
{
return (rand() % 10000) + 40000; // 0-1023 = Well Known, 1024-49151 = User, 49152 - 65535 = Dynamic
}
};
class ThreadClientTest : public capu::Runnable {
capu::int16_t port;
public:
//client thread to test data exchange between client and server
ThreadClientTest(capu::int16_t port) : port(port) {}
void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
//ALLOCATION AND SYNCH OF cient and server
capu::Socket *cli_socket = new capu::Socket();
//TRY TO CONNECT TO IPV6
EXPECT_TRUE(cli_socket->connect((unsigned char *) "::1", port) == capu::CAPU_SOCKET_EADDR);
//connects to he given id
capu::status_t result = capu::CAPU_ERROR;
//wait for server to start up
mutex.lock();
while (!cond) {
cv.wait(&mutex);
}
cond = false;
mutex.unlock();
result = capu::CAPU_ERROR;
capu::int32_t attemps = 0;
while (result != capu::CAPU_OK && attemps < 10) {
result = cli_socket->connect((unsigned char *) "localhost", port);
attemps++;
capu::Thread::Sleep(50);
}
EXPECT_TRUE(result == capu::CAPU_OK);
capu::int32_t i = 5;
//send data
EXPECT_TRUE(cli_socket->send((unsigned char*) &i, sizeof (capu::int32_t)) == capu::CAPU_OK);
//receive
capu::status_t res = cli_socket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes);
EXPECT_EQ(capu::CAPU_OK,res);
//CHECK VALUE
EXPECT_EQ(6,communication_variable);
mutex.lock();
cond = true;
cv.signal();
mutex.unlock();
//socket close
EXPECT_TRUE(cli_socket->close() == capu::CAPU_OK);
//deallocating
delete cli_socket;
}
};
class ThreadTimeoutClientTest : public capu::Runnable {
capu::int16_t port;
public:
//timeout test
ThreadTimeoutClientTest(capu::int16_t port) : port(port) {}
void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
capu::Socket *cli_socket = new capu::Socket();
//timeout is 2 second;
cli_socket->setTimeout(2);
//connects to he given id
capu::status_t result = capu::CAPU_ERROR;
//wait for server to start up
mutex.lock();
while (!cond) {
cv.wait(&mutex);
}
cond = false;
mutex.unlock();
result = cli_socket->connect((unsigned char *) "localhost", port);
EXPECT_TRUE(result == capu::CAPU_OK);
capu::int32_t i = 5;
//send data
EXPECT_TRUE(cli_socket->send((unsigned char*) &i, sizeof (capu::int32_t)) == capu::CAPU_OK);
//receive
EXPECT_EQ(capu::CAPU_ETIMEOUT, cli_socket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes));
//client has received timeout, server can close socket
mutex.lock();
cond = true;
cv.signal();
mutex.unlock();
//socket close
EXPECT_TRUE(cli_socket->close() == capu::CAPU_OK);
//deallocating
delete cli_socket;
}
};
class ThreadServerTest : public capu::Runnable {
capu::int16_t port;
public:
//SERVER thread to test data exchange between client and server
ThreadServerTest(capu::int16_t port) : port(port) {}
void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
//server socket allocation
capu::ServerSocket *socket = new capu::ServerSocket();
//bind to given address
EXPECT_TRUE(socket->bind(port, "0.0.0.0") == capu::CAPU_OK);
//start listening
EXPECT_TRUE(socket->listen(5) == capu::CAPU_OK);
//accept connection
//server is ready to accept clients
mutex.lock();
cond = true;
cv.signal();
mutex.unlock();
capu::Socket *new_socket = socket->accept();
//receive data
capu::status_t result = capu::CAPU_ERROR;
result = new_socket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes);
EXPECT_TRUE(result == capu::CAPU_OK);
//CHECK VALUE
EXPECT_TRUE(communication_variable == 5);
//update data
communication_variable++;
//send it back
EXPECT_TRUE(new_socket->send((unsigned char *) &communication_variable, sizeof (capu::int32_t)) == capu::CAPU_OK);
//wait with close until client has received data
mutex.lock();
while (!cond) {
cv.wait(&mutex);
}
cond = false;
mutex.unlock();
//close session
EXPECT_TRUE(new_socket->close() == capu::CAPU_OK);
//deallocate session identifier
delete new_socket;
EXPECT_EQ(capu::CAPU_OK, socket->close());
delete socket;
}
};
class ThreadTimeoutServerTest : public capu::Runnable {
capu::int16_t port;
public:
//timeout test
ThreadTimeoutServerTest(capu::int16_t port) : port(port) {}
inline void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
//server socket allocation
capu::ServerSocket *socket = new capu::ServerSocket();
//bind to given address
EXPECT_TRUE(socket->bind(port, "0.0.0.0") == capu::CAPU_OK);
//start listening
EXPECT_TRUE(socket->listen(5) == capu::CAPU_OK);
//server is ready to accept clients
mutex.lock();
cond = true;
cv.signal();
mutex.unlock();
//accept connection
capu::Socket *new_socket = socket->accept();
capu::status_t result = capu::CAPU_ERROR;
result = new_socket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes);
EXPECT_EQ(capu::CAPU_OK, result);
//CHECK VALUE
EXPECT_TRUE(communication_variable == 5);
//wait for timeout on client side
mutex.lock();
while (!cond) {
cv.wait(&mutex);
}
cond = false;
mutex.unlock();
//close session
EXPECT_TRUE(new_socket->close() == capu::CAPU_OK);
//deallocate session identifier
delete new_socket;
EXPECT_EQ(capu::CAPU_OK, socket->close());
delete socket;
}
};
TEST(Socket, ConnectTest) {
capu::Socket *socket = new capu::Socket();
//pass null
capu::uint16_t port = RandomPort::get();
EXPECT_TRUE(socket->connect(NULL, port) == capu::CAPU_EINVAL);
EXPECT_TRUE(socket->connect((unsigned char *)"www.test", port) == capu::CAPU_SOCKET_EADDR);
delete socket;
}
TEST(Socket, CloseReceiveAndSendTest) {
capu::Socket *socket = new capu::Socket();
capu::int32_t i = 0;
capu::int32_t numBytes = 0;
EXPECT_TRUE(socket->close() == capu::CAPU_OK);
//try to send data via closed socket
EXPECT_TRUE(socket->send((unsigned char *) "asda", 4) == capu::CAPU_SOCKET_ESOCKET);
//try to receive data from closed socket
EXPECT_TRUE(socket->receive((unsigned char *) &i, 4, numBytes) == capu::CAPU_SOCKET_ESOCKET);
//Deallocation of socket
delete socket;
}
TEST(Socket, SetAndGetPropertiesTest) {
capu::Socket *socket = new capu::Socket();
capu::uint16_t port = RandomPort::get();
capu::ServerSocket *serverSocket = new capu::ServerSocket();
//TRY TO CHANGE THE PROPERTIES OF NOT CONNECTED SOCKET
EXPECT_TRUE(socket->setBufferSize(1024) == capu::CAPU_OK);
EXPECT_TRUE(socket->setKeepAlive(true) == capu::CAPU_OK);
EXPECT_TRUE(socket->setLingerOption(true, 90) == capu::CAPU_OK);
EXPECT_TRUE(socket->setNoDelay(false) == capu::CAPU_OK);
EXPECT_TRUE(socket->setTimeout(90) == capu::CAPU_OK);
capu::int32_t int_tmp;
capu::bool_t bool_tmp;
//CHECK THE PROPERTIES ARE CORRECTLY SET
EXPECT_TRUE(socket->getBufferSize(int_tmp) == capu::CAPU_OK);
//On Linux the kernel adjust the buffer size and set it to doubles of given size (at least)
//therefore we have to check here for >=
EXPECT_TRUE(int_tmp >= 1024);
EXPECT_TRUE(socket->getKeepAlive(bool_tmp) == capu::CAPU_OK);
EXPECT_TRUE(bool_tmp == true);
EXPECT_TRUE(socket->getLingerOption(bool_tmp, int_tmp) == capu::CAPU_OK);
EXPECT_TRUE(int_tmp == 90);
EXPECT_TRUE(bool_tmp == true);
EXPECT_TRUE(socket->getNoDelay(bool_tmp) == capu::CAPU_OK);
EXPECT_TRUE(bool_tmp == false);
EXPECT_TRUE(socket->getTimeout(int_tmp) == capu::CAPU_OK);
EXPECT_TRUE(int_tmp == 90);
serverSocket->bind(port, "0.0.0.0");
serverSocket->listen(3);
socket->connect((unsigned char *) "127.0.0.1", port);
//TRY TO CHANGE THE PROPERTIES OF CONNECTED SOCKET
EXPECT_TRUE(socket->setBufferSize(2024) == capu::CAPU_OK);
EXPECT_TRUE(socket->setKeepAlive(false) == capu::CAPU_OK);
EXPECT_TRUE(socket->setLingerOption(false, 0) == capu::CAPU_OK);
EXPECT_TRUE(socket->setNoDelay(true) == capu::CAPU_OK);
EXPECT_TRUE(socket->setTimeout(92) == capu::CAPU_OK);
//CHECK THE PROPERTIES ARE CORRECTLY SET
EXPECT_TRUE(socket->getBufferSize(int_tmp) == capu::CAPU_OK);
//kernel adjust the buffer size and set it to doubles of given size (at least)
EXPECT_TRUE(int_tmp >= 2024);
EXPECT_TRUE(socket->getKeepAlive(bool_tmp) == capu::CAPU_OK);
EXPECT_TRUE(bool_tmp == false);
EXPECT_TRUE(socket->getLingerOption(bool_tmp, int_tmp) == capu::CAPU_OK);
EXPECT_TRUE(bool_tmp == false);
EXPECT_TRUE(socket->getNoDelay(bool_tmp) == capu::CAPU_OK);
EXPECT_TRUE(bool_tmp == true);
EXPECT_TRUE(socket->getTimeout(int_tmp) == capu::CAPU_OK);
EXPECT_TRUE(int_tmp == 92);
socket->close();
//TRY TO CHANGE THE PROPERTIES OF CLOSED SOCKET
EXPECT_TRUE(socket->setBufferSize(1024) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->setKeepAlive(true) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->setLingerOption(true, 90) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->setNoDelay(false) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->setTimeout(90) == capu::CAPU_SOCKET_ESOCKET);
//TRY TO GET PROPERTIES OF CLOSED SOCKET
EXPECT_TRUE(socket->getBufferSize(int_tmp) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->getKeepAlive(bool_tmp) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->getLingerOption(bool_tmp, int_tmp) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->getNoDelay(bool_tmp) == capu::CAPU_SOCKET_ESOCKET);
EXPECT_TRUE(socket->getTimeout(int_tmp) == capu::CAPU_SOCKET_ESOCKET);
delete socket;
delete serverSocket;
}
TEST(SocketAndServerSocket, CommunicationTest) {
cond = false;
capu::uint16_t port = RandomPort::get();
ThreadServerTest server(port);
ThreadClientTest client(port);
capu::Thread * server_thread = new capu::Thread(&server);
server_thread->start();
capu::Thread * client_thread = new capu::Thread(&client);
client_thread->start();
//Create two threads which will behave like client and server to test functionality
server_thread->join();
client_thread->join();
delete client_thread;
delete server_thread;
}
TEST(SocketAndServerSocket, TimeoutTest) {
cond = false;
capu::uint16_t port = RandomPort::get();
ThreadTimeoutServerTest server(port);
ThreadTimeoutClientTest client(port);
capu::Thread * server_thread = new capu::Thread(&server);
server_thread->start();
capu::Thread * client_thread = new capu::Thread(&client);
client_thread->start();
//client_thread two threads which will behave like client and server to test functionality
server_thread->join();
client_thread->join();
delete client_thread;
delete server_thread;
}