blob: 51039390430d4ce4804b11f88b80f47b9d141402 [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/UdpSocket.h"
#include "capu/os/Thread.h"
#include "capu/os/Mutex.h"
#include "capu/os/CondVar.h"
capu::Mutex mutex2;
capu::CondVar cv2;
capu::bool_t cond2;
class RandomPort
{
public:
/**
* Gets a Random Port between 1024 and 10024
*/
static capu::uint16_t get()
{
return (rand() % 10000) + 30000; // 0-1023 = Well Known, 1024-49151 = User, 49152 - 65535 = Dynamic
}
};
class ThreadClientUdpTest : public capu::Runnable {
capu::uint16_t port;
public:
//client thread to test data exchange between client and server
ThreadClientUdpTest(capu::uint16_t port) : port(port) {}
void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
capu::UdpSocket *clientSocket = new capu::UdpSocket();
capu::int32_t i = 5;
//try to connect to ipv6
EXPECT_TRUE(clientSocket->send((unsigned char*) &i, sizeof (capu::int32_t), "::1", port) == capu::CAPU_SOCKET_EADDR);
//wait for other side to start up
mutex2.lock();
while (!cond2) {
cv2.wait(&mutex2);
}
cond2 = false;
mutex2.unlock();
//send data
EXPECT_TRUE(clientSocket->send((unsigned char*) &i, sizeof (capu::int32_t), "127.0.0.1", port) == capu::CAPU_OK);
//receive
capu::status_t result = capu::CAPU_ERROR;
result = clientSocket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes, 0);
EXPECT_EQ(capu::CAPU_OK,result);
//check value
EXPECT_EQ(6,communication_variable);
mutex2.lock();
cond2 = true;
cv2.signal();
mutex2.unlock();
//socket close
EXPECT_EQ(capu::CAPU_OK, clientSocket->close());
delete clientSocket;
}
};
class ThreadTimeoutClientUdpTest : public capu::Runnable {
capu::uint16_t port;
public:
//timeout test
ThreadTimeoutClientUdpTest(capu::uint16_t port) : port(port) {}
void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
capu::Thread::Sleep(1000);
//ALLOCATION AND SYNCH OF cient and server
capu::UdpSocket *cli_socket = new capu::UdpSocket();
//timeout is 2 second;
cli_socket->setTimeout(2);
capu::int32_t i = 5;
//wait for other side to start up
mutex2.lock();
while (!cond2) {
cv2.wait(&mutex2);
}
cond2 = false;
mutex2.unlock();
//send data
EXPECT_EQ(capu::CAPU_OK, cli_socket->send((unsigned char*) &i, sizeof (capu::int32_t), "localhost", port));
//receive
EXPECT_EQ(capu::CAPU_ETIMEOUT, cli_socket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes, 0));
mutex2.lock();
cond2 = true;
cv2.signal();
mutex2.unlock();
//socket close
EXPECT_TRUE(cli_socket->close() == capu::CAPU_OK);
//deallocating
delete cli_socket;
}
};
class ThreadServerUdpTest : public capu::Runnable {
capu::uint16_t port;
public:
//SERVER thread to test data exchange between client and server
ThreadServerUdpTest(capu::uint16_t port) : port(port) {}
void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
//server socket allocation
capu::UdpSocket *serverSocket = new capu::UdpSocket();
//bind to given address
EXPECT_TRUE(serverSocket->bind(port, "127.0.0.1") == capu::CAPU_OK);
//receive data
capu::UdpSocket::SocketAddrInfo remoteSocket;
//receive
capu::status_t result = capu::CAPU_ERROR;
//send signal that server is ready to receive
mutex2.lock();
cond2 = true;
cv2.signal();
mutex2.unlock();
result = serverSocket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes, &remoteSocket);
EXPECT_TRUE(result == capu::CAPU_OK);
EXPECT_STREQ("127.0.0.1", remoteSocket.addr);
//check value
EXPECT_TRUE(communication_variable == 5);
//update data
communication_variable++;
//send it back
EXPECT_TRUE(serverSocket->send((unsigned char*) &communication_variable, sizeof (capu::int32_t), remoteSocket) == capu::CAPU_OK);
mutex2.lock();
while (!cond2) {
cv2.wait(&mutex2);
}
cond2 = false;
mutex2.unlock();
//close session
EXPECT_TRUE(serverSocket->close() == capu::CAPU_OK);
delete serverSocket;
}
};
class ThreadTimeoutServerUdpTest : public capu::Runnable {
capu::uint16_t port;
public:
//timeout test
ThreadTimeoutServerUdpTest(capu::uint16_t port) : port(port) {}
void run() {
capu::int32_t communication_variable;
capu::int32_t numBytes = 0;
//server socket allocation
capu::UdpSocket *serverSocket = new capu::UdpSocket();
//bind to given address
EXPECT_TRUE(serverSocket->bind(port) == capu::CAPU_OK);
//receive data
capu::status_t result = capu::CAPU_ERROR;
//send signal that server is ready to receive
mutex2.lock();
cond2 = true;
cv2.signal();
mutex2.unlock();
result = serverSocket->receive((unsigned char *) &communication_variable, sizeof (capu::int32_t), numBytes, NULL);
EXPECT_TRUE(result == capu::CAPU_OK);
//check value
EXPECT_TRUE(communication_variable == 5);
mutex2.lock();
while (!cond2) {
cv2.wait(&mutex2);
}
cond2 = false;
mutex2.unlock();
//close session
EXPECT_TRUE(serverSocket->close() == capu::CAPU_OK);
delete serverSocket;
}
};
TEST(UdpSocket, CloseReceiveAndSendTest) {
capu::uint16_t port = RandomPort::get();
capu::UdpSocket *socket = new capu::UdpSocket();
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, "localhost", port) == capu::CAPU_SOCKET_ESOCKET);
//try to receive data from closed socket
EXPECT_TRUE(socket->receive((unsigned char *) &i, 4, numBytes, NULL) == capu::CAPU_SOCKET_ESOCKET);
//Deallocation of socket
delete socket;
}
TEST(UdpSocket, SetAndGetPropertiesTest) {
capu::UdpSocket *socket = new capu::UdpSocket();
//TRY TO CHANGE THE PROPERTIES OF NOT CONNECTED SOCKET
EXPECT_TRUE(socket->setBufferSize(1024) == capu::CAPU_OK);
EXPECT_TRUE(socket->setTimeout(90) == capu::CAPU_OK);
capu::int32_t int_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->getTimeout(int_tmp) == capu::CAPU_OK);
EXPECT_TRUE(int_tmp == 90);
socket->close();
//TRY TO CHANGE THE PROPERTIES OF CLOSED SOCKET
EXPECT_TRUE(socket->setBufferSize(1024) == 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->getTimeout(int_tmp) == capu::CAPU_SOCKET_ESOCKET);
delete socket;
}
TEST(UdpSocketAndUdpServerSocket, CommunicationTest) {
cond2 = false;
capu::uint16_t port = RandomPort::get();
ThreadServerUdpTest server(port);
ThreadClientUdpTest 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(UdpSocketAndUdpServerSocket, TimeoutTest) {
cond2 = false;
capu::uint16_t port = RandomPort::get();
ThreadTimeoutServerUdpTest server(port);
ThreadTimeoutClientUdpTest 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;
}