summaryrefslogtreecommitdiffhomepage
path: root/tests/fastcgiprocess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/fastcgiprocess.cpp')
-rw-r--r--tests/fastcgiprocess.cpp115
1 files changed, 115 insertions, 0 deletions
diff --git a/tests/fastcgiprocess.cpp b/tests/fastcgiprocess.cpp
new file mode 100644
index 0000000..53b9d04
--- /dev/null
+++ b/tests/fastcgiprocess.cpp
@@ -0,0 +1,115 @@
+#include "fastcgiprocess.h"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/beast/core.hpp>
+#include <boost/beast/http.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/beast/websocket/ssl.hpp>
+#include <boost/beast/ssl.hpp>
+#include <boost/beast/version.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/buffers_iterator.hpp>
+#include <boost/asio/connect.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/ssl/error.hpp>
+#include <boost/asio/ssl/stream.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+
+#include <signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <libreichwein/file.h>
+#include <libreichwein/process.h>
+
+#include "helper.h"
+
+using namespace std::string_literals;
+namespace fs = std::filesystem;
+namespace pt = boost::property_tree;
+using namespace boost::unit_test;
+using namespace Reichwein;
+
+#define FCGI_LISTENSOCK_FILENO 0
+
+FastCGIProcess::FastCGIProcess(const std::filesystem::path& path, const std::string& host, unsigned short port):
+ m_pid{},
+ m_command{path.generic_string()},
+ m_host{host},
+ m_port{port}
+{
+ start();
+}
+
+FastCGIProcess::~FastCGIProcess()
+{
+ stop();
+}
+
+void FastCGIProcess::start()
+{
+ if (m_pid != 0)
+ throw std::runtime_error("Process already running, so it can't be started");
+
+ m_pid = fork();
+ if (m_pid < 0)
+ throw std::runtime_error("Fork unsuccessful.");
+
+ if (m_pid == 0) { // child process branch
+ try {
+ boost::asio::io_context ioc;
+ boost::asio::ip::tcp::resolver resolver(ioc);
+ auto const results = resolver.resolve(m_host.c_str(), std::to_string(m_port).c_str());
+ if (results.begin() == results.end())
+ std::runtime_error("no resolve result");
+ boost::asio::ip::tcp::endpoint endpoint{*results.begin()};
+ boost::asio::ip::tcp::acceptor acceptor(ioc);
+ acceptor.open(endpoint.protocol());
+ acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor.bind(endpoint);
+ acceptor.listen();
+ int fd{acceptor.native_handle()};
+
+ if (fd != FCGI_LISTENSOCK_FILENO) {
+ close(FCGI_LISTENSOCK_FILENO);
+ dup2(fd, FCGI_LISTENSOCK_FILENO);
+ close(fd);
+ }
+
+ execl(m_command.c_str(), m_command.c_str(), (const char*)nullptr);
+ } catch (const std::exception& ex) {
+ std::cout << "FastCGI process error: " << ex.what() << std::endl;
+ }
+ exit(0);
+ }
+
+ // wait for server to start up
+ wait_for_pid_listening_on(m_pid, m_port);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+}
+
+void FastCGIProcess::stop()
+{
+ if (m_pid == 0)
+ throw std::runtime_error("Process not running, so it can't be stopped");
+
+ if (kill(m_pid, SIGTERM) != 0)
+ throw std::runtime_error("Unable to kill process");
+
+ if (int result = waitpid(m_pid, NULL, 0); result != m_pid)
+ throw std::runtime_error("waitpid returned "s + std::to_string(result));
+
+ m_pid = 0;
+}
+
+bool FastCGIProcess::is_running()
+{
+ if (m_pid == 0)
+ return false;
+
+ return Reichwein::Process::is_running(m_pid);
+}
+