unittests: improved coverage for UDPSocket and TCPSocket

Add functional and line coverage for UDPSocket and TCPSocket. The EventFlagsstub and NetworkStackstub classes are allowed to store multiple return values to allow running internal loops multiple times.
pull/8341/head
Michal Paszta 2018-09-12 13:00:20 +02:00 committed by adbridge
parent cb80c49f3a
commit 2bbf033fe2
5 changed files with 354 additions and 14 deletions

View File

@ -17,10 +17,24 @@
#include "gtest/gtest.h"
#include "features/netsocket/TCPSocket.h"
#include "NetworkStack_stub.h"
// Control the rtos EventFlags stub. See EventFlags_stub.cpp
extern std::list<uint32_t> eventFlagsStubNextRetval;
// To test protected functions
class TCPSocketFriend : public TCPSocket {
friend class TestTCPSocket;
FRIEND_TEST(TestTCPSocket, get_proto);
};
class TestTCPSocket : public testing::Test {
public:
unsigned int dataSize = 10;
char dataBuf[10];
protected:
TCPSocket *socket;
NetworkStackstub stack;
virtual void SetUp()
{
@ -29,11 +43,227 @@ protected:
virtual void TearDown()
{
stack.return_values.clear();
eventFlagsStubNextRetval.clear();
delete socket;
}
};
TEST_F(TestTCPSocket, get_proto)
{
TCPSocketFriend tcpFriend;
EXPECT_EQ(tcpFriend.get_proto(), NSAPI_TCP);
}
TEST_F(TestTCPSocket, constructor)
{
EXPECT_TRUE(socket);
}
TEST_F(TestTCPSocket, constructor_parameters)
{
TCPSocket socketParam = TCPSocket(dynamic_cast<NetworkStack*>(&stack));
const SocketAddress a("127.0.0.1", 1024);
EXPECT_EQ(socketParam.connect(a), NSAPI_ERROR_OK);
}
/* connect */
TEST_F(TestTCPSocket, connect)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_OK;
const SocketAddress a("127.0.0.1", 1024);
EXPECT_EQ(socket->connect(a), NSAPI_ERROR_OK);
}
TEST_F(TestTCPSocket, connect_no_open)
{
stack.return_value = NSAPI_ERROR_OK;
const SocketAddress a("127.0.0.1", 1024);
EXPECT_EQ(socket->connect(a), NSAPI_ERROR_NO_SOCKET);
}
TEST_F(TestTCPSocket, connect_error_in_progress_no_timeout)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_IN_PROGRESS;
const SocketAddress a("127.0.0.1", 1024);
eventFlagsStubNextRetval.push_back(osFlagsError); // Break the wait loop
EXPECT_EQ(socket->connect(a), NSAPI_ERROR_IN_PROGRESS);
}
TEST_F(TestTCPSocket, connect_with_timeout)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_IN_PROGRESS;
const SocketAddress a("127.0.0.1", 1024);
eventFlagsStubNextRetval.push_back(osFlagsError); // Break the wait loop
socket->set_timeout(1);
EXPECT_EQ(socket->connect(a), NSAPI_ERROR_IN_PROGRESS);
}
TEST_F(TestTCPSocket, connect_error_is_connected)
{
socket->open((NetworkStack *)&stack);
stack.return_values.push_back(NSAPI_ERROR_ALREADY);
stack.return_values.push_back(NSAPI_ERROR_IS_CONNECTED);
const SocketAddress a("127.0.0.1", 1024);
socket->set_timeout(1);
EXPECT_EQ(socket->connect(a), NSAPI_ERROR_OK);
}
TEST_F(TestTCPSocket, connect_by_name_and_port)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_OK;
EXPECT_EQ(socket->connect("testhost", 80), NSAPI_ERROR_OK);
}
TEST_F(TestTCPSocket, connect_by_name_and_port_dns_fail)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_DNS_FAILURE;
EXPECT_EQ(socket->connect("testhost", 80), NSAPI_ERROR_DNS_FAILURE);
}
/* send */
TEST_F(TestTCPSocket, send_no_open)
{
stack.return_value = NSAPI_ERROR_OK;
EXPECT_EQ(socket->send(dataBuf, dataSize), NSAPI_ERROR_NO_SOCKET);
}
TEST_F(TestTCPSocket, send_in_one_chunk)
{
socket->open((NetworkStack *)&stack);
stack.return_value = dataSize;
EXPECT_EQ(socket->send(dataBuf, dataSize), dataSize);
}
TEST_F(TestTCPSocket, send_in_two_chunks)
{
socket->open((NetworkStack *)&stack);
stack.return_values.push_back(4);
stack.return_values.push_back(dataSize - 4);
EXPECT_EQ(socket->send(dataBuf, dataSize), dataSize);
}
TEST_F(TestTCPSocket, send_error_would_block)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_WOULD_BLOCK;
eventFlagsStubNextRetval.push_back(osFlagsError); // Break the wait loop
EXPECT_EQ(socket->send(dataBuf, dataSize), NSAPI_ERROR_WOULD_BLOCK);
}
TEST_F(TestTCPSocket, send_error_other)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_NO_MEMORY;
EXPECT_EQ(socket->send(dataBuf, dataSize), NSAPI_ERROR_NO_MEMORY);
}
TEST_F(TestTCPSocket, send_error_no_timeout)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_WOULD_BLOCK;
socket->set_timeout(0);
EXPECT_EQ(socket->send(dataBuf, dataSize), NSAPI_ERROR_WOULD_BLOCK);
}
TEST_F(TestTCPSocket, send_to)
{
socket->open((NetworkStack *)&stack);
stack.return_value = 10;
const SocketAddress a("127.0.0.1", 1024);
EXPECT_EQ(socket->sendto(a, dataBuf, dataSize), dataSize);
}
/* recv */
TEST_F(TestTCPSocket, recv_no_open)
{
stack.return_value = NSAPI_ERROR_OK;
EXPECT_EQ(socket->recv(dataBuf, dataSize), NSAPI_ERROR_NO_SOCKET);
}
TEST_F(TestTCPSocket, recv_all_data)
{
socket->open((NetworkStack *)&stack);
stack.return_value = dataSize;
EXPECT_EQ(socket->recv(dataBuf, dataSize), dataSize);
}
TEST_F(TestTCPSocket, recv_less_than_expected)
{
socket->open((NetworkStack *)&stack);
unsigned int lessThanDataSize = dataSize -1;
stack.return_values.push_back(lessThanDataSize);
EXPECT_EQ(socket->recv(dataBuf, dataSize), lessThanDataSize);
}
TEST_F(TestTCPSocket, recv_would_block)
{
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_WOULD_BLOCK;
eventFlagsStubNextRetval.push_back(0);
eventFlagsStubNextRetval.push_back(osFlagsError); // Break the wait loop
EXPECT_EQ(socket->recv(dataBuf, dataSize), NSAPI_ERROR_WOULD_BLOCK);
}
TEST_F(TestTCPSocket, recv_from)
{
stack.return_value = NSAPI_ERROR_OK;
SocketAddress a("127.0.0.1", 1024);
EXPECT_EQ(socket->recvfrom(&a, dataBuf, dataSize), NSAPI_ERROR_NO_SOCKET);
}
/* listen */
TEST_F(TestTCPSocket, listen_no_open)
{
stack.return_value = NSAPI_ERROR_OK;
EXPECT_EQ(socket->listen(1), NSAPI_ERROR_NO_SOCKET);
}
TEST_F(TestTCPSocket, listen)
{
stack.return_value = NSAPI_ERROR_OK;
socket->open((NetworkStack *)&stack);
EXPECT_EQ(socket->listen(1), NSAPI_ERROR_OK);
}
/* accept - will accept ever be used on TCPSocket, or is it just meant for TCPServer?
* accept currently always returns NULL - is this intended? Memory leak
* Perhaps we should make it return UNSUPPORTED ? */
TEST_F(TestTCPSocket, accept_no_open)
{
nsapi_error_t error;
stack.return_value = NSAPI_ERROR_OK;
EXPECT_EQ(socket->accept(&error), static_cast<TCPSocket*>(NULL));
EXPECT_EQ(error, NSAPI_ERROR_NO_SOCKET);
}
TEST_F(TestTCPSocket, accept)
{
nsapi_error_t error;
stack.return_value = NSAPI_ERROR_OK;
socket->open((NetworkStack *)&stack);
EXPECT_EQ(socket->accept(&error), static_cast<TCPSocket*>(NULL));
EXPECT_EQ(error, NSAPI_ERROR_OK);
}
TEST_F(TestTCPSocket, accept_would_block)
{
nsapi_error_t error;
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_WOULD_BLOCK;
eventFlagsStubNextRetval.push_back(0);
eventFlagsStubNextRetval.push_back(osFlagsError); // Break the wait loop
EXPECT_EQ(socket->accept(&error), static_cast<TCPSocket*>(NULL));
EXPECT_EQ(error, NSAPI_ERROR_WOULD_BLOCK);
}

View File

@ -5,6 +5,7 @@
set(unittest-sources
../features/netsocket/SocketAddress.cpp
../features/netsocket/NetworkStack.cpp
../features/netsocket/InternetSocket.cpp
../features/netsocket/TCPSocket.cpp
../features/frameworks/nanostack-libservice/source/libip4string/ip4tos.c
@ -15,6 +16,10 @@ set(unittest-test-sources
features/netsocket/TCPSocket/test_TCPSocket.cpp
stubs/Mutex_stub.cpp
stubs/mbed_assert_stub.c
stubs/equeue_stub.c
stubs/EventQueue_stub.cpp
stubs/mbed_shared_queues_stub.cpp
stubs/nsapi_dns_stub.cpp
stubs/EventFlags_stub.cpp
stubs/stoip4_stub.c
stubs/ip4tos_stub.c

View File

@ -26,21 +26,25 @@
* following the documentation of google test.
* [*](https://github.com/google/googletest/blob/master/googletest/docs/advanced.md)
*/
class stubUDPSocket : public UDPSocket {
class UDPSocketFriend : public UDPSocket {
friend class TestUDPSocket;
FRIEND_TEST(TestUDPSocket, get_proto);
};
// Control the rtos EventFlags stub. See EventFlags_stub.cpp
extern std::list<uint32_t> eventFlagsStubNextRetval;
class TestUDPSocket : public testing::Test {
protected:
stubUDPSocket *socket;
UDPSocket *socket;
NetworkStackstub stack;
unsigned int dataSize = 10;
char dataBuf[10];
virtual void SetUp()
{
socket = new stubUDPSocket;
socket = new UDPSocket;
stack.return_value = NSAPI_ERROR_OK;
socket->open((NetworkStack *)&stack);
}
virtual void TearDown()
@ -51,31 +55,92 @@ protected:
TEST_F(TestUDPSocket, get_proto)
{
EXPECT_EQ(socket->get_proto(), NSAPI_UDP);
UDPSocketFriend udpFriend;
EXPECT_EQ(udpFriend.get_proto(), NSAPI_UDP);
}
TEST_F(TestUDPSocket, sendto_addr_port)
{
// The code below causes a segfault. Should we add a check?
//EXPECT_EQ(socket->sendto("127.0.0.1", 0, 0, 0), NSAPI_ERROR_NO_SOCKET);
const SocketAddress a("127.0.0.1", 1024);
EXPECT_EQ(socket->sendto(a, 0, 0), NSAPI_ERROR_NO_SOCKET);
socket->open((NetworkStack *)&stack);
stack.return_value = NSAPI_ERROR_PARAMETER;
EXPECT_EQ(socket->sendto("127.0.0.1", 0, 0, 0), NSAPI_ERROR_DNS_FAILURE);
stack.return_value = NSAPI_ERROR_OK;
EXPECT_EQ(socket->sendto("127.0.0.1", 0, 0, 0), 0);
}
TEST_F(TestUDPSocket, sendto)
TEST_F(TestUDPSocket, connect)
{
SocketAddress addr("127.0.0.1", 1024);
stack.return_value = NSAPI_ERROR_OK;
const SocketAddress a("127.0.0.1", 1024);
socket->open((NetworkStack *)&stack);
stack.return_value = 100;
EXPECT_EQ(socket->sendto(addr, 0, 100), 100);
EXPECT_EQ(socket->send(dataBuf, dataSize), NSAPI_ERROR_NO_ADDRESS);
EXPECT_EQ(socket->connect(a), NSAPI_ERROR_OK);
stack.return_value = 100;
EXPECT_EQ(socket->send(dataBuf, dataSize), 100);
}
TEST_F(TestUDPSocket, sendto_timeout)
{
SocketAddress addr("127.0.0.1", 1024);
socket->open((NetworkStack *)&stack);
socket->set_timeout(0);
stack.return_value = NSAPI_ERROR_WOULD_BLOCK;
eventFlagsStubNextRetval.push_back(0);
eventFlagsStubNextRetval.push_back(osFlagsError); // Break the wait loop
EXPECT_EQ(socket->sendto(addr, 0, 100), NSAPI_ERROR_WOULD_BLOCK);
socket->set_timeout(-1);
stack.return_value = NSAPI_ERROR_NO_CONNECTION;
EXPECT_EQ(socket->sendto(addr, 0, 100), NSAPI_ERROR_NO_CONNECTION);
stack.return_value = NSAPI_ERROR_NO_MEMORY;
socket->set_timeout(1);
EXPECT_EQ(socket->sendto(addr, 0, 100), NSAPI_ERROR_NO_MEMORY);
}
TEST_F(TestUDPSocket, recv)
{
EXPECT_EQ(socket->recv(&dataBuf, dataSize), NSAPI_ERROR_NO_SOCKET);
socket->open((NetworkStack *)&stack);
stack.return_value = 100;
EXPECT_EQ(socket->recv(&dataBuf, dataSize), 100);
stack.return_value = NSAPI_ERROR_WOULD_BLOCK;
eventFlagsStubNextRetval.push_back(0);
eventFlagsStubNextRetval.push_back(osFlagsError); // Break the wait loop
EXPECT_EQ(socket->recv(&dataBuf, dataSize), NSAPI_ERROR_WOULD_BLOCK);
}
TEST_F(TestUDPSocket, recv_address_filtering)
{
socket->open((NetworkStack *)&stack);
SocketAddress a1("127.0.0.1", 1024);
SocketAddress a2("127.0.0.2", 1024);
EXPECT_EQ(socket->connect(a1), NSAPI_ERROR_OK);
stack.return_values.push_back(100); //This will not return, because wrong address is used.
stack.return_values.push_back(NSAPI_ERROR_NO_MEMORY); //Break the loop of waiting for data from a1.
EXPECT_EQ(socket->recvfrom(&a2, &dataBuf, dataSize), NSAPI_ERROR_NO_MEMORY);
stack.return_values.push_back(100);
EXPECT_EQ(socket->recvfrom(&a1, &dataBuf, dataSize), 100);
}
TEST_F(TestUDPSocket, unsupported_api)
{
nsapi_error_t error;
EXPECT_EQ(socket->accept(&error), static_cast<Socket *>(NULL));
EXPECT_EQ(error, NSAPI_ERROR_UNSUPPORTED);
EXPECT_EQ(socket->listen(1), NSAPI_ERROR_UNSUPPORTED);
}

View File

@ -17,6 +17,10 @@
#include <cstddef>
#include "rtos/EventFlags.h"
#include <list>
/** Store the next value to be returned by Event Flags member functions */
std::list<uint32_t> eventFlagsStubNextRetval;
rtos::EventFlags::EventFlags() {}
rtos::EventFlags::~EventFlags() {}
@ -38,5 +42,11 @@ uint32_t rtos::EventFlags::wait_all(uint32_t flags, uint32_t timeout, bool clear
}
uint32_t rtos::EventFlags::wait_any(uint32_t flags, uint32_t timeout, bool clear)
{
if (!eventFlagsStubNextRetval.empty())
{
uint32_t ret = eventFlagsStubNextRetval.front();
eventFlagsStubNextRetval.pop_front();
return ret;
}
return 0;
}

View File

@ -19,10 +19,11 @@
#define NETWORKSTACKSTUB_H
#include "netsocket/NetworkStack.h"
#include <list>
class NetworkStackstub : public NetworkStack {
public:
std::list<nsapi_error_t> return_values;
nsapi_error_t return_value = 0;
virtual const char *get_ip_address()
{
@ -46,6 +47,11 @@ public:
protected:
virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
{
if (return_value == NSAPI_ERROR_OK && return_values.front() == NSAPI_ERROR_OK)
{
// Make sure a non-NULL value is returned if error is not expected
*handle = reinterpret_cast<nsapi_socket_t*>(1234);
}
return return_value;
};
virtual nsapi_error_t socket_close(nsapi_socket_t handle)
@ -62,6 +68,12 @@ protected:
};
virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address)
{
if (!return_values.empty())
{
nsapi_error_t ret = return_values.front();
return_values.pop_front();
return ret;
}
return return_value;
};
virtual nsapi_error_t socket_accept(nsapi_socket_t server,
@ -72,11 +84,23 @@ protected:
virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
const void *data, nsapi_size_t size)
{
if (!return_values.empty())
{
nsapi_error_t ret = return_values.front();
return_values.pop_front();
return ret;
}
return return_value;
};
virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle,
void *data, nsapi_size_t size)
{
if (!return_values.empty())
{
nsapi_error_t ret = return_values.front();
return_values.pop_front();
return ret;
}
return return_value;
};
virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address,
@ -87,6 +111,12 @@ protected:
virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
void *buffer, nsapi_size_t size)
{
if (!return_values.empty())
{
nsapi_error_t ret = return_values.front();
return_values.pop_front();
return ret;
}
return return_value;
};
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) {};