From 3cb78411178f8458f889975799060e0bb866d2cf Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Thu, 12 Jan 2023 10:04:13 +0100 Subject: Speed up webserver tests by improving wait for server --- tests/test-webserver.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/tests/test-webserver.cpp b/tests/test-webserver.cpp index 077c27e..727356d 100644 --- a/tests/test-webserver.cpp +++ b/tests/test-webserver.cpp @@ -59,10 +59,84 @@ const fs::path testConfigFilename{"./webserver.conf"}; const fs::path testCertFilename{"./testchain.pem"}; const fs::path testKeyFilename{"./testkey.pem"}; +// tcp: tcp or tcp6 +bool tcp_is_pid_listening_on(const std::string& tcp, pid_t pid, int port) +{ + std::string filename{fmt::format("/proc/{}/net/{}", pid, tcp)}; + std::ifstream f{filename, std::ios::in}; + // e.g.: + // sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + // 0: 00000000:C799 00000000:0000 0A 00000000:00000000 00:00000000 00000000 107 0 21869 1 00000000335416a4 100 0 0 10 0 + std::string s; + std::getline(f, s); // skip head line + while (std::getline(f, s)) { + boost::algorithm::trim_left(s); + + size_t pos_space1{s.find(' ')}; + if (pos_space1 == std::string::npos) + throw std::runtime_error("Expected first space in " + filename); + + size_t pos_colon1{s.find(':', pos_space1 + 1)}; + if (pos_colon1 == std::string::npos) + throw std::runtime_error("Expected first colon in " + filename); + + size_t pos_space2{s.find(' ', pos_colon1 + 1)}; + if (pos_space2 == std::string::npos) + throw std::runtime_error("Expected second space in " + filename); + + std::string port_s{s.substr(pos_colon1 + 1, pos_space2 - (pos_colon1 + 1))}; + auto current_port{std::stoul(port_s, nullptr, 16)}; + if (current_port != port) + continue; + + // now, we are in a line related to matching local port + + size_t pos_space3{s.find(' ', pos_space2 + 1)}; + if (pos_space3 == std::string::npos) + throw std::runtime_error("Expected third space in " + filename); + + size_t pos_space4{s.find(' ', pos_space3 + 1)}; + if (pos_space4 == std::string::npos) + throw std::runtime_error("Expected fourth space in " + filename); + + std::string state_s{s.substr(pos_space3 + 1, pos_space4 - (pos_space3 + 1))}; + if (state_s == "0A") // listening state TCP_LISTEN, from net/tcp_states.h + return true; + } + + return false; // not found +} + +bool is_pid_listening_on(pid_t pid, int port) +{ + return tcp_is_pid_listening_on("tcp", pid, port) || tcp_is_pid_listening_on("tcp6", pid, port); +} + +void wait_for_pid_listening_on(pid_t pid, int port) +{ + while (!is_pid_listening_on(pid, port)) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +// returns -1 if no port found in config +int port_from_config(const std::string& config) +{ + pt::ptree tree; + std::istringstream stream{config}; + pt::read_xml(stream, tree); + try { + return tree.get("webserver.sockets.socket.port"); + } catch(...) { + return -1; + } +} + class WebserverProcess { void init(const std::string& config) { + m_config = config; File::setFile(testConfigFilename, config); // test self signed certificate @@ -202,7 +276,9 @@ public: } // wait for server to start up - std::this_thread::sleep_for(std::chrono::milliseconds(200)); + if (int port{port_from_config(m_config)}; port >= 0) + wait_for_pid_listening_on(m_pid, port); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } void stop() @@ -247,6 +323,7 @@ public: private: pid_t m_pid; + std::string m_config; // child stdout std::shared_ptr<__gnu_cxx::stdio_filebuf> m_filebuf; @@ -576,7 +653,7 @@ public: exit(0); } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + wait_for_pid_listening_on(m_pid, 8765); } void stop() -- cgit v1.2.3