sync code

This commit is contained in:
Ned Wright
2024-10-14 14:51:28 +00:00
parent b58f7781e6
commit c2ea2cda6d
89 changed files with 2545 additions and 447 deletions

View File

@@ -14,10 +14,49 @@
#include "agent_details.h"
#include "mock/mock_messaging.h"
#include "tenant_manager.h"
#include <netdb.h>
#include <arpa/inet.h>
using namespace std;
using namespace testing;
static const string config_json_allow_external =
"{\n"
" \"connection\": {\n"
" \"Nano service API Port Primary\": [\n"
" {\n"
" \"value\": 9777\n"
" }\n"
" ],\n"
" \"Nano service API Port Alternative\": [\n"
" {\n"
" \"value\": 9778\n"
" }\n"
" ],\n"
" \"Nano service API Allow Get From External IP\": [\n"
" {\n"
" \"value\": true\n"
" }\n"
" ]\n"
" }\n"
"}\n";
static const string config_json =
"{\n"
" \"connection\": {\n"
" \"Nano service API Port Primary\": [\n"
" {\n"
" \"value\": 9777\n"
" }\n"
" ],\n"
" \"Nano service API Port Alternative\": [\n"
" {\n"
" \"value\": 9778\n"
" }\n"
" ]\n"
" }\n"
"}\n";
USE_DEBUG_FLAG(D_API);
USE_DEBUG_FLAG(D_MAINLOOP);
@@ -31,22 +70,6 @@ public:
time_proxy.init();
mainloop_comp.init();
string config_json =
"{\n"
" \"connection\": {\n"
" \"Nano service API Port Primary\": [\n"
" {\n"
" \"value\": 9777\n"
" }\n"
" ],\n"
" \"Nano service API Port Alternative\": [\n"
" {\n"
" \"value\": 9778\n"
" }\n"
" ]\n"
" }\n"
"}\n";
istringstream ss(config_json);
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss);
@@ -58,6 +81,9 @@ public:
~RestConfigTest()
{
Debug::setNewDefaultStdout(&cout);
auto mainloop = Singleton::Consume<I_MainLoop>::from(mainloop_comp);
mainloop->stopAll();
rest_server.fini();
time_proxy.fini();
mainloop_comp.fini();
}
@@ -133,7 +159,7 @@ int TestServer::g_num = 0;
TEST_F(RestConfigTest, basic_flow)
{
env.preload();
Singleton::Consume<I_Environment>::from(env)->registerValue<string>("Executable Name", "tmp_test_file");
Singleton::Consume<I_Environment>::from(env)->registerValue<string>("Base Executable Name", "tmp_test_file");
config.preload();
config.init();
@@ -165,11 +191,15 @@ TEST_F(RestConfigTest, basic_flow)
auto mainloop = Singleton::Consume<I_MainLoop>::from(mainloop_comp);
I_MainLoop::Routine stop_routine = [&] () {
EXPECT_EQ(connect(file_descriptor1, (struct sockaddr*)&sa, sizeof(struct sockaddr)), 0);
EXPECT_EQ(connect(file_descriptor1, (struct sockaddr*)&sa, sizeof(struct sockaddr)), 0)
<< "file_descriptor1 Error: "
<< strerror(errno);
string msg1 = "GET /stuff HTTP/1.1\r\n\r\n";
EXPECT_EQ(write(file_descriptor1, msg1.data(), msg1.size()), static_cast<int>(msg1.size()));
EXPECT_EQ(connect(file_descriptor2, (struct sockaddr*)&sa, sizeof(struct sockaddr)), 0);
EXPECT_EQ(connect(file_descriptor2, (struct sockaddr*)&sa, sizeof(struct sockaddr)), 0)
<< "file_descriptor2 Error: "
<< strerror(errno);
string msg2 = "POST /add-test HTTP/1.1\r\nContent-Length: 10\r\n\r\n{\"num\": 5}";
EXPECT_EQ(write(file_descriptor2, msg2.data(), msg2.size()), static_cast<int>(msg2.size()));
@@ -204,3 +234,159 @@ TEST_F(RestConfigTest, basic_flow)
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 6\r\n\r\nblabla"
);
}
string
getLocalIPAddress() {
char hostname[1024];
hostname[1024 - 1] = '\0';
// Get the hostname
if (gethostname(hostname, sizeof(hostname)) == -1) {
return "";
}
struct addrinfo hints, *info, *p;
int gai_result;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; // Use AF_INET for IPv4
hints.ai_socktype = SOCK_STREAM;
// Get the address info
if ((gai_result = getaddrinfo(hostname, nullptr, &hints, &info)) != 0) {
return "";
}
std::string ip_address;
for (p = info; p != nullptr; p = p->ai_next) {
void *addr;
char ipstr[INET_ADDRSTRLEN];
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
// Convert the IP to a string and print it
inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
if (std::string(ipstr) != "127.0.0.1") {
ip_address = ipstr;
break;
}
}
freeaddrinfo(info); // Free the linked list
return ip_address;
}
TEST_F(RestConfigTest, not_loopback_flow)
{
env.preload();
Singleton::Consume<I_Environment>::from(env)->registerValue<string>("Executable Name", "tmp_test_file");
istringstream ss(config_json_allow_external);
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss);
config.preload();
config.init();
rest_server.init();
time_proxy.init();
mainloop_comp.init();
auto i_rest = Singleton::Consume<I_RestApi>::from(rest_server);
ASSERT_TRUE(i_rest->addRestCall<TestServer>(RestAction::ADD, "test"));
ASSERT_TRUE(i_rest->addGetCall("stuff", [] () { return string("blabla"); }));
int file_descriptor1 = socket(AF_INET, SOCK_STREAM, 0);
EXPECT_NE(file_descriptor1, -1);
int file_descriptor2 = socket(AF_INET, SOCK_STREAM, 0);
EXPECT_NE(file_descriptor2, -1);
auto primary_port = getConfiguration<uint>("connection", "Nano service API Port Primary");
auto second_port = getConfiguration<uint>("connection", "Nano service API Port Alternative");
auto local_ip = getLocalIPAddress();
struct sockaddr_in sa_primary;
sa_primary.sin_family = AF_INET;
sa_primary.sin_port = htons(primary_port.unpack());
sa_primary.sin_addr.s_addr = inet_addr(local_ip.c_str());
struct sockaddr_in sa_second;
sa_second.sin_family = AF_INET;
sa_second.sin_port = htons(second_port.unpack());
sa_second.sin_addr.s_addr = inet_addr(local_ip.c_str());
int socket_enable = 1;
EXPECT_EQ(setsockopt(file_descriptor1, SOL_SOCKET, SO_REUSEADDR, &socket_enable, sizeof(int)), 0);
EXPECT_EQ(setsockopt(file_descriptor2, SOL_SOCKET, SO_REUSEADDR, &socket_enable, sizeof(int)), 0);
EXPECT_CALL(messaging, sendSyncMessage(_, _, _, _, _))
.WillRepeatedly(Return(HTTPResponse(HTTPStatusCode::HTTP_OK, "")));
Debug::setNewDefaultStdout(&cout);
auto mainloop = Singleton::Consume<I_MainLoop>::from(mainloop_comp);
Debug::setNewDefaultStdout(&cout);
I_MainLoop::Routine stop_routine = [&] () {
int socket_client_2 = -1;
auto socket_client_1 = connect(file_descriptor1, (struct sockaddr*)&sa_primary, sizeof(struct sockaddr));
dbgDebug(D_API) << "socket_client_1: " << socket_client_1;
if (socket_client_1 == -1) {
dbgDebug(D_API) << "Error: " << strerror(errno);
socket_client_2 = connect(file_descriptor1, (struct sockaddr*)&sa_second, sizeof(struct sockaddr));
dbgDebug(D_API) << "socket_client_2: " << socket_client_2;
if (socket_client_2 == -1) {
dbgDebug(D_API) << "Error: " << strerror(errno) << endl;
} else {
EXPECT_EQ(connect(file_descriptor2, (struct sockaddr*)&sa_second, sizeof(struct sockaddr)), 0);
string msg2 = "POST /add-test HTTP/1.1\r\nContent-Length: 10\r\n\r\n{\"num\": 5}";
EXPECT_EQ(write(file_descriptor2, msg2.data(), msg2.size()), static_cast<int>(msg2.size()));
}
} else {
EXPECT_EQ(connect(file_descriptor2, (struct sockaddr*)&sa_primary, sizeof(struct sockaddr)), 0);
string msg2 = "POST /add-test HTTP/1.1\r\nContent-Length: 10\r\n\r\n{\"num\": 5}";
EXPECT_EQ(write(file_descriptor2, msg2.data(), msg2.size()), static_cast<int>(msg2.size()));
}
EXPECT_TRUE(socket_client_1 != -1 || socket_client_2 != -1);
string msg1 = "GET /stuff HTTP/1.1\r\n\r\n";
EXPECT_EQ(write(file_descriptor1, msg1.data(), msg1.size()), static_cast<int>(msg1.size()));
mainloop->yield(true);
struct pollfd s_poll;
s_poll.fd = file_descriptor1;
s_poll.events = POLLIN;
s_poll.revents = 0;
while(poll(&s_poll, 1, 0) <= 0) {
mainloop->yield(true);
}
struct pollfd s_poll2;
s_poll2.fd = file_descriptor2;
s_poll2.events = POLLIN;
s_poll2.revents = 0;
while(poll(&s_poll2, 1, 0) <= 0) {
mainloop->yield(true);
}
mainloop->stopAll();
};
mainloop->addOneTimeRoutine(
I_MainLoop::RoutineType::RealTime,
stop_routine,
"RestConfigTest-alternative_port_used stop routine",
true
);
mainloop->run();
char respose[1000];
EXPECT_EQ(read(file_descriptor1, respose, 1000), 76);
EXPECT_EQ(
string(respose, 76),
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 6\r\n\r\nblabla"
);
EXPECT_EQ(read(file_descriptor2, respose, 1000), 89);
EXPECT_EQ(
string(respose, 89),
"HTTP/1.1 500 Internal Server Error\r\nContent-Type: application/json\r\nContent-Length: 0\r\n\r\n"
);
}

View File

@@ -437,7 +437,7 @@ TEST(RestSchema, server_schema)
env.preload();
Singleton::Consume<I_Environment>::from(env)->registerValue<string>("Executable Name", "tmp_test_file");
Singleton::Consume<I_Environment>::from(env)->registerValue<string>("Base Executable Name", "tmp_test_file");
config.preload();
config.init();