diff options
| author | Dan Engelbrecht <[email protected]> | 2024-03-14 16:33:17 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2024-03-14 16:33:17 +0100 |
| commit | 45bfc721dd049193abf3b2be2aa7b097466ddbe9 (patch) | |
| tree | abb6cf119aa148972aabad730ed384c115177cf1 /src | |
| parent | change code owners for Enterprise github user names (#7) (diff) | |
| download | zen-45bfc721dd049193abf3b2be2aa7b097466ddbe9.tar.xz zen-45bfc721dd049193abf3b2be2aa7b097466ddbe9.zip | |
clean up test linking (#4)
- Improvement: Add zenhttp-test and zenutil-test
- Improvement: Moved cachepolicy test to cachepolicy.cpp
- Improvement: Renamed cachestore tests from z$ to cachestore
- Improvement: Moved test linking so test for a lib is linked by <lib>-test
- Improvement: Removed HttpRequestParseRelativeUri in httpstructuredcache.cpp and use the one in cacherequests.h instead
Diffstat (limited to 'src')
23 files changed, 412 insertions, 632 deletions
diff --git a/src/zencore-test/zencore-test.cpp b/src/zencore-test/zencore-test.cpp index 53413fb25..64df746e4 100644 --- a/src/zencore-test/zencore-test.cpp +++ b/src/zencore-test/zencore-test.cpp @@ -3,9 +3,16 @@ // zencore-test.cpp : Defines the entry point for the console application. // +#include <zencore/filesystem.h> #include <zencore/logging.h> #include <zencore/zencore.h> +#if ZEN_USE_MIMALLOC +ZEN_THIRD_PARTY_INCLUDES_START +# include <mimalloc-new-delete.h> +ZEN_THIRD_PARTY_INCLUDES_END +#endif + #if ZEN_WITH_TESTS # define ZEN_TEST_WITH_RUNNER 1 # include <zencore/testing.h> @@ -14,10 +21,14 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { +#if ZEN_USE_MIMALLOC + mi_version(); +#endif #if ZEN_WITH_TESTS zen::zencore_forcelinktests(); zen::logging::InitializeLogging(); + zen::MaximizeOpenFileCount(); return ZEN_RUN_TESTS(argc, argv); #else diff --git a/src/zenhttp-test/xmake.lua b/src/zenhttp-test/xmake.lua new file mode 100644 index 000000000..a6163e506 --- /dev/null +++ b/src/zenhttp-test/xmake.lua @@ -0,0 +1,15 @@ +-- Copyright Epic Games, Inc. All Rights Reserved. + +target("zenhttp-test") + set_kind("binary") + set_group("tests") + add_headerfiles("**.h") + add_files("*.cpp") + add_deps("zenhttp", "zencore") + add_packages("vcpkg::doctest") + + if is_plat("macosx") then + add_ldflags("-framework CoreFoundation") + add_ldflags("-framework Security") + add_ldflags("-framework SystemConfiguration") + end diff --git a/src/zenhttp-test/zenhttp-test.cpp b/src/zenhttp-test/zenhttp-test.cpp new file mode 100644 index 000000000..440e85a9f --- /dev/null +++ b/src/zenhttp-test/zenhttp-test.cpp @@ -0,0 +1,34 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include <zencore/filesystem.h> +#include <zencore/logging.h> +#include <zenhttp/zenhttp.h> + +#if ZEN_USE_MIMALLOC +ZEN_THIRD_PARTY_INCLUDES_START +# include <mimalloc-new-delete.h> +ZEN_THIRD_PARTY_INCLUDES_END +#endif + +#if ZEN_WITH_TESTS +# define ZEN_TEST_WITH_RUNNER 1 +# include <zencore/testing.h> +#endif + +int +main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +{ +#if ZEN_USE_MIMALLOC + mi_version(); +#endif +#if ZEN_WITH_TESTS + zen::zenhttp_forcelinktests(); + + zen::logging::InitializeLogging(); + zen::MaximizeOpenFileCount(); + + return ZEN_RUN_TESTS(argc, argv); +#else + return 0; +#endif +} diff --git a/src/zennet-test/zennet-test.cpp b/src/zennet-test/zennet-test.cpp index b133f246c..f7f54e6ad 100644 --- a/src/zennet-test/zennet-test.cpp +++ b/src/zennet-test/zennet-test.cpp @@ -1,49 +1,31 @@ // Copyright Epic Games, Inc. All Rights Reserved. -#include "zennet-test.h" -#include <zencore/fmtutils.h> +#include <zencore/filesystem.h> #include <zencore/logging.h> -#include <zencore/timer.h> #include <zennet/zennet.h> -#include <zenutil/zenserverprocess.h> #if ZEN_USE_MIMALLOC ZEN_THIRD_PARTY_INCLUDES_START -# include <mimalloc.h> +# include <mimalloc-new-delete.h> ZEN_THIRD_PARTY_INCLUDES_END #endif -////////////////////////////////////////////////////////////////////////// - #if ZEN_WITH_TESTS # define ZEN_TEST_WITH_RUNNER 1 # include <zencore/testing.h> #endif -////////////////////////////////////////////////////////////////////////// - -using namespace std::literals; - -zen::ZenServerEnvironment TestEnv; - int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { #if ZEN_USE_MIMALLOC mi_version(); #endif - #if ZEN_WITH_TESTS zen::zennet_forcelinktests(); zen::logging::InitializeLogging(); - - 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); - - ZEN_INFO("Running tests...(base dir: '{}')", TestBaseDir); + zen::MaximizeOpenFileCount(); return ZEN_RUN_TESTS(argc, argv); #else diff --git a/src/zennet-test/zennet-test.h b/src/zennet-test/zennet-test.h deleted file mode 100644 index f84fd52ce..000000000 --- a/src/zennet-test/zennet-test.h +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include <zenutil/zenserverprocess.h> - -extern zen::ZenServerEnvironment TestEnv; diff --git a/src/zenserver-test/cachepolicy-tests.cpp b/src/zenserver-test/cachepolicy-tests.cpp deleted file mode 100644 index 79d78e522..000000000 --- a/src/zenserver-test/cachepolicy-tests.cpp +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include <zencore/zencore.h> - -#if ZEN_WITH_TESTS - -# include <zencore/compactbinary.h> -# include <zencore/compactbinarybuilder.h> -# include <zencore/string.h> -# include <zencore/testing.h> -# include <zencore/uid.h> -# include <zenutil/cache/cachepolicy.h> - -namespace zen::tests { - -using namespace std::literals; - -TEST_CASE("cachepolicy") -{ - SUBCASE("atomics serialization") - { - CachePolicy SomeAtomics[] = {CachePolicy::None, - CachePolicy::QueryLocal, - CachePolicy::StoreRemote, - CachePolicy::SkipData, - CachePolicy::KeepAlive}; - for (CachePolicy Atomic : SomeAtomics) - { - CHECK(ParseCachePolicy(WriteToString<128>(Atomic)) == Atomic); - } - // Also verify that we ignore unrecognized bits - for (CachePolicy Atomic : SomeAtomics) - { - CHECK(ParseCachePolicy(WriteToString<128>(Atomic | (CachePolicy)0x10000000)) == Atomic); - } - } - SUBCASE("aliases serialization") - { - CachePolicy SomeAliases[] = {CachePolicy::Query, CachePolicy::Local}; - for (CachePolicy Alias : SomeAliases) - { - CHECK(ParseCachePolicy(WriteToString<128>(Alias)) == Alias); - } - // Also verify that we ignore unrecognized bits - for (CachePolicy Alias : SomeAliases) - { - CHECK(ParseCachePolicy(WriteToString<128>(Alias | (CachePolicy)0x10000000)) == Alias); - } - } - SUBCASE("aliases take priority over atomics") - { - CHECK(WriteToString<128>(CachePolicy::Default).ToView() == "Default"sv); - CHECK(WriteToString<128>(CachePolicy::Query).ToView() == "Query"sv); - CHECK(WriteToString<128>(CachePolicy::Local).ToView() == "Local"sv); - } - SUBCASE("policies requiring multiple strings work") - { - char Delimiter = ','; - CachePolicy Combination = CachePolicy::SkipData | CachePolicy::QueryLocal; - CHECK(WriteToString<128>(Combination).ToView().find(Delimiter) != std::string_view::npos); - CHECK(ParseCachePolicy(WriteToString<128>(Combination)) == Combination); - } - SUBCASE("parsing invalid text") - { - CHECK(ParseCachePolicy(",,,") == CachePolicy::None); - CHECK(ParseCachePolicy("fee,fie,foo,fum") == CachePolicy::None); - CHECK(ParseCachePolicy("fee,KeepAlive,foo,fum") == CachePolicy::KeepAlive); - } -} - -TEST_CASE("cacherecordpolicy") -{ - SUBCASE("policy with no values") - { - CachePolicy Policy = CachePolicy::SkipData | CachePolicy::QueryLocal | CachePolicy::PartialRecord; - CachePolicy ValuePolicy = Policy & CacheValuePolicy::PolicyMask; - CacheRecordPolicy RecordPolicy; - CacheRecordPolicyBuilder Builder(Policy); - RecordPolicy = Builder.Build(); - SUBCASE("construct") - { - CHECK(RecordPolicy.IsUniform()); - CHECK(RecordPolicy.GetRecordPolicy() == Policy); - CHECK(RecordPolicy.GetBasePolicy() == Policy); - CHECK(RecordPolicy.GetValuePolicy(Oid::NewOid()) == ValuePolicy); - CHECK(RecordPolicy.GetValuePolicies().size() == 0); - } - SUBCASE("saveload") - { - CbWriter Writer; - RecordPolicy.Save(Writer); - CbObject Saved = Writer.Save()->AsObject(); - CacheRecordPolicy Loaded = CacheRecordPolicy::Load(Saved).Get(); - CHECK(Loaded.IsUniform()); - CHECK(Loaded.GetRecordPolicy() == Policy); - CHECK(Loaded.GetBasePolicy() == Policy); - CHECK(Loaded.GetValuePolicy(Oid::NewOid()) == ValuePolicy); - CHECK(Loaded.GetValuePolicies().size() == 0); - } - } - - SUBCASE("policy with values") - { - CachePolicy DefaultPolicy = CachePolicy::StoreRemote | CachePolicy::QueryLocal | CachePolicy::PartialRecord; - CachePolicy DefaultValuePolicy = DefaultPolicy & CacheValuePolicy::PolicyMask; - CachePolicy PartialOverlap = CachePolicy::StoreRemote; - CachePolicy NoOverlap = CachePolicy::QueryRemote; - CachePolicy UnionPolicy = DefaultPolicy | PartialOverlap | NoOverlap | CachePolicy::PartialRecord; - - CacheRecordPolicy RecordPolicy; - CacheRecordPolicyBuilder Builder(DefaultPolicy); - Oid PartialOid = Oid::NewOid(); - Oid NoOverlapOid = Oid::NewOid(); - Oid OtherOid = Oid::NewOid(); - Builder.AddValuePolicy(PartialOid, PartialOverlap); - Builder.AddValuePolicy(NoOverlapOid, NoOverlap); - RecordPolicy = Builder.Build(); - SUBCASE("construct") - { - CHECK(!RecordPolicy.IsUniform()); - CHECK(RecordPolicy.GetRecordPolicy() == UnionPolicy); - CHECK(RecordPolicy.GetBasePolicy() == DefaultPolicy); - CHECK(RecordPolicy.GetValuePolicy(PartialOid) == PartialOverlap); - CHECK(RecordPolicy.GetValuePolicy(NoOverlapOid) == NoOverlap); - CHECK(RecordPolicy.GetValuePolicy(OtherOid) == DefaultValuePolicy); - CHECK(RecordPolicy.GetValuePolicies().size() == 2); - } - SUBCASE("saveload") - { - CbWriter Writer; - RecordPolicy.Save(Writer); - CbObject Saved = Writer.Save()->AsObject(); - CacheRecordPolicy Loaded = CacheRecordPolicy::Load(Saved).Get(); - CHECK(!RecordPolicy.IsUniform()); - CHECK(RecordPolicy.GetRecordPolicy() == UnionPolicy); - CHECK(RecordPolicy.GetBasePolicy() == DefaultPolicy); - CHECK(RecordPolicy.GetValuePolicy(PartialOid) == PartialOverlap); - CHECK(RecordPolicy.GetValuePolicy(NoOverlapOid) == NoOverlap); - CHECK(RecordPolicy.GetValuePolicy(OtherOid) == DefaultValuePolicy); - CHECK(RecordPolicy.GetValuePolicies().size() == 2); - } - } - - SUBCASE("parsing invalid text") - { - OptionalCacheRecordPolicy Loaded = CacheRecordPolicy::Load(CbObject()); - CHECK(Loaded.IsNull()); - } -} - -} // namespace zen::tests - -#endif diff --git a/src/zenserver-test/zenserver-test.cpp b/src/zenserver-test/zenserver-test.cpp index 9074485b6..4a368c992 100644 --- a/src/zenserver-test/zenserver-test.cpp +++ b/src/zenserver-test/zenserver-test.cpp @@ -27,12 +27,6 @@ #include <zenutil/packageformat.h> #include <zenutil/zenserverprocess.h> -#if ZEN_USE_MIMALLOC -ZEN_THIRD_PARTY_INCLUDES_START -# include <mimalloc.h> -ZEN_THIRD_PARTY_INCLUDES_END -#endif - #include <http_parser.h> #if ZEN_PLATFORM_WINDOWS @@ -59,6 +53,12 @@ ZEN_THIRD_PARTY_INCLUDES_END # include <process.h> #endif +#if ZEN_USE_MIMALLOC +ZEN_THIRD_PARTY_INCLUDES_START +# include <mimalloc-new-delete.h> +ZEN_THIRD_PARTY_INCLUDES_END +#endif + ////////////////////////////////////////////////////////////////////////// #include "projectclient.h" @@ -100,16 +100,11 @@ zen::ZenServerEnvironment TestEnv; int main(int argc, char** argv) { - using namespace std::literals; - using namespace zen; - # if ZEN_USE_MIMALLOC mi_version(); # endif - - zencore_forcelinktests(); - zenhttp_forcelinktests(); - cacherequests_forcelink(); + using namespace std::literals; + using namespace zen; zen::logging::InitializeLogging(); diff --git a/src/zenserver/cache/httpstructuredcache.cpp b/src/zenserver/cache/httpstructuredcache.cpp index 4cf7c9a01..f64b9c5a5 100644 --- a/src/zenserver/cache/httpstructuredcache.cpp +++ b/src/zenserver/cache/httpstructuredcache.cpp @@ -39,11 +39,6 @@ #include <cpr/cpr.h> #include <gsl/gsl-lite.hpp> -#if ZEN_WITH_TESTS -# include <zencore/testing.h> -# include <zencore/testutils.h> -#endif - namespace zen { using namespace std::literals; @@ -64,64 +59,6 @@ namespace { static constinit std::string_view HttpZCacheUtilReplayRecording = "exec$/replay-recording"sv; static constinit std::string_view HttpZCacheDetailsPrefix = "details$"sv; - constinit AsciiSet ValidNamespaceNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789-_.ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; - constinit AsciiSet ValidBucketNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; - - std::optional<std::string> GetValidNamespaceName(std::string_view Name) - { - if (Name.empty()) - { - ZEN_WARN("Namespace is invalid, empty namespace is not allowed"); - return {}; - } - - if (Name.length() > 64) - { - ZEN_WARN("Namespace '{}' is invalid, length exceeds 64 characters", Name); - return {}; - } - - if (!AsciiSet::HasOnly(Name, ValidNamespaceNameCharactersSet)) - { - ZEN_WARN("Namespace '{}' is invalid, invalid characters detected", Name); - return {}; - } - - return ToLower(Name); - } - - std::optional<std::string> GetValidBucketName(std::string_view Name) - { - if (Name.empty()) - { - ZEN_WARN("Bucket name is invalid, empty bucket name is not allowed"); - return {}; - } - - if (!AsciiSet::HasOnly(Name, ValidBucketNameCharactersSet)) - { - ZEN_WARN("Bucket name '{}' is invalid, invalid characters detected", Name); - return {}; - } - - return ToLower(Name); - } - - std::optional<IoHash> GetValidIoHash(std::string_view Hash) - { - if (Hash.length() != IoHash::StringLength) - { - return {}; - } - - IoHash KeyHash; - if (!ParseHexBytes(Hash.data(), Hash.size(), KeyHash.Hash)) - { - return {}; - } - return KeyHash; - } - struct HttpRequestData { std::optional<std::string> Namespace; @@ -130,117 +67,6 @@ namespace { std::optional<IoHash> ValueContentId; }; - bool HttpRequestParseRelativeUri(std::string_view Key, HttpRequestData& Data) - { - std::vector<std::string_view> Tokens; - uint32_t TokenCount = ForEachStrTok(Key, '/', [&](const std::string_view& Token) { - Tokens.push_back(Token); - return true; - }); - - switch (TokenCount) - { - case 0: - return true; - case 1: - Data.Namespace = GetValidNamespaceName(Tokens[0]); - return Data.Namespace.has_value(); - case 2: - { - std::optional<IoHash> PossibleHashKey = GetValidIoHash(Tokens[1]); - if (PossibleHashKey.has_value()) - { - // Legacy bucket/key request - Data.Bucket = GetValidBucketName(Tokens[0]); - if (!Data.Bucket.has_value()) - { - return false; - } - Data.HashKey = PossibleHashKey; - Data.Namespace = ZenCacheStore::DefaultNamespace; - return true; - } - Data.Namespace = GetValidNamespaceName(Tokens[0]); - if (!Data.Namespace.has_value()) - { - return false; - } - Data.Bucket = GetValidBucketName(Tokens[1]); - if (!Data.Bucket.has_value()) - { - return false; - } - return true; - } - case 3: - { - std::optional<IoHash> PossibleHashKey = GetValidIoHash(Tokens[1]); - if (PossibleHashKey.has_value()) - { - // Legacy bucket/key/valueid request - Data.Bucket = GetValidBucketName(Tokens[0]); - if (!Data.Bucket.has_value()) - { - return false; - } - Data.HashKey = PossibleHashKey; - Data.ValueContentId = GetValidIoHash(Tokens[2]); - if (!Data.ValueContentId.has_value()) - { - return false; - } - Data.Namespace = ZenCacheStore::DefaultNamespace; - return true; - } - Data.Namespace = GetValidNamespaceName(Tokens[0]); - if (!Data.Namespace.has_value()) - { - return false; - } - Data.Bucket = GetValidBucketName(Tokens[1]); - if (!Data.Bucket.has_value()) - { - return false; - } - Data.HashKey = GetValidIoHash(Tokens[2]); - if (!Data.HashKey) - { - return false; - } - return true; - } - case 4: - { - Data.Namespace = GetValidNamespaceName(Tokens[0]); - if (!Data.Namespace.has_value()) - { - return false; - } - - Data.Bucket = GetValidBucketName(Tokens[1]); - if (!Data.Bucket.has_value()) - { - return false; - } - - Data.HashKey = GetValidIoHash(Tokens[2]); - if (!Data.HashKey.has_value()) - { - return false; - } - - Data.ValueContentId = GetValidIoHash(Tokens[3]); - if (!Data.ValueContentId.has_value()) - { - return false; - } - return true; - } - default: - return false; - } - } - } // namespace ////////////////////////////////////////////////////////////////////////// @@ -614,8 +440,8 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request) return; } - HttpRequestData RequestData; - if (!HttpRequestParseRelativeUri(Key, RequestData)) + cacherequests::HttpRequestData RequestData; + if (!cacherequests::HttpRequestParseRelativeUri(Key, ZenCacheStore::DefaultNamespace, RequestData)) { m_CacheStats.BadRequestCount++; return Request.WriteResponse(HttpResponseCode::BadRequest); // invalid URL @@ -1968,106 +1794,4 @@ HttpStructuredCacheService::AreDiskWritesAllowed() const return (m_DiskWriteBlocker == nullptr || m_DiskWriteBlocker->AreDiskWritesAllowed()); } -#if ZEN_WITH_TESTS - -TEST_CASE("z$service.parse.relative.Uri") -{ - HttpRequestData RootRequest; - CHECK(HttpRequestParseRelativeUri("", RootRequest)); - CHECK(!RootRequest.Namespace.has_value()); - CHECK(!RootRequest.Bucket.has_value()); - CHECK(!RootRequest.HashKey.has_value()); - CHECK(!RootRequest.ValueContentId.has_value()); - - RootRequest = {}; - CHECK(HttpRequestParseRelativeUri("/", RootRequest)); - CHECK(!RootRequest.Namespace.has_value()); - CHECK(!RootRequest.Bucket.has_value()); - CHECK(!RootRequest.HashKey.has_value()); - CHECK(!RootRequest.ValueContentId.has_value()); - - HttpRequestData LegacyBucketRequestBecomesNamespaceRequest; - CHECK(HttpRequestParseRelativeUri("test", LegacyBucketRequestBecomesNamespaceRequest)); - CHECK(LegacyBucketRequestBecomesNamespaceRequest.Namespace == "test"sv); - CHECK(!LegacyBucketRequestBecomesNamespaceRequest.Bucket.has_value()); - CHECK(!LegacyBucketRequestBecomesNamespaceRequest.HashKey.has_value()); - CHECK(!LegacyBucketRequestBecomesNamespaceRequest.ValueContentId.has_value()); - - HttpRequestData LegacyHashKeyRequest; - CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", LegacyHashKeyRequest)); - CHECK(LegacyHashKeyRequest.Namespace == ZenCacheStore::DefaultNamespace); - CHECK(LegacyHashKeyRequest.Bucket == "test"sv); - CHECK(LegacyHashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); - CHECK(!LegacyHashKeyRequest.ValueContentId.has_value()); - - HttpRequestData LegacyValueContentIdRequest; - CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789", - LegacyValueContentIdRequest)); - CHECK(LegacyValueContentIdRequest.Namespace == ZenCacheStore::DefaultNamespace); - CHECK(LegacyValueContentIdRequest.Bucket == "test"sv); - CHECK(LegacyValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); - CHECK(LegacyValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv)); - - HttpRequestData V2DefaultNamespaceRequest; - CHECK(HttpRequestParseRelativeUri("ue4.ddc", V2DefaultNamespaceRequest)); - CHECK(V2DefaultNamespaceRequest.Namespace == "ue4.ddc"); - CHECK(!V2DefaultNamespaceRequest.Bucket.has_value()); - CHECK(!V2DefaultNamespaceRequest.HashKey.has_value()); - CHECK(!V2DefaultNamespaceRequest.ValueContentId.has_value()); - - HttpRequestData V2NamespaceRequest; - CHECK(HttpRequestParseRelativeUri("nicenamespace", V2NamespaceRequest)); - CHECK(V2NamespaceRequest.Namespace == "nicenamespace"sv); - CHECK(!V2NamespaceRequest.Bucket.has_value()); - CHECK(!V2NamespaceRequest.HashKey.has_value()); - CHECK(!V2NamespaceRequest.ValueContentId.has_value()); - - HttpRequestData V2BucketRequestWithDefaultNamespace; - CHECK(HttpRequestParseRelativeUri("ue4.ddc/test", V2BucketRequestWithDefaultNamespace)); - CHECK(V2BucketRequestWithDefaultNamespace.Namespace == "ue4.ddc"); - CHECK(V2BucketRequestWithDefaultNamespace.Bucket == "test"sv); - CHECK(!V2BucketRequestWithDefaultNamespace.HashKey.has_value()); - CHECK(!V2BucketRequestWithDefaultNamespace.ValueContentId.has_value()); - - HttpRequestData V2BucketRequestWithNamespace; - CHECK(HttpRequestParseRelativeUri("nicenamespace/test", V2BucketRequestWithNamespace)); - CHECK(V2BucketRequestWithNamespace.Namespace == "nicenamespace"sv); - CHECK(V2BucketRequestWithNamespace.Bucket == "test"sv); - CHECK(!V2BucketRequestWithNamespace.HashKey.has_value()); - CHECK(!V2BucketRequestWithNamespace.ValueContentId.has_value()); - - HttpRequestData V2HashKeyRequest; - CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", V2HashKeyRequest)); - CHECK(V2HashKeyRequest.Namespace == ZenCacheStore::DefaultNamespace); - CHECK(V2HashKeyRequest.Bucket == "test"); - CHECK(V2HashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); - CHECK(!V2HashKeyRequest.ValueContentId.has_value()); - - HttpRequestData V2ValueContentIdRequest; - CHECK( - HttpRequestParseRelativeUri("nicenamespace/test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789", - V2ValueContentIdRequest)); - CHECK(V2ValueContentIdRequest.Namespace == "nicenamespace"sv); - CHECK(V2ValueContentIdRequest.Bucket == "test"sv); - CHECK(V2ValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); - CHECK(V2ValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv)); - - HttpRequestData Invalid; - CHECK(!HttpRequestParseRelativeUri("bad\2_namespace", Invalid)); - CHECK(!HttpRequestParseRelativeUri("nice/\2\1bucket", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789a", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcdef1234", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/pppppppp89abcdef12340123456789abcdef1234", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcd", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/ppppppppdef12345678956789abcdef123456789", - Invalid)); -} - -#endif - -void -z$service_forcelink() -{ -} - } // namespace zen diff --git a/src/zenserver/cache/httpstructuredcache.h b/src/zenserver/cache/httpstructuredcache.h index da4bdd63c..7dc8c4c21 100644 --- a/src/zenserver/cache/httpstructuredcache.h +++ b/src/zenserver/cache/httpstructuredcache.h @@ -136,6 +136,4 @@ private: std::unique_ptr<cache::IRpcRequestRecorder> m_RequestRecorder; }; -void z$service_forcelink(); - } // namespace zen diff --git a/src/zenserver/main.cpp b/src/zenserver/main.cpp index 8faefca88..4a5b98e8e 100644 --- a/src/zenserver/main.cpp +++ b/src/zenserver/main.cpp @@ -23,7 +23,6 @@ #if ZEN_USE_MIMALLOC ZEN_THIRD_PARTY_INCLUDES_START # include <mimalloc-new-delete.h> -# include <mimalloc.h> ZEN_THIRD_PARTY_INCLUDES_END #endif @@ -293,11 +292,7 @@ ZenWindowsService::Run() int test_main(int argc, char** argv) { - zen::zencore_forcelinktests(); - zen::zenhttp_forcelinktests(); - zen::zenstore_forcelinktests(); - zen::zenutil_forcelinktests(); - zen::z$service_forcelink(); + zen::zenserver_forcelinktests(); zen::logging::InitializeLogging(); zen::logging::SetLogLevel(zen::logging::level::Debug); @@ -311,11 +306,10 @@ test_main(int argc, char** argv) int main(int argc, char* argv[]) { - using namespace zen; - #if ZEN_USE_MIMALLOC mi_version(); #endif + using namespace zen; if (argc >= 2) { diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index 3f3762dbf..6b0760343 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -944,4 +944,14 @@ ZenServer::ToString(ServerState Value) } } +#if ZEN_WITH_TESTS + +void +zenserver_forcelinktests() +{ + zen::prj_forcelink(); +} + +#endif + } // namespace zen diff --git a/src/zenserver/zenserver.h b/src/zenserver/zenserver.h index 6ff13cfff..cdd7c17a7 100644 --- a/src/zenserver/zenserver.h +++ b/src/zenserver/zenserver.h @@ -143,4 +143,6 @@ private: std::string m_StartupScrubOptions; }; +void zenserver_forcelinktests(); + } // namespace zen diff --git a/src/zenstore-test/zenstore-test.cpp b/src/zenstore-test/zenstore-test.cpp index c301c04a3..3ad9e620b 100644 --- a/src/zenstore-test/zenstore-test.cpp +++ b/src/zenstore-test/zenstore-test.cpp @@ -2,15 +2,12 @@ #include <zencore/filesystem.h> #include <zencore/logging.h> -#include <zencore/zencore.h> -#include <zenstore/cache/structuredcachestore.h> #include <zenstore/zenstore.h> -#include <zenutil/zenutil.h> -#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC -# include <sys/time.h> -# include <sys/resource.h> -# include <zencore/except.h> +#if ZEN_USE_MIMALLOC +ZEN_THIRD_PARTY_INCLUDES_START +# include <mimalloc-new-delete.h> +ZEN_THIRD_PARTY_INCLUDES_END #endif #if ZEN_WITH_TESTS @@ -21,10 +18,11 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { +#if ZEN_USE_MIMALLOC + mi_version(); +#endif #if ZEN_WITH_TESTS zen::zenstore_forcelinktests(); - zen::zenutil_forcelinktests(); - zen::structured_cachestore_forcelink(); zen::logging::InitializeLogging(); zen::MaximizeOpenFileCount(); diff --git a/src/zenstore/cache/cacherpc.cpp b/src/zenstore/cache/cacherpc.cpp index 5acb2b8c9..e6ba6629d 100644 --- a/src/zenstore/cache/cacherpc.cpp +++ b/src/zenstore/cache/cacherpc.cpp @@ -14,55 +14,9 @@ #include <zenstore/cache/structuredcachestore.h> #include <zenstore/cache/upstreamcacheclient.h> #include <zenstore/cidstore.h> +#include <zenutil/cache/cacherequests.h> #include <zenutil/packageformat.h> -namespace zen { namespace { - - constinit AsciiSet ValidNamespaceNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789-_.ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; - constinit AsciiSet ValidBucketNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; - - std::optional<std::string> GetValidNamespaceName(std::string_view Name) - { - if (Name.empty()) - { - ZEN_WARN("Namespace is invalid, empty namespace is not allowed"); - return {}; - } - - if (Name.length() > 64) - { - ZEN_WARN("Namespace '{}' is invalid, length exceeds 64 characters", Name); - return {}; - } - - if (!AsciiSet::HasOnly(Name, ValidNamespaceNameCharactersSet)) - { - ZEN_WARN("Namespace '{}' is invalid, invalid characters detected", Name); - return {}; - } - - return ToLower(Name); - } - - std::optional<std::string> GetValidBucketName(std::string_view Name) - { - if (Name.empty()) - { - ZEN_WARN("Bucket name is invalid, empty bucket name is not allowed"); - return {}; - } - - if (!AsciiSet::HasOnly(Name, ValidBucketNameCharactersSet)) - { - ZEN_WARN("Bucket name '{}' is invalid, invalid characters detected", Name); - return {}; - } - - return ToLower(Name); - } - -}} // namespace zen:: - ////////////////////////////////////////////////////////////////////////// namespace zen { @@ -86,7 +40,7 @@ GetRpcRequestNamespace(const CbObjectView Params) { return {}; } - return GetValidNamespaceName(NamespaceField.AsString()); + return cacherequests::GetValidNamespaceName(NamespaceField.AsString()); } bool @@ -101,7 +55,7 @@ GetRpcRequestCacheKey(const CbObjectView& KeyView, CacheKey& Key) { return false; } - std::optional<std::string> Bucket = GetValidBucketName(BucketField.AsString()); + std::optional<std::string> Bucket = cacherequests::GetValidBucketName(BucketField.AsString()); if (!Bucket.has_value()) { return false; diff --git a/src/zenstore/cache/structuredcachestore.cpp b/src/zenstore/cache/structuredcachestore.cpp index 7ef290cf5..daa628f77 100644 --- a/src/zenstore/cache/structuredcachestore.cpp +++ b/src/zenstore/cache/structuredcachestore.cpp @@ -873,7 +873,7 @@ namespace testutils { } // namespace testutils -TEST_CASE("z$.store") +TEST_CASE("cachestore.store") { ScopedTemporaryDirectory TempDir; @@ -914,7 +914,7 @@ TEST_CASE("z$.store") } } -TEST_CASE("z$.size") +TEST_CASE("cachestore.size") { auto JobQueue = MakeJobQueue(1, "testqueue"); @@ -1029,7 +1029,7 @@ TEST_CASE("z$.size") } } -TEST_CASE("z$.gc") +TEST_CASE("cachestore.gc") { using namespace testutils; @@ -1208,7 +1208,7 @@ TEST_CASE("z$.gc") } } -TEST_CASE_TEMPLATE("z$.threadedinsert", GCV2, FalseType, TrueType) // * doctest::skip(true)) +TEST_CASE_TEMPLATE("cachestore.threadedinsert", GCV2, FalseType, TrueType) // * doctest::skip(true)) { // for (uint32_t i = 0; i < 100; ++i) { @@ -1482,7 +1482,7 @@ TEST_CASE_TEMPLATE("z$.threadedinsert", GCV2, FalseType, TrueType) // * doctest: } } -TEST_CASE("z$.namespaces") +TEST_CASE("cachestore.namespaces") { using namespace testutils; @@ -1550,7 +1550,7 @@ TEST_CASE("z$.namespaces") } } -TEST_CASE("z$.drop.bucket") +TEST_CASE("cachestore.drop.bucket") { using namespace testutils; @@ -1625,7 +1625,7 @@ TEST_CASE("z$.drop.bucket") } } -TEST_CASE("z$.drop.namespace") +TEST_CASE("cachestore.drop.namespace") { using namespace testutils; @@ -1715,7 +1715,7 @@ TEST_CASE("z$.drop.namespace") } } -TEST_CASE("z$.blocked.disklayer.put") +TEST_CASE("cachestore.blocked.disklayer.put") { ScopedTemporaryDirectory TempDir; @@ -1768,7 +1768,7 @@ TEST_CASE("z$.blocked.disklayer.put") CHECK(memcmp(NewView.GetData(), Buffer2.GetData(), NewView.GetSize()) == 0); } -TEST_CASE("z$.scrub") +TEST_CASE("cachestore.scrub") { ScopedTemporaryDirectory TempDir; @@ -1862,7 +1862,7 @@ TEST_CASE("z$.scrub") CHECK(ScrubCtx.BadCids().GetSize() == 0); } -TEST_CASE("z$.newgc.basics") +TEST_CASE("cachestore.newgc.basics") { using namespace testutils; diff --git a/src/zenstore/zenstore.cpp b/src/zenstore/zenstore.cpp index 60dabe31f..038c6bdc7 100644 --- a/src/zenstore/zenstore.cpp +++ b/src/zenstore/zenstore.cpp @@ -5,6 +5,7 @@ #if ZEN_WITH_TESTS # include <zenstore/blockstore.h> +# include <zenstore/cache/structuredcachestore.h> # include <zenstore/gc.h> # include <zenstore/hashkeyset.h> @@ -23,6 +24,7 @@ zenstore_forcelinktests() compactcas_forcelink(); gc_forcelink(); hashkeyset_forcelink(); + structured_cachestore_forcelink(); } } // namespace zen diff --git a/src/zenutil-test/xmake.lua b/src/zenutil-test/xmake.lua new file mode 100644 index 000000000..61a828f1c --- /dev/null +++ b/src/zenutil-test/xmake.lua @@ -0,0 +1,9 @@ +-- Copyright Epic Games, Inc. All Rights Reserved. + +target("zenutil-test") + set_kind("binary") + set_group("tests") + add_headerfiles("**.h") + add_files("*.cpp") + add_deps("zenutil", "zencore") + add_packages("vcpkg::doctest") diff --git a/src/zenutil-test/zenutil-test.cpp b/src/zenutil-test/zenutil-test.cpp new file mode 100644 index 000000000..f95b7e888 --- /dev/null +++ b/src/zenutil-test/zenutil-test.cpp @@ -0,0 +1,34 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include <zencore/filesystem.h> +#include <zencore/logging.h> +#include <zenutil/zenutil.h> + +#if ZEN_USE_MIMALLOC +ZEN_THIRD_PARTY_INCLUDES_START +# include <mimalloc-new-delete.h> +ZEN_THIRD_PARTY_INCLUDES_END +#endif + +#if ZEN_WITH_TESTS +# define ZEN_TEST_WITH_RUNNER 1 +# include <zencore/testing.h> +#endif + +int +main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) +{ +#if ZEN_USE_MIMALLOC + mi_version(); +#endif +#if ZEN_WITH_TESTS + zen::zenutil_forcelinktests(); + + zen::logging::InitializeLogging(); + zen::MaximizeOpenFileCount(); + + return ZEN_RUN_TESTS(argc, argv); +#else + return 0; +#endif +} diff --git a/src/zenutil/cache/cachepolicy.cpp b/src/zenutil/cache/cachepolicy.cpp index 3bca363bb..0bdfd87ce 100644 --- a/src/zenutil/cache/cachepolicy.cpp +++ b/src/zenutil/cache/cachepolicy.cpp @@ -10,6 +10,10 @@ #include <algorithm> #include <unordered_map> +#if ZEN_WITH_TESTS +# include <zencore/testing.h> +#endif + namespace zen::Private { class CacheRecordPolicyShared; } @@ -279,4 +283,144 @@ CacheRecordPolicyBuilder::Build() return Policy; } +#if ZEN_WITH_TESTS +TEST_CASE("cachepolicy") +{ + SUBCASE("atomics serialization") + { + CachePolicy SomeAtomics[] = {CachePolicy::None, + CachePolicy::QueryLocal, + CachePolicy::StoreRemote, + CachePolicy::SkipData, + CachePolicy::KeepAlive}; + for (CachePolicy Atomic : SomeAtomics) + { + CHECK(ParseCachePolicy(WriteToString<128>(Atomic)) == Atomic); + } + // Also verify that we ignore unrecognized bits + for (CachePolicy Atomic : SomeAtomics) + { + CHECK(ParseCachePolicy(WriteToString<128>(Atomic | (CachePolicy)0x10000000)) == Atomic); + } + } + SUBCASE("aliases serialization") + { + CachePolicy SomeAliases[] = {CachePolicy::Query, CachePolicy::Local}; + for (CachePolicy Alias : SomeAliases) + { + CHECK(ParseCachePolicy(WriteToString<128>(Alias)) == Alias); + } + // Also verify that we ignore unrecognized bits + for (CachePolicy Alias : SomeAliases) + { + CHECK(ParseCachePolicy(WriteToString<128>(Alias | (CachePolicy)0x10000000)) == Alias); + } + } + SUBCASE("aliases take priority over atomics") + { + CHECK(WriteToString<128>(CachePolicy::Default).ToView() == "Default"sv); + CHECK(WriteToString<128>(CachePolicy::Query).ToView() == "Query"sv); + CHECK(WriteToString<128>(CachePolicy::Local).ToView() == "Local"sv); + } + SUBCASE("policies requiring multiple strings work") + { + char Delimiter = ','; + CachePolicy Combination = CachePolicy::SkipData | CachePolicy::QueryLocal; + CHECK(WriteToString<128>(Combination).ToView().find(Delimiter) != std::string_view::npos); + CHECK(ParseCachePolicy(WriteToString<128>(Combination)) == Combination); + } + SUBCASE("parsing invalid text") + { + CHECK(ParseCachePolicy(",,,") == CachePolicy::None); + CHECK(ParseCachePolicy("fee,fie,foo,fum") == CachePolicy::None); + CHECK(ParseCachePolicy("fee,KeepAlive,foo,fum") == CachePolicy::KeepAlive); + } +} + +TEST_CASE("cacherecordpolicy") +{ + SUBCASE("policy with no values") + { + CachePolicy Policy = CachePolicy::SkipData | CachePolicy::QueryLocal | CachePolicy::PartialRecord; + CachePolicy ValuePolicy = Policy & CacheValuePolicy::PolicyMask; + CacheRecordPolicy RecordPolicy; + CacheRecordPolicyBuilder Builder(Policy); + RecordPolicy = Builder.Build(); + SUBCASE("construct") + { + CHECK(RecordPolicy.IsUniform()); + CHECK(RecordPolicy.GetRecordPolicy() == Policy); + CHECK(RecordPolicy.GetBasePolicy() == Policy); + CHECK(RecordPolicy.GetValuePolicy(Oid::NewOid()) == ValuePolicy); + CHECK(RecordPolicy.GetValuePolicies().size() == 0); + } + SUBCASE("saveload") + { + CbWriter Writer; + RecordPolicy.Save(Writer); + CbObject Saved = Writer.Save()->AsObject(); + CacheRecordPolicy Loaded = CacheRecordPolicy::Load(Saved).Get(); + CHECK(Loaded.IsUniform()); + CHECK(Loaded.GetRecordPolicy() == Policy); + CHECK(Loaded.GetBasePolicy() == Policy); + CHECK(Loaded.GetValuePolicy(Oid::NewOid()) == ValuePolicy); + CHECK(Loaded.GetValuePolicies().size() == 0); + } + } + + SUBCASE("policy with values") + { + CachePolicy DefaultPolicy = CachePolicy::StoreRemote | CachePolicy::QueryLocal | CachePolicy::PartialRecord; + CachePolicy DefaultValuePolicy = DefaultPolicy & CacheValuePolicy::PolicyMask; + CachePolicy PartialOverlap = CachePolicy::StoreRemote; + CachePolicy NoOverlap = CachePolicy::QueryRemote; + CachePolicy UnionPolicy = DefaultPolicy | PartialOverlap | NoOverlap | CachePolicy::PartialRecord; + + CacheRecordPolicy RecordPolicy; + CacheRecordPolicyBuilder Builder(DefaultPolicy); + Oid PartialOid = Oid::NewOid(); + Oid NoOverlapOid = Oid::NewOid(); + Oid OtherOid = Oid::NewOid(); + Builder.AddValuePolicy(PartialOid, PartialOverlap); + Builder.AddValuePolicy(NoOverlapOid, NoOverlap); + RecordPolicy = Builder.Build(); + SUBCASE("construct") + { + CHECK(!RecordPolicy.IsUniform()); + CHECK(RecordPolicy.GetRecordPolicy() == UnionPolicy); + CHECK(RecordPolicy.GetBasePolicy() == DefaultPolicy); + CHECK(RecordPolicy.GetValuePolicy(PartialOid) == PartialOverlap); + CHECK(RecordPolicy.GetValuePolicy(NoOverlapOid) == NoOverlap); + CHECK(RecordPolicy.GetValuePolicy(OtherOid) == DefaultValuePolicy); + CHECK(RecordPolicy.GetValuePolicies().size() == 2); + } + SUBCASE("saveload") + { + CbWriter Writer; + RecordPolicy.Save(Writer); + CbObject Saved = Writer.Save()->AsObject(); + CacheRecordPolicy Loaded = CacheRecordPolicy::Load(Saved).Get(); + CHECK(!RecordPolicy.IsUniform()); + CHECK(RecordPolicy.GetRecordPolicy() == UnionPolicy); + CHECK(RecordPolicy.GetBasePolicy() == DefaultPolicy); + CHECK(RecordPolicy.GetValuePolicy(PartialOid) == PartialOverlap); + CHECK(RecordPolicy.GetValuePolicy(NoOverlapOid) == NoOverlap); + CHECK(RecordPolicy.GetValuePolicy(OtherOid) == DefaultValuePolicy); + CHECK(RecordPolicy.GetValuePolicies().size() == 2); + } + } + + SUBCASE("parsing invalid text") + { + OptionalCacheRecordPolicy Loaded = CacheRecordPolicy::Load(CbObject()); + CHECK(Loaded.IsNull()); + } +} +#endif + +void +cachepolicy_forcelink() +{ +} + } // namespace zen diff --git a/src/zenutil/cache/cacherequests.cpp b/src/zenutil/cache/cacherequests.cpp index 51fb61c27..f4de6bacd 100644 --- a/src/zenutil/cache/cacherequests.cpp +++ b/src/zenutil/cache/cacherequests.cpp @@ -24,67 +24,67 @@ namespace cacherequests { namespace { constinit AsciiSet ValidNamespaceNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789-_.ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; constinit AsciiSet ValidBucketNameCharactersSet{"abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; + } // namespace - std::optional<std::string> GetValidNamespaceName(std::string_view Name) + std::optional<std::string> GetValidNamespaceName(std::string_view Name) + { + if (Name.empty()) { - if (Name.empty()) - { - ZEN_WARN("Namespace is invalid, empty namespace is not allowed"); - return {}; - } - - if (Name.length() > 64) - { - ZEN_WARN("Namespace '{}' is invalid, length exceeds 64 characters", Name); - return {}; - } - - if (!AsciiSet::HasOnly(Name, ValidNamespaceNameCharactersSet)) - { - ZEN_WARN("Namespace '{}' is invalid, invalid characters detected", Name); - return {}; - } + ZEN_WARN("Namespace is invalid, empty namespace is not allowed"); + return {}; + } - return ToLower(Name); + if (Name.length() > 64) + { + ZEN_WARN("Namespace '{}' is invalid, length exceeds 64 characters", Name); + return {}; } - std::optional<std::string> GetValidBucketName(std::string_view Name) + if (!AsciiSet::HasOnly(Name, ValidNamespaceNameCharactersSet)) { - if (Name.empty()) - { - ZEN_WARN("Bucket name is invalid, empty bucket name is not allowed"); - return {}; - } + ZEN_WARN("Namespace '{}' is invalid, invalid characters detected", Name); + return {}; + } - if (!AsciiSet::HasOnly(Name, ValidBucketNameCharactersSet)) - { - ZEN_WARN("Bucket name '{}' is invalid, invalid characters detected", Name); - return {}; - } + return ToLower(Name); + } - return ToLower(Name); + std::optional<std::string> GetValidBucketName(std::string_view Name) + { + if (Name.empty()) + { + ZEN_WARN("Bucket name is invalid, empty bucket name is not allowed"); + return {}; } - std::optional<IoHash> GetValidIoHash(std::string_view Hash) + if (!AsciiSet::HasOnly(Name, ValidBucketNameCharactersSet)) { - if (Hash.length() != IoHash::StringLength) - { - return {}; - } + ZEN_WARN("Bucket name '{}' is invalid, invalid characters detected", Name); + return {}; + } - IoHash KeyHash; - if (!ParseHexBytes(Hash.data(), Hash.size(), KeyHash.Hash)) - { - return {}; - } - return KeyHash; + return ToLower(Name); + } + + std::optional<IoHash> GetValidIoHash(std::string_view Hash) + { + if (Hash.length() != IoHash::StringLength) + { + return {}; } - std::optional<CacheRecordPolicy> Convert(const OptionalCacheRecordPolicy& Policy) + IoHash KeyHash; + if (!ParseHexBytes(Hash.data(), Hash.size(), KeyHash.Hash)) { - return Policy.IsValid() ? Policy.Get() : std::optional<CacheRecordPolicy>{}; - }; - } // namespace + return {}; + } + return KeyHash; + } + + std::optional<CacheRecordPolicy> Convert(const OptionalCacheRecordPolicy& Policy) + { + return Policy.IsValid() ? Policy.Get() : std::optional<CacheRecordPolicy>{}; + }; std::optional<std::string> GetRequestNamespace(const CbObjectView& Params) { @@ -923,16 +923,18 @@ namespace cacherequests { return true; } - bool HttpRequestParseRelativeUri(std::string_view Key, HttpRequestData& Data) + bool HttpRequestParseRelativeUri(std::string_view Key, std::string_view DefaultNamespace, HttpRequestData& Data) { std::vector<std::string_view> Tokens; - uint32_t TokenCount = zen::ForEachStrTok(Key, '/', [&](const std::string_view& Token) { + uint32_t TokenCount = ForEachStrTok(Key, '/', [&](const std::string_view& Token) { Tokens.push_back(Token); return true; }); switch (TokenCount) { + case 0: + return true; case 1: Data.Namespace = GetValidNamespaceName(Tokens[0]); return Data.Namespace.has_value(); @@ -947,7 +949,8 @@ namespace cacherequests { { return false; } - Data.HashKey = PossibleHashKey; + Data.HashKey = PossibleHashKey; + Data.Namespace = DefaultNamespace; return true; } Data.Namespace = GetValidNamespaceName(Tokens[0]); @@ -979,6 +982,7 @@ namespace cacherequests { { return false; } + Data.Namespace = DefaultNamespace; return true; } Data.Namespace = GetValidNamespaceName(Tokens[0]); @@ -1552,85 +1556,104 @@ namespace cacherequests { CHECK(FullResult == FullResultCopy); } - TEST_CASE("z$service.parse.relative.Uri") + TEST_CASE("cachrequests.parse.relative.Uri") { + using namespace std::literals; + + HttpRequestData RootRequest; + CHECK(HttpRequestParseRelativeUri("", "!default!", RootRequest)); + CHECK(!RootRequest.Namespace.has_value()); + CHECK(!RootRequest.Bucket.has_value()); + CHECK(!RootRequest.HashKey.has_value()); + CHECK(!RootRequest.ValueContentId.has_value()); + + RootRequest = {}; + CHECK(HttpRequestParseRelativeUri("/", "!default!", RootRequest)); + CHECK(!RootRequest.Namespace.has_value()); + CHECK(!RootRequest.Bucket.has_value()); + CHECK(!RootRequest.HashKey.has_value()); + CHECK(!RootRequest.ValueContentId.has_value()); + HttpRequestData LegacyBucketRequestBecomesNamespaceRequest; - CHECK(HttpRequestParseRelativeUri("test", LegacyBucketRequestBecomesNamespaceRequest)); - CHECK(LegacyBucketRequestBecomesNamespaceRequest.Namespace == "test"); + CHECK(HttpRequestParseRelativeUri("test", "!default!", LegacyBucketRequestBecomesNamespaceRequest)); + CHECK(LegacyBucketRequestBecomesNamespaceRequest.Namespace == "test"sv); CHECK(!LegacyBucketRequestBecomesNamespaceRequest.Bucket.has_value()); CHECK(!LegacyBucketRequestBecomesNamespaceRequest.HashKey.has_value()); CHECK(!LegacyBucketRequestBecomesNamespaceRequest.ValueContentId.has_value()); HttpRequestData LegacyHashKeyRequest; - CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", LegacyHashKeyRequest)); - CHECK(!LegacyHashKeyRequest.Namespace); - CHECK(LegacyHashKeyRequest.Bucket == "test"); - CHECK(LegacyHashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234")); + CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", "!default!", LegacyHashKeyRequest)); + CHECK(LegacyHashKeyRequest.Namespace == "!default!"); + CHECK(LegacyHashKeyRequest.Bucket == "test"sv); + CHECK(LegacyHashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); CHECK(!LegacyHashKeyRequest.ValueContentId.has_value()); HttpRequestData LegacyValueContentIdRequest; CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789", + "!default!", LegacyValueContentIdRequest)); - CHECK(!LegacyValueContentIdRequest.Namespace); - CHECK(LegacyValueContentIdRequest.Bucket == "test"); - CHECK(LegacyValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234")); - CHECK(LegacyValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789")); + CHECK(LegacyValueContentIdRequest.Namespace == "!default!"); + CHECK(LegacyValueContentIdRequest.Bucket == "test"sv); + CHECK(LegacyValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); + CHECK(LegacyValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv)); HttpRequestData V2DefaultNamespaceRequest; - CHECK(HttpRequestParseRelativeUri("ue4.ddc", V2DefaultNamespaceRequest)); + CHECK(HttpRequestParseRelativeUri("ue4.ddc", "!default!", V2DefaultNamespaceRequest)); CHECK(V2DefaultNamespaceRequest.Namespace == "ue4.ddc"); CHECK(!V2DefaultNamespaceRequest.Bucket.has_value()); CHECK(!V2DefaultNamespaceRequest.HashKey.has_value()); CHECK(!V2DefaultNamespaceRequest.ValueContentId.has_value()); HttpRequestData V2NamespaceRequest; - CHECK(HttpRequestParseRelativeUri("nicenamespace", V2NamespaceRequest)); - CHECK(V2NamespaceRequest.Namespace == "nicenamespace"); + CHECK(HttpRequestParseRelativeUri("nicenamespace", "!default!", V2NamespaceRequest)); + CHECK(V2NamespaceRequest.Namespace == "nicenamespace"sv); CHECK(!V2NamespaceRequest.Bucket.has_value()); CHECK(!V2NamespaceRequest.HashKey.has_value()); CHECK(!V2NamespaceRequest.ValueContentId.has_value()); HttpRequestData V2BucketRequestWithDefaultNamespace; - CHECK(HttpRequestParseRelativeUri("ue4.ddc/test", V2BucketRequestWithDefaultNamespace)); + CHECK(HttpRequestParseRelativeUri("ue4.ddc/test", "!default!", V2BucketRequestWithDefaultNamespace)); CHECK(V2BucketRequestWithDefaultNamespace.Namespace == "ue4.ddc"); - CHECK(V2BucketRequestWithDefaultNamespace.Bucket == "test"); + CHECK(V2BucketRequestWithDefaultNamespace.Bucket == "test"sv); CHECK(!V2BucketRequestWithDefaultNamespace.HashKey.has_value()); CHECK(!V2BucketRequestWithDefaultNamespace.ValueContentId.has_value()); HttpRequestData V2BucketRequestWithNamespace; - CHECK(HttpRequestParseRelativeUri("nicenamespace/test", V2BucketRequestWithNamespace)); - CHECK(V2BucketRequestWithNamespace.Namespace == "nicenamespace"); - CHECK(V2BucketRequestWithNamespace.Bucket == "test"); + CHECK(HttpRequestParseRelativeUri("nicenamespace/test", "!default!", V2BucketRequestWithNamespace)); + CHECK(V2BucketRequestWithNamespace.Namespace == "nicenamespace"sv); + CHECK(V2BucketRequestWithNamespace.Bucket == "test"sv); CHECK(!V2BucketRequestWithNamespace.HashKey.has_value()); CHECK(!V2BucketRequestWithNamespace.ValueContentId.has_value()); HttpRequestData V2HashKeyRequest; - CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", V2HashKeyRequest)); - CHECK(!V2HashKeyRequest.Namespace); + CHECK(HttpRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", "!default!", V2HashKeyRequest)); + CHECK(V2HashKeyRequest.Namespace == "!default!"); CHECK(V2HashKeyRequest.Bucket == "test"); - CHECK(V2HashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234")); + CHECK(V2HashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); CHECK(!V2HashKeyRequest.ValueContentId.has_value()); HttpRequestData V2ValueContentIdRequest; CHECK(HttpRequestParseRelativeUri( "nicenamespace/test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789", + "!default!", V2ValueContentIdRequest)); - CHECK(V2ValueContentIdRequest.Namespace == "nicenamespace"); - CHECK(V2ValueContentIdRequest.Bucket == "test"); - CHECK(V2ValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234")); - CHECK(V2ValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789")); + CHECK(V2ValueContentIdRequest.Namespace == "nicenamespace"sv); + CHECK(V2ValueContentIdRequest.Bucket == "test"sv); + CHECK(V2ValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); + CHECK(V2ValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv)); HttpRequestData Invalid; - CHECK(!HttpRequestParseRelativeUri("", Invalid)); - CHECK(!HttpRequestParseRelativeUri("/", Invalid)); - CHECK(!HttpRequestParseRelativeUri("bad\2_namespace", Invalid)); - CHECK(!HttpRequestParseRelativeUri("nice/\2\1bucket", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789a", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcdef1234", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/pppppppp89abcdef12340123456789abcdef1234", Invalid)); - CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcd", Invalid)); + CHECK(!HttpRequestParseRelativeUri("bad\2_namespace", "!default!", Invalid)); + CHECK(!HttpRequestParseRelativeUri("nice/\2\1bucket", "!default!", Invalid)); + CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789a", "!default!", Invalid)); + CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcdef1234", + "!default!", + Invalid)); + CHECK(!HttpRequestParseRelativeUri("namespace/bucket/pppppppp89abcdef12340123456789abcdef1234", "!default!", Invalid)); + CHECK(!HttpRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcd", "!default!", Invalid)); CHECK(!HttpRequestParseRelativeUri( "namespace/bucket/0123456789abcdef12340123456789abcdef1234/ppppppppdef12345678956789abcdef123456789", + "!default!", Invalid)); } #endif diff --git a/src/zenutil/include/zenutil/cache/cachepolicy.h b/src/zenutil/include/zenutil/cache/cachepolicy.h index c9c9e78a4..7773cd3d1 100644 --- a/src/zenutil/include/zenutil/cache/cachepolicy.h +++ b/src/zenutil/include/zenutil/cache/cachepolicy.h @@ -224,4 +224,6 @@ public: inline void Reset() { *this = OptionalCacheRecordPolicy(); } }; +void cachepolicy_forcelink(); + } // namespace zen diff --git a/src/zenutil/include/zenutil/cache/cacherequests.h b/src/zenutil/include/zenutil/cache/cacherequests.h index f1999ebfe..abc5a3c13 100644 --- a/src/zenutil/include/zenutil/cache/cacherequests.h +++ b/src/zenutil/include/zenutil/cache/cacherequests.h @@ -240,6 +240,10 @@ namespace cacherequests { ////////////////////////////////////////////////////////////////////////// + std::optional<std::string> GetValidNamespaceName(std::string_view Name); + std::optional<std::string> GetValidBucketName(std::string_view Name); + std::optional<IoHash> GetValidIoHash(std::string_view Hash); + struct HttpRequestData { std::optional<std::string> Namespace; @@ -248,7 +252,7 @@ namespace cacherequests { std::optional<IoHash> ValueContentId; }; - bool HttpRequestParseRelativeUri(std::string_view Key, HttpRequestData& Data); + bool HttpRequestParseRelativeUri(std::string_view Key, std::string_view DefaultNamespace, HttpRequestData& Data); // Temporarily public std::optional<std::string> GetRequestNamespace(const CbObjectView& Params); diff --git a/src/zenutil/zenutil.cpp b/src/zenutil/zenutil.cpp index 8544f3401..97ebeb01d 100644 --- a/src/zenutil/zenutil.cpp +++ b/src/zenutil/zenutil.cpp @@ -5,6 +5,7 @@ #if ZEN_WITH_TESTS # include <zenutil/basicfile.h> +# include <zenutil/cache/cacherequests.h> # include <zenutil/cache/rpcrecording.h> # include <zenutil/packageformat.h> @@ -14,8 +15,10 @@ void zenutil_forcelinktests() { basicfile_forcelink(); + cachepolicy_forcelink(); cache::rpcrecord_forcelink(); forcelink_packageformat(); + cacherequests_forcelink(); } } // namespace zen |