diff options
| author | Stefan Boberg <[email protected]> | 2023-04-24 15:53:30 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2023-04-24 15:53:30 +0200 |
| commit | 9ee1a686c29b7ab18207c2963497337532f441cb (patch) | |
| tree | 17d2681767e92603b7199d88235a775e5ca354ab | |
| parent | added changelog comment (diff) | |
| parent | fixed dashboard file serving bug (#255) (diff) | |
| download | zen-9ee1a686c29b7ab18207c2963497337532f441cb.tar.xz zen-9ee1a686c29b7ab18207c2963497337532f441cb.zip | |
Merge branch 'main' of https://github.com/EpicGames/zen
| -rw-r--r-- | xmake.lua | 2 | ||||
| -rw-r--r-- | zen/zen.cpp | 2 | ||||
| -rw-r--r-- | zencore/include/zencore/testing.h | 54 | ||||
| -rw-r--r-- | zencore/testing.cpp | 52 | ||||
| -rw-r--r-- | zenhttp/httpasio.cpp | 5 | ||||
| -rw-r--r-- | zenhttp/httpsys.cpp | 13 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/httpserver.h | 2 | ||||
| -rw-r--r-- | zenserver-test/zenserver-test.cpp | 42 | ||||
| -rw-r--r-- | zenserver/frontend/frontend.cpp | 2 | ||||
| -rw-r--r-- | zenserver/zenserver.cpp | 2 | ||||
| -rw-r--r-- | zenutil/include/zenutil/zenserverprocess.h | 14 | ||||
| -rw-r--r-- | zenutil/zenserverprocess.cpp | 24 |
12 files changed, 177 insertions, 37 deletions
@@ -111,6 +111,8 @@ if is_os("windows") then set_description("Enable http.sys server") option_end() add_define_by_config("ZEN_WITH_HTTPSYS", "httpsys") +else + add_defines("ZEN_WITH_HTTPSYS=0") end option("compute") diff --git a/zen/zen.cpp b/zen/zen.cpp index 5a34ffa80..9754f4434 100644 --- a/zen/zen.cpp +++ b/zen/zen.cpp @@ -27,7 +27,7 @@ #include <zenhttp/httpcommon.h> #if ZEN_WITH_TESTS -# define ZEN_TEST_WITH_RUNNER +# define ZEN_TEST_WITH_RUNNER 1 # include <zencore/testing.h> #endif diff --git a/zencore/include/zencore/testing.h b/zencore/include/zencore/testing.h index bd55524aa..a00ee3166 100644 --- a/zencore/include/zencore/testing.h +++ b/zencore/include/zencore/testing.h @@ -4,24 +4,64 @@ #include <zencore/zencore.h> -#ifdef ZEN_TEST_WITH_RUNNER -# define CATCH_CONFIG_RUNNER +#include <memory> + +#ifndef ZEN_TEST_WITH_RUNNER +# define ZEN_TEST_WITH_RUNNER 0 +#endif + +#if ZEN_TEST_WITH_RUNNER # define DOCTEST_CONFIG_IMPLEMENT #endif #if ZEN_WITH_TESTS # include <doctest/doctest.h> -# define ZEN_RUN_TESTS(argC, argV) doctest::Context(argc, argv).run() inline auto Approx(auto Value) { return doctest::Approx(Value); } -#else -# define ZEN_RUN_TESTS(argC, argV) #endif -#ifdef ZEN_TEST_WITH_RUNNER -# undef CATCH_CONFIG_RUNNER +/** + * Test runner helper + * + * This acts as a thin layer between the test app and the test + * framework, which is used to customize configuration logic + * and to set up logging. + * + * If you don't want to implement custom setup then the + * ZEN_RUN_TESTS macro can be used instead. + */ + +#if ZEN_WITH_TESTS +namespace zen::testing { + +class TestRunner +{ +public: + TestRunner(); + ~TestRunner(); + + int ApplyCommandLine(int argc, char const* const* argv); + int Run(); + +private: + struct Impl; + + std::unique_ptr<Impl> m_Impl; +}; + +# define ZEN_RUN_TESTS(argC, argV) \ + [&] { \ + zen::testing::TestRunner Runner; \ + Runner.ApplyCommandLine(argC, argV); \ + return Runner.Run(); \ + }() + +} // namespace zen::testing +#endif + +#if ZEN_TEST_WITH_RUNNER # undef DOCTEST_CONFIG_IMPLEMENT #endif diff --git a/zencore/testing.cpp b/zencore/testing.cpp new file mode 100644 index 000000000..15be4b716 --- /dev/null +++ b/zencore/testing.cpp @@ -0,0 +1,52 @@ +#include "zencore/testing.h" +#include "zencore/logging.h" + +#if ZEN_WITH_TESTS + +namespace zen::testing { + +using namespace std::literals; + +struct TestRunner::Impl +{ + doctest::Context Session; +}; + +TestRunner::TestRunner() +{ + m_Impl = std::make_unique<Impl>(); +} + +TestRunner::~TestRunner() +{ +} + +int +TestRunner::ApplyCommandLine(int argc, char const* const* argv) +{ + m_Impl->Session.applyCommandLine(argc, argv); + + for (int i = 1; i < argc; ++i) + { + if (argv[i] == "--debug"sv) + { + spdlog::set_level(spdlog::level::debug); + } + } + + return 0; +} + +int +TestRunner::Run() +{ + int Rv = 0; + + m_Impl->Session.run(); + + return Rv; +} + +} // namespace zen::testing + +#endif diff --git a/zenhttp/httpasio.cpp b/zenhttp/httpasio.cpp index f270c9d2b..510b349f9 100644 --- a/zenhttp/httpasio.cpp +++ b/zenhttp/httpasio.cpp @@ -1077,8 +1077,9 @@ HttpAsioServerRequest::HttpAsioServerRequest(asio_http::HttpRequest& Request, Ht std::string_view Uri = Request.Url(); Uri.remove_prefix(std::min(PrefixLength, static_cast<int>(Uri.size()))); - m_Uri = Uri; - m_QueryString = Request.QueryString(); + m_Uri = Uri; + m_UriWithExtension = Uri; + m_QueryString = Request.QueryString(); m_Verb = Request.RequestVerb(); m_ContentLength = Request.Body().Size(); diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index 16ec135cd..0f4fe0a6d 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -1232,6 +1232,9 @@ HttpSysServerRequest::HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& std::string_view UriSuffix8{m_UriUtf8}; + m_UriWithExtension = UriSuffix8; // Retain URI with extension for user access + m_Uri = UriSuffix8; + const size_t LastComponentIndex = UriSuffix8.find_last_of('/'); if (LastComponentIndex != std::string_view::npos) @@ -1244,22 +1247,18 @@ HttpSysServerRequest::HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& if (LastDotIndex != std::string_view::npos) { UriSuffix8.remove_prefix(LastDotIndex + 1); + m_Uri.remove_suffix(UriSuffix8.size() + 1); AcceptContentType = ParseContentType(UriSuffix8); - - if (AcceptContentType != HttpContentType::kUnknownContentType) - { - m_UriUtf8.RemoveSuffix((uint32_t)(UriSuffix8.size() + 1)); - } } } else { m_UriUtf8.Reset(); + m_Uri = {}; + m_UriWithExtension = {}; } - m_Uri = std::string_view(m_UriUtf8); - if (uint16_t QueryStringLength = HttpRequestPtr->CookedUrl.QueryStringLength) { --QueryStringLength; // We skip the leading question mark diff --git a/zenhttp/include/zenhttp/httpserver.h b/zenhttp/include/zenhttp/httpserver.h index 451a47b4a..3b9fa50b4 100644 --- a/zenhttp/include/zenhttp/httpserver.h +++ b/zenhttp/include/zenhttp/httpserver.h @@ -34,6 +34,7 @@ public: // Synchronous operations [[nodiscard]] inline std::string_view RelativeUri() const { return m_Uri; } // Returns URI without service prefix + [[nodiscard]] std::string_view RelativeUriWithExtension() const { return m_UriWithExtension; } [[nodiscard]] inline std::string_view QueryString() const { return m_QueryString; } struct QueryParams @@ -118,6 +119,7 @@ protected: HttpContentType m_AcceptType = HttpContentType::kUnknownContentType; uint64_t m_ContentLength = ~0ull; std::string_view m_Uri; + std::string_view m_UriWithExtension; std::string_view m_QueryString; mutable uint32_t m_RequestId = ~uint32_t(0); mutable Oid m_SessionId = Oid::Zero; diff --git a/zenserver-test/zenserver-test.cpp b/zenserver-test/zenserver-test.cpp index 1f320f2f6..3195181d1 100644 --- a/zenserver-test/zenserver-test.cpp +++ b/zenserver-test/zenserver-test.cpp @@ -300,7 +300,7 @@ main() return 0; } #elif 0 -//#include <restinio/all.hpp> +// #include <restinio/all.hpp> int main() @@ -317,6 +317,8 @@ zen::ZenServerEnvironment TestEnv; int main(int argc, char** argv) { + using namespace std::literals; + # if ZEN_USE_MIMALLOC mi_version(); # endif @@ -333,11 +335,31 @@ main(int argc, char** argv) std::filesystem::path ProgramBaseDir = std::filesystem::path(argv[0]).parent_path(); std::filesystem::path TestBaseDir = ProgramBaseDir.parent_path().parent_path() / ".test"; - TestEnv.InitializeForTest(ProgramBaseDir, TestBaseDir); + // This is pretty janky because we're passing most of the options through to the test + // framework, so we can't just use cxxopts (I think). This should ideally be cleaned up + // somehow in the future + + std::string ServerClass; + + for (int i = 1; i < argc; ++i) + { + if (argv[i] == "--http"sv) + { + if ((i + 1) < argc) + { + ServerClass = argv[++i]; + } + } + } + + TestEnv.InitializeForTest(ProgramBaseDir, TestBaseDir, ServerClass); ZEN_INFO("Running tests...(base dir: '{}')", TestBaseDir); - return ZEN_RUN_TESTS(argc, argv); + zen::testing::TestRunner Runner; + Runner.ApplyCommandLine(argc, argv); + + return Runner.Run(); } namespace zen::tests { @@ -454,7 +476,7 @@ TEST_CASE("project.basic") ZenServerInstance Instance1(TestEnv); Instance1.SetTestDir(TestDir); - Instance1.SpawnServer(PortNumber, "--http asio"); + Instance1.SpawnServer(PortNumber); Instance1.WaitUntilReady(); std::atomic<uint64_t> RequestCount{0}; @@ -1711,19 +1733,17 @@ TEST_CASE("zcache.failing.upstream") using namespace std::literals; using namespace utils; - const uint16_t Upstream1PortNumber = 13338; - ZenConfig Upstream1Cfg = ZenConfig::New(Upstream1PortNumber); - Upstream1Cfg.Args += (" --http asio"); + const uint16_t Upstream1PortNumber = 13338; + ZenConfig Upstream1Cfg = ZenConfig::New(Upstream1PortNumber); ZenServerInstance Upstream1Server(TestEnv); - const uint16_t Upstream2PortNumber = 13339; - ZenConfig Upstream2Cfg = ZenConfig::New(Upstream2PortNumber); - Upstream2Cfg.Args += (" --http asio"); + const uint16_t Upstream2PortNumber = 13339; + ZenConfig Upstream2Cfg = ZenConfig::New(Upstream2PortNumber); ZenServerInstance Upstream2Server(TestEnv); std::vector<std::uint16_t> UpstreamPorts = {Upstream1PortNumber, Upstream2PortNumber}; ZenConfig LocalCfg = ZenConfig::NewWithThreadedUpstreams(UpstreamPorts, false); - LocalCfg.Args += (" --http asio --upstream-thread-count 2"); + LocalCfg.Args += (" --upstream-thread-count 2"); ZenServerInstance LocalServer(TestEnv); const uint16_t LocalPortNumber = 13337; const auto LocalUri = fmt::format("http://localhost:{}/z$", LocalPortNumber); diff --git a/zenserver/frontend/frontend.cpp b/zenserver/frontend/frontend.cpp index e0b27ac55..149d97924 100644 --- a/zenserver/frontend/frontend.cpp +++ b/zenserver/frontend/frontend.cpp @@ -75,7 +75,7 @@ HttpFrontendService::HandleRequest(zen::HttpServerRequest& Request) { using namespace std::literals; - std::string_view Uri = Request.RelativeUri(); + std::string_view Uri = Request.RelativeUriWithExtension(); for (; Uri[0] == '/'; Uri = Uri.substr(1)) ; if (Uri.empty()) diff --git a/zenserver/zenserver.cpp b/zenserver/zenserver.cpp index 443bb627e..5b861f1bc 100644 --- a/zenserver/zenserver.cpp +++ b/zenserver/zenserver.cpp @@ -50,7 +50,7 @@ ZEN_THIRD_PARTY_INCLUDES_END // in some shared code into the executable #if ZEN_WITH_TESTS -# define ZEN_TEST_WITH_RUNNER +# define ZEN_TEST_WITH_RUNNER 1 # include <zencore/testing.h> #endif diff --git a/zenutil/include/zenutil/zenserverprocess.h b/zenutil/include/zenutil/zenserverprocess.h index 3ec4b19b0..1c204c144 100644 --- a/zenutil/include/zenutil/zenserverprocess.h +++ b/zenutil/include/zenutil/zenserverprocess.h @@ -20,19 +20,21 @@ public: ~ZenServerEnvironment(); void Initialize(std::filesystem::path ProgramBaseDir); - void InitializeForTest(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir); + void InitializeForTest(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir, std::string_view ServerClass = ""); - std::filesystem::path CreateNewTestDir(); - std::filesystem::path ProgramBaseDir() const { return m_ProgramBaseDir; } - std::filesystem::path GetTestRootDir(std::string_view Path); - inline bool IsInitialized() const { return m_IsInitialized; } - inline bool IsTestEnvironment() const { return m_IsTestInstance; } + std::filesystem::path CreateNewTestDir(); + std::filesystem::path ProgramBaseDir() const { return m_ProgramBaseDir; } + std::filesystem::path GetTestRootDir(std::string_view Path); + inline bool IsInitialized() const { return m_IsInitialized; } + inline bool IsTestEnvironment() const { return m_IsTestInstance; } + inline std::string_view GetServerClass() const { return m_ServerClass; } private: std::filesystem::path m_ProgramBaseDir; std::filesystem::path m_TestBaseDir; bool m_IsInitialized = false; bool m_IsTestInstance = false; + std::string m_ServerClass; }; struct ZenServerInstance diff --git a/zenutil/zenserverprocess.cpp b/zenutil/zenserverprocess.cpp index 659eb665b..5ecde343b 100644 --- a/zenutil/zenserverprocess.cpp +++ b/zenutil/zenserverprocess.cpp @@ -397,8 +397,12 @@ ZenServerEnvironment::Initialize(std::filesystem::path ProgramBaseDir) } void -ZenServerEnvironment::InitializeForTest(std::filesystem::path ProgramBaseDir, std::filesystem::path TestBaseDir) +ZenServerEnvironment::InitializeForTest(std::filesystem::path ProgramBaseDir, + std::filesystem::path TestBaseDir, + std::string_view ServerClass) { + using namespace std::literals; + m_ProgramBaseDir = ProgramBaseDir; m_TestBaseDir = TestBaseDir; @@ -408,6 +412,19 @@ ZenServerEnvironment::InitializeForTest(std::filesystem::path ProgramBaseDir, st m_IsTestInstance = true; m_IsInitialized = true; + + if (ServerClass.empty()) + { +#if ZEN_WITH_HTTPSYS + m_ServerClass = "httpsys"sv; +#else + m_ServerClass = "asio"sv; +#endif + } + else + { + m_ServerClass = ServerClass; + } } std::filesystem::path @@ -516,6 +533,11 @@ ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerAr CommandLine << " --child-id " << ChildEventName; + if (std::string_view ServerClass = m_Env.GetServerClass(); ServerClass.empty() == false) + { + CommandLine << " --http " << ServerClass; + } + if (BasePort) { CommandLine << " --port " << BasePort; |