From 91529a777fd3f56aeadef19dc25e196ba2e1cc51 Mon Sep 17 00:00:00 2001 From: Mauro Sardara Date: Mon, 7 Sep 2020 19:58:45 +0200 Subject: [HICN-636] Add gtest framework and first tests for loop. Signed-off-by: Mauro Sardara Change-Id: I133c8adda125c430aa9c4a35fb63bf1d8585afe9 Signed-off-by: Mauro Sardara --- hicn-light/src/hicn/base/test/test-loop.cc | 291 +++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 hicn-light/src/hicn/base/test/test-loop.cc (limited to 'hicn-light/src/hicn/base/test/test-loop.cc') diff --git a/hicn-light/src/hicn/base/test/test-loop.cc b/hicn-light/src/hicn/base/test/test-loop.cc new file mode 100644 index 000000000..44684ef0e --- /dev/null +++ b/hicn-light/src/hicn/base/test/test-loop.cc @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2020 Cisco and/or its affiliates. + * Licensed 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 + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +class LoopTest : public ::testing::Test { + static constexpr uint16_t BUFFER_SIZE = 1024; + protected: + LoopTest() + : server_port_(9191), + loop_(nullptr), + timer_tick_(2000), + connection_socket_(-1), + event_(nullptr), + timer_(nullptr) { + } + + virtual ~LoopTest() { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + virtual void SetUp() { + // Code here will be called immediately after the constructor (right + // before each test). + } + + virtual void TearDown() { + // Code here will be called immediately after each test (right + // before the destructor). + } + + static int onFirstTimerExpiration(void *owner, int fd, void* arg) { + std::cout << "This function should never be called" << std::endl; + EXPECT_TRUE(false); + return -1; + } + + static int onSecondTimerExpiration(void *owner, int fd, void* arg) { + std::cout << "First timer expired. Cancel second timer." << std::endl; + LoopTest *test = (LoopTest *)(arg); + loop_event_unregister(test->timer_); + return 0; + } + + static int onTimerExpiration(void *owner, int fd, void* arg) { + // Create client socket + struct sockaddr_in addr; + int client_socket; + LoopTest *test = (LoopTest *)(arg); + + client_socket = socket(AF_INET, SOCK_STREAM, 0); + if (client_socket == -1) { + perror("socket"); + return -1; + } + + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.sin_family = AF_INET; + addr.sin_port = htons(test->server_port_); + + if (connect(client_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) { + perror("connect"); + return -1; + } + + if (send(client_socket, "Hello, world!\n", 14, 0) == -1){ + perror("send"); + return -1; + } + + close(client_socket); + loop_event_unregister(test->timer_); + + return 0; + } + + static int onNewConnection(void *owner, int fd, void* arg) { + LoopTest *test = (LoopTest *)arg; + struct sockaddr_in addr; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + + socklen_t addr_len = sizeof(struct sockaddr_in); + int ret; + + int client_fd = accept(test->connection_socket_, (struct sockaddr*)(&addr), &addr_len); + if (client_fd == -1) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "accept failed"); + } + + perror("accept"); + return -1; + } + + // Read whatever data available and close connection. + ret = read(client_fd, test->buffer, BUFFER_SIZE); + if (ret < 0) { + perror("read"); + return -1; + } + + test->buffer[ret] = '\0'; + std::cout << "Received: " << (char*)test->buffer << std::endl; + + close(client_fd); + loop_event_unregister(test->event_); + + return 0; + } + + void createTcpSocketServer() { + struct sockaddr_in addr; + int ret; + + /* Create local socket. */ + + connection_socket_ = socket(AF_INET, SOCK_STREAM, 0); + if (connection_socket_ == -1) { + perror("socket"); + return; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(server_port_); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(connection_socket_, (const struct sockaddr *) &addr, + sizeof(struct sockaddr_in)); + if (ret == -1) { + perror("bind"); + return; + } + + ret = listen(connection_socket_, 20); + if (ret == -1) { + perror("listen"); + return; + } +} + + uint16_t server_port_; + loop_t *loop_; + unsigned timer_tick_; + int connection_socket_; + event_t *event_; + event_t *timer_; + char buffer[BUFFER_SIZE]; +}; + +TEST_F(LoopTest, LoopCreate) +{ + loop_ = loop_create(); + EXPECT_TRUE(loop_ != NULL); +} + +TEST_F(LoopTest, LoopFree) +{ + loop_ = loop_create(); + loop_free (loop_); + EXPECT_TRUE(loop_ != NULL); +} + +TEST_F(LoopTest, EventCreateAndFree) +{ + int ret; + + // Fake fd + int fd = 1; + loop_ = loop_create(); + + ret = loop_fd_event_create(&event_, loop_, fd, nullptr, &LoopTest::onNewConnection, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(event_); + + // Register the event + ret = loop_fd_event_register(event_); + EXPECT_TRUE(ret >= 0); + + // Unregister the event + ret = loop_event_unregister(event_); + EXPECT_TRUE(ret >= 0); + + // Free event loop + loop_free (loop_); +} + +TEST_F(LoopTest, TimerCreateAndCancel) +{ + int ret; + event_t *timer2; + loop_ = loop_create(); + + ret = loop_timer_create(&timer_, loop_, nullptr, &LoopTest::onFirstTimerExpiration, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer_); + + ret = loop_timer_create(&timer2, loop_, nullptr, &LoopTest::onSecondTimerExpiration, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer2); + + // Register the 1st timer + ret = loop_timer_register(timer_, timer_tick_); + EXPECT_TRUE(ret >= 0); + + // Register the 2nd timer + ret = loop_timer_register(timer2, timer_tick_ / 2); + EXPECT_TRUE(ret >= 0); + + loop_dispatch(loop_); + + loop_undispatch(loop_); + + // Unregister the events + ret = loop_event_unregister(timer_); + ret += loop_event_unregister(timer2); + EXPECT_TRUE(ret >= 0); + + // Free event loop + loop_free (loop_); +} + +TEST_F(LoopTest, LoopDispatch) +{ + int ret; + + // Create new unix socket + createTcpSocketServer(); + loop_ = loop_create(); + + ret = loop_fd_event_create(&event_, loop_, connection_socket_, nullptr, &LoopTest::onNewConnection, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(event_); + + ret = loop_fd_event_register(event_); + EXPECT_TRUE(ret >= 0); + + // Create timer. + ret = loop_timer_create(&timer_, loop_, nullptr, &LoopTest::onTimerExpiration, this); + EXPECT_TRUE(ret >= 0); + EXPECT_TRUE(timer_); + + ret = loop_timer_register(timer_, timer_tick_); + EXPECT_TRUE(ret >= 0); + + // Start event dispatching + loop_dispatch(loop_); + + // Stop dispatching + loop_undispatch(loop_); + + // Free events + loop_event_free(timer_); + loop_event_free(event_); + + // Free event loop + loop_free (loop_); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} -- cgit 1.2.3-korg