// Copyright Epic Games, Inc. All Rights Reserved. #include "cacherequests.h" #include #include #include #include #include #include #include #include #include #include #if ZEN_WITH_TESTS # include #endif namespace zen { namespace cacherequests { std::optional Convert(const OptionalCacheRecordPolicy& Policy) { return Policy.IsValid() ? Policy.Get() : std::optional{}; }; void WriteCacheRequestKey(CbObjectWriter& Writer, const CacheKey& Value) { Writer.BeginObject("Key"); { Writer << "Bucket" << Value.Bucket; Writer << "Hash" << Value.Hash; } Writer.EndObject(); } void WriteOptionalCacheRequestPolicy(CbObjectWriter& Writer, std::string_view FieldName, const std::optional& Policy) { if (Policy) { Writer.SetName(FieldName); Policy->Save(Writer); } } std::optional GetCachePolicy(CbObjectView ObjectView, std::string_view FieldName) { std::string_view DefaultPolicyText = ObjectView[FieldName].AsString(); if (DefaultPolicyText.empty()) { return {}; } return ParseCachePolicy(DefaultPolicyText); } void WriteCachePolicy(CbObjectWriter& Writer, std::string_view FieldName, const std::optional& Policy) { if (Policy) { Writer << FieldName << WriteToString<128>(*Policy); } } bool PutCacheRecordsRequest::Parse(const CbPackage& Package) { CbObjectView BatchObject = Package.GetObject(); ZEN_ASSERT(BatchObject["Method"].AsString() == "PutCacheRecords"); AcceptMagic = BatchObject["AcceptType"].AsUInt32(0); CbObjectView Params = BatchObject["Params"].AsObjectView(); std::optional RequestNamespace = GetCacheRequestNamespace(Params); if (!RequestNamespace) { return false; } Namespace = *RequestNamespace; DefaultPolicy = GetCachePolicy(Params, "DefaultPolicy").value_or(CachePolicy::Default); CbArrayView RequestFieldArray = Params["Requests"].AsArrayView(); Requests.resize(RequestFieldArray.Num()); for (size_t RequestIndex = 0; CbFieldView RequestField : RequestFieldArray) { CbObjectView RequestObject = RequestField.AsObjectView(); CbObjectView RecordObject = RequestObject["Record"].AsObjectView(); CbObjectView KeyView = RecordObject["Key"].AsObjectView(); PutCacheRecordRequest& Request = Requests[RequestIndex++]; if (!GetCacheRequestCacheKey(KeyView, Request.Key)) { return false; } Request.Policy = Convert(CacheRecordPolicy::Load(RequestObject["Policy"].AsObjectView())); std::unordered_map RawHashToAttachmentIndex; CbArrayView ValuesArray = RecordObject["Values"].AsArrayView(); Request.Values.resize(ValuesArray.Num()); RawHashToAttachmentIndex.reserve(ValuesArray.Num()); for (size_t Index = 0; CbFieldView Value : ValuesArray) { CbObjectView ObjectView = Value.AsObjectView(); IoHash AttachmentHash = ObjectView["RawHash"].AsHash(); RawHashToAttachmentIndex[AttachmentHash] = Index; Request.Values[Index++] = {.Id = ObjectView["Id"].AsObjectId(), .RawHash = AttachmentHash}; } RecordObject.IterateAttachments([&](CbFieldView HashView) { const IoHash ValueHash = HashView.AsHash(); if (const CbAttachment* Attachment = Package.FindAttachment(ValueHash)) { if (Attachment->IsCompressedBinary()) { auto It = RawHashToAttachmentIndex.find(ValueHash); ZEN_ASSERT(It != RawHashToAttachmentIndex.end()); PutCacheRecordRequestValue& Value = Request.Values[It->second]; ZEN_ASSERT(Value.RawHash == ValueHash); Value.Body = Attachment->AsCompressedBinary(); ZEN_ASSERT_SLOW(Value.Body.DecodeRawHash() == Value.RawHash); } } }); } return true; } bool PutCacheRecordsRequest::Format(CbPackage& OutPackage) const { CbObjectWriter Writer; Writer << "Method" << "PutCacheRecords"; if (AcceptMagic != 0) { Writer << "Accept" << AcceptMagic; } Writer.BeginObject("Params"); { Writer << "DefaultPolicy" << WriteToString<128>(DefaultPolicy); Writer << "Namespace" << Namespace; Writer.BeginArray("Requests"); for (const PutCacheRecordRequest& RecordRequest : Requests) { Writer.BeginObject(); { Writer.BeginObject("Record"); { WriteCacheRequestKey(Writer, RecordRequest.Key); Writer.BeginArray("Values"); for (const PutCacheRecordRequestValue& Value : RecordRequest.Values) { Writer.BeginObject(); { Writer.AddObjectId("Id", Value.Id); const CompressedBuffer& Buffer = Value.Body; if (Buffer) { IoHash AttachmentHash = Buffer.DecodeRawHash(); // TODO: Slow! Writer.AddBinaryAttachment("RawHash", AttachmentHash); OutPackage.AddAttachment(CbAttachment(Buffer, AttachmentHash)); Writer.AddInteger("RawSize", Buffer.DecodeRawSize()); // TODO: Slow! } else { if (Value.RawHash == IoHash::Zero) { return false; } Writer.AddBinaryAttachment("RawHash", Value.RawHash); } } Writer.EndObject(); } Writer.EndArray(); } Writer.EndObject(); WriteOptionalCacheRequestPolicy(Writer, "Policy", RecordRequest.Policy); } Writer.EndObject(); } Writer.EndArray(); } Writer.EndObject(); OutPackage.SetObject(Writer.Save()); return true; } bool PutCacheRecordsResult::Parse(const CbPackage& Package) { CbArrayView ResultsArray = Package.GetObject()["Result"].AsArrayView(); if (!ResultsArray) { return false; } CbFieldViewIterator It = ResultsArray.CreateViewIterator(); while (It.HasValue()) { Success.push_back(It.AsBool()); It++; } CbArrayView DetailsArray = Package.GetObject()["Details"].AsArrayView(); if (DetailsArray) { It = DetailsArray.CreateViewIterator(); while (It.HasValue()) { Details.push_back(It.AsObjectView()); It++; } } return true; } bool PutCacheRecordsResult::Format(CbPackage& OutPackage) const { CbObjectWriter ResponseObject; ResponseObject.BeginArray("Result"); for (bool Value : Success) { ResponseObject.AddBool(Value); } ResponseObject.EndArray(); if (!Details.empty()) { ResponseObject.BeginArray("Details"); for (CbObjectView Value : Details) { ResponseObject.AddObject(Value); } ResponseObject.EndArray(); } OutPackage.SetObject(ResponseObject.Save()); return true; } bool GetCacheRecordsRequest::Parse(const CbObjectView& RpcRequest) { ZEN_ASSERT(RpcRequest["Method"].AsString() == "GetCacheRecords"); AcceptMagic = RpcRequest["AcceptType"].AsUInt32(0); AcceptOptions = RpcRequest["AcceptFlags"].AsUInt16(0); ProcessPid = RpcRequest["Pid"].AsInt32(0); CbObjectView Params = RpcRequest["Params"].AsObjectView(); std::optional RequestNamespace = GetCacheRequestNamespace(Params); if (!RequestNamespace) { return false; } Namespace = *RequestNamespace; DefaultPolicy = GetCachePolicy(Params, "DefaultPolicy").value_or(CachePolicy::Default); CbArrayView RequestsArray = Params["Requests"].AsArrayView(); Requests.reserve(RequestsArray.Num()); for (CbFieldView RequestField : RequestsArray) { CbObjectView RequestObject = RequestField.AsObjectView(); CbObjectView KeyObject = RequestObject["Key"].AsObjectView(); GetCacheRecordRequest& Request = Requests.emplace_back(); if (!GetCacheRequestCacheKey(KeyObject, Request.Key)) { return false; } Request.Policy = Convert(CacheRecordPolicy::Load(RequestObject["Policy"].AsObjectView())); } return true; } bool GetCacheRecordsRequest::Parse(const CbPackage& RpcRequest) { return Parse(RpcRequest.GetObject()); } bool GetCacheRecordsRequest::Format(CbObjectWriter& Writer, const std::span OptionalRecordFilter) const { Writer << "Method" << "GetCacheRecords"; if (AcceptMagic != 0) { Writer << "Accept" << AcceptMagic; } if (AcceptOptions != 0) { Writer << "AcceptFlags" << AcceptOptions; } if (ProcessPid != 0) { Writer << "Pid" << ProcessPid; } Writer.BeginObject("Params"); { Writer << "DefaultPolicy" << WriteToString<128>(DefaultPolicy); Writer << "Namespace" << Namespace; Writer.BeginArray("Requests"); if (OptionalRecordFilter.empty()) { for (const GetCacheRecordRequest& RecordRequest : Requests) { Writer.BeginObject(); { WriteCacheRequestKey(Writer, RecordRequest.Key); WriteOptionalCacheRequestPolicy(Writer, "Policy", RecordRequest.Policy); } Writer.EndObject(); } } else { for (size_t Index : OptionalRecordFilter) { const GetCacheRecordRequest& RecordRequest = Requests[Index]; Writer.BeginObject(); { WriteCacheRequestKey(Writer, RecordRequest.Key); WriteOptionalCacheRequestPolicy(Writer, "Policy", RecordRequest.Policy); } Writer.EndObject(); } } Writer.EndArray(); } Writer.EndObject(); return true; } bool GetCacheRecordsRequest::Format(CbPackage& OutPackage, const std::span OptionalRecordFilter) const { CbObjectWriter Writer; if (!Format(Writer, OptionalRecordFilter)) { return false; } OutPackage.SetObject(Writer.Save()); return true; } bool GetCacheRecordsResult::Parse(const CbPackage& Package, const std::span OptionalRecordResultIndexes) { CbObject ResponseObject = Package.GetObject(); CbArrayView ResultsArray = ResponseObject["Result"].AsArrayView(); if (!ResultsArray) { return false; } Results.reserve(ResultsArray.Num()); if (!OptionalRecordResultIndexes.empty() && ResultsArray.Num() != OptionalRecordResultIndexes.size()) { return false; } for (size_t Index = 0; CbFieldView RecordView : ResultsArray) { size_t ResultIndex = OptionalRecordResultIndexes.empty() ? Index : OptionalRecordResultIndexes[Index]; Index++; if (Results.size() <= ResultIndex) { Results.resize(ResultIndex + 1); } if (RecordView.IsNull()) { continue; } Results[ResultIndex] = GetCacheRecordResult{}; GetCacheRecordResult& Request = Results[ResultIndex].value(); CbObjectView RecordObject = RecordView.AsObjectView(); CbObjectView KeyObject = RecordObject["Key"].AsObjectView(); if (!GetCacheRequestCacheKey(KeyObject, Request.Key)) { return false; } CbArrayView ValuesArray = RecordObject["Values"].AsArrayView(); Request.Values.reserve(ValuesArray.Num()); for (CbFieldView Value : ValuesArray) { CbObjectView ValueObject = Value.AsObjectView(); IoHash RawHash = ValueObject["RawHash"].AsHash(); uint64_t RawSize = ValueObject["RawSize"].AsUInt64(); Oid Id = ValueObject["Id"].AsObjectId(); const CbAttachment* Attachment = Package.FindAttachment(RawHash); if (!Attachment) { Request.Values.push_back({.Id = Id, .RawHash = RawHash, .RawSize = RawSize, .Body = {}}); continue; } if (!Attachment->IsCompressedBinary()) { return false; } Request.Values.push_back({.Id = Id, .RawHash = RawHash, .RawSize = RawSize, .Body = Attachment->AsCompressedBinary()}); } } return true; } bool GetCacheRecordsResult::Format(CbPackage& OutPackage) const { CbObjectWriter Writer; Writer.BeginArray("Result"); for (const std::optional& RecordResult : Results) { if (!RecordResult.has_value()) { Writer.AddNull(); continue; } Writer.BeginObject(); WriteCacheRequestKey(Writer, RecordResult->Key); Writer.BeginArray("Values"); for (const GetCacheRecordResultValue& Value : RecordResult->Values) { IoHash AttachmentHash = Value.Body ? Value.Body.DecodeRawHash() : Value.RawHash; Writer.BeginObject(); { Writer.AddObjectId("Id", Value.Id); Writer.AddHash("RawHash", AttachmentHash); Writer.AddInteger("RawSize", Value.Body ? Value.Body.DecodeRawSize() : Value.RawSize); } Writer.EndObject(); if (Value.Body) { OutPackage.AddAttachment(CbAttachment(Value.Body, AttachmentHash)); } } Writer.EndArray(); Writer.EndObject(); } Writer.EndArray(); OutPackage.SetObject(Writer.Save()); return true; } bool PutCacheValuesRequest::Parse(const CbPackage& Package) { CbObjectView BatchObject = Package.GetObject(); ZEN_ASSERT(BatchObject["Method"].AsString() == "PutCacheValues"); AcceptMagic = BatchObject["AcceptType"].AsUInt32(0); CbObjectView Params = BatchObject["Params"].AsObjectView(); std::optional RequestNamespace = GetCacheRequestNamespace(Params); if (!RequestNamespace) { return false; } Namespace = *RequestNamespace; DefaultPolicy = GetCachePolicy(Params, "DefaultPolicy").value_or(CachePolicy::Default); CbArrayView RequestsArray = Params["Requests"].AsArrayView(); Requests.reserve(RequestsArray.Num()); for (CbFieldView RequestField : RequestsArray) { CbObjectView RequestObject = RequestField.AsObjectView(); CbObjectView KeyObject = RequestObject["Key"].AsObjectView(); PutCacheValueRequest& Request = Requests.emplace_back(); if (!GetCacheRequestCacheKey(KeyObject, Request.Key)) { return false; } Request.RawHash = RequestObject["RawHash"].AsBinaryAttachment(); Request.Policy = GetCachePolicy(RequestObject, "Policy"); if (const CbAttachment* Attachment = Package.FindAttachment(Request.RawHash)) { if (!Attachment->IsCompressedBinary()) { return false; } Request.Body = Attachment->AsCompressedBinary(); } } return true; } bool PutCacheValuesRequest::Format(CbPackage& OutPackage) const { CbObjectWriter Writer; Writer << "Method" << "PutCacheValues"; if (AcceptMagic != 0) { Writer << "Accept" << AcceptMagic; } Writer.BeginObject("Params"); { Writer << "DefaultPolicy" << WriteToString<128>(DefaultPolicy); Writer << "Namespace" << Namespace; Writer.BeginArray("Requests"); for (const PutCacheValueRequest& ValueRequest : Requests) { Writer.BeginObject(); { WriteCacheRequestKey(Writer, ValueRequest.Key); if (ValueRequest.Body) { IoHash AttachmentHash = ValueRequest.Body.DecodeRawHash(); if (ValueRequest.RawHash != IoHash::Zero && AttachmentHash != ValueRequest.RawHash) { return false; } Writer.AddBinaryAttachment("RawHash", AttachmentHash); OutPackage.AddAttachment(CbAttachment(ValueRequest.Body, AttachmentHash)); } else if (ValueRequest.RawHash != IoHash::Zero) { Writer.AddBinaryAttachment("RawHash", ValueRequest.RawHash); } else { return false; } WriteCachePolicy(Writer, "Policy", ValueRequest.Policy); } Writer.EndObject(); } Writer.EndArray(); } Writer.EndObject(); OutPackage.SetObject(Writer.Save()); return true; } bool PutCacheValuesResult::Parse(const CbPackage& Package) { CbArrayView ResultsArray = Package.GetObject()["Result"].AsArrayView(); if (!ResultsArray) { return false; } CbFieldViewIterator It = ResultsArray.CreateViewIterator(); while (It.HasValue()) { Success.push_back(It.AsBool()); It++; } return true; } bool PutCacheValuesResult::Format(CbPackage& OutPackage) const { if (Success.empty()) { return false; } CbObjectWriter ResponseObject; ResponseObject.BeginArray("Result"); for (bool Value : Success) { ResponseObject.AddBool(Value); } ResponseObject.EndArray(); OutPackage.SetObject(ResponseObject.Save()); return true; } bool GetCacheValuesRequest::Parse(const CbObjectView& BatchObject) { ZEN_ASSERT(BatchObject["Method"].AsString() == "GetCacheValues"); AcceptMagic = BatchObject["AcceptType"].AsUInt32(0); AcceptOptions = BatchObject["AcceptFlags"].AsUInt16(0); ProcessPid = BatchObject["Pid"].AsInt32(0); CbObjectView Params = BatchObject["Params"].AsObjectView(); std::optional RequestNamespace = GetCacheRequestNamespace(Params); if (!RequestNamespace) { return false; } Namespace = *RequestNamespace; DefaultPolicy = GetCachePolicy(Params, "DefaultPolicy").value_or(CachePolicy::Default); CbArrayView RequestsArray = Params["Requests"].AsArrayView(); Requests.reserve(RequestsArray.Num()); for (CbFieldView RequestField : RequestsArray) { CbObjectView RequestObject = RequestField.AsObjectView(); CbObjectView KeyObject = RequestObject["Key"].AsObjectView(); GetCacheValueRequest& Request = Requests.emplace_back(); if (!GetCacheRequestCacheKey(KeyObject, Request.Key)) { return false; } Request.Policy = GetCachePolicy(RequestObject, "Policy"); } return true; } bool GetCacheValuesRequest::Format(CbPackage& OutPackage, const std::span OptionalValueFilter) const { CbObjectWriter Writer; Writer << "Method" << "GetCacheValues"; if (AcceptMagic != 0) { Writer << "Accept" << AcceptMagic; } if (AcceptOptions != 0) { Writer << "AcceptFlags" << AcceptOptions; } if (ProcessPid != 0) { Writer << "Pid" << ProcessPid; } Writer.BeginObject("Params"); { Writer << "DefaultPolicy" << WriteToString<128>(DefaultPolicy); Writer << "Namespace" << Namespace; Writer.BeginArray("Requests"); if (OptionalValueFilter.empty()) { for (const GetCacheValueRequest& ValueRequest : Requests) { Writer.BeginObject(); { WriteCacheRequestKey(Writer, ValueRequest.Key); WriteCachePolicy(Writer, "Policy", ValueRequest.Policy); } Writer.EndObject(); } } else { for (size_t Index : OptionalValueFilter) { const GetCacheValueRequest& ValueRequest = Requests[Index]; Writer.BeginObject(); { WriteCacheRequestKey(Writer, ValueRequest.Key); WriteCachePolicy(Writer, "Policy", ValueRequest.Policy); } Writer.EndObject(); } } Writer.EndArray(); } Writer.EndObject(); OutPackage.SetObject(Writer.Save()); return true; } bool CacheValuesResult::Parse(const CbPackage& Package, const std::span OptionalValueResultIndexes) { CbObject ResponseObject = Package.GetObject(); CbArrayView ResultsArray = ResponseObject["Result"].AsArrayView(); if (!ResultsArray) { return false; } Results.reserve(ResultsArray.Num()); if (!OptionalValueResultIndexes.empty() && ResultsArray.Num() != OptionalValueResultIndexes.size()) { return false; } for (size_t Index = 0; CbFieldView RecordView : ResultsArray) { size_t ResultIndex = OptionalValueResultIndexes.empty() ? Index : OptionalValueResultIndexes[Index]; Index++; if (Results.size() <= ResultIndex) { Results.resize(ResultIndex + 1); } if (RecordView.IsNull()) { continue; } CacheValueResult& ValueResult = Results[ResultIndex]; CbObjectView RecordObject = RecordView.AsObjectView(); CbFieldView RawHashField = RecordObject["RawHash"]; ValueResult.RawHash = RawHashField.AsHash(); bool Succeeded = !RawHashField.HasError(); if (Succeeded) { ValueResult.FragmentOffset = RecordObject["FragmentOffset"].AsUInt64(0); ValueResult.FragmentHash = RecordObject["FragmentHash"].AsHash(); const CbAttachment* Attachment = Package.FindAttachment(ValueResult.FragmentHash == IoHash::Zero ? ValueResult.RawHash : ValueResult.FragmentHash); ValueResult.Body = Attachment ? Attachment->AsCompressedBinary().MakeOwned() : CompressedBuffer(); if (ValueResult.Body) { ValueResult.RawSize = ValueResult.Body.DecodeRawSize(); } else { ValueResult.RawSize = RecordObject["RawSize"].AsUInt64(UINT64_MAX); } } } return true; } bool CacheValuesResult::Format(CbPackage& OutPackage) const { CbObjectWriter ResponseObject; ResponseObject.BeginArray("Result"); for (const CacheValueResult& ValueResult : Results) { ResponseObject.BeginObject(); if (ValueResult.RawHash != IoHash::Zero) { ResponseObject.AddHash("RawHash", ValueResult.RawHash); if (ValueResult.Body) { OutPackage.AddAttachment(CbAttachment(ValueResult.Body, ValueResult.RawHash)); } else { ResponseObject.AddInteger("RawSize", ValueResult.RawSize); } } ResponseObject.EndObject(); } ResponseObject.EndArray(); OutPackage.SetObject(ResponseObject.Save()); return true; } bool GetCacheChunksRequest::Parse(const CbObjectView& BatchObject) { ZEN_ASSERT(BatchObject["Method"].AsString() == "GetCacheChunks"); AcceptMagic = BatchObject["AcceptType"].AsUInt32(0); AcceptOptions = BatchObject["AcceptFlags"].AsUInt16(0); ProcessPid = BatchObject["Pid"].AsInt32(0); CbObjectView Params = BatchObject["Params"].AsObjectView(); std::optional RequestNamespace = GetCacheRequestNamespace(Params); if (!RequestNamespace) { return false; } Namespace = *RequestNamespace; DefaultPolicy = GetCachePolicy(Params, "DefaultPolicy").value_or(CachePolicy::Default); CbArrayView RequestsArray = Params["ChunkRequests"].AsArrayView(); Requests.reserve(RequestsArray.Num()); for (CbFieldView RequestField : RequestsArray) { CbObjectView RequestObject = RequestField.AsObjectView(); CbObjectView KeyObject = RequestObject["Key"].AsObjectView(); GetCacheChunkRequest& Request = Requests.emplace_back(); if (!GetCacheRequestCacheKey(KeyObject, Request.Key)) { return false; } Request.ValueId = RequestObject["ValueId"].AsObjectId(); Request.ChunkId = RequestObject["ChunkId"].AsHash(); Request.RawOffset = RequestObject["RawOffset"].AsUInt64(); Request.RawSize = RequestObject["RawSize"].AsUInt64(UINT64_MAX); Request.Policy = GetCachePolicy(RequestObject, "Policy"); } return true; } bool GetCacheChunksRequest::Format(CbPackage& OutPackage) const { CbObjectWriter Writer; Writer << "Method" << "GetCacheChunks"; if (AcceptMagic != 0) { Writer << "Accept" << AcceptMagic; } if (AcceptOptions != 0) { Writer << "AcceptFlags" << AcceptOptions; } if (ProcessPid != 0) { Writer << "Pid" << ProcessPid; } Writer.BeginObject("Params"); { Writer << "DefaultPolicy" << WriteToString<128>(DefaultPolicy); Writer << "Namespace" << Namespace; Writer.BeginArray("ChunkRequests"); for (const GetCacheChunkRequest& ValueRequest : Requests) { Writer.BeginObject(); { WriteCacheRequestKey(Writer, ValueRequest.Key); Writer.AddObjectId("ValueId", ValueRequest.ValueId); Writer.AddHash("ChunkId", ValueRequest.ChunkId); Writer.AddInteger("RawOffset", ValueRequest.RawOffset); Writer.AddInteger("RawSize", ValueRequest.RawSize); WriteCachePolicy(Writer, "Policy", ValueRequest.Policy); } Writer.EndObject(); } Writer.EndArray(); } Writer.EndObject(); OutPackage.SetObject(Writer.Save()); return true; } // bool CacheRecord::Parse(CbObjectView& Reader) // { // CbObjectView KeyView = Reader["Key"].AsObjectView(); // // if (!GetCacheRequestCacheKey(KeyView, Key)) // { // return false; // } // CbArrayView ValuesArray = Reader["Values"].AsArrayView(); // Values.reserve(ValuesArray.Num()); // for (CbFieldView Value : ValuesArray) // { // CbObjectView ObjectView = Value.AsObjectView(); // Values.push_back({.Id = ObjectView["Id"].AsObjectId(), // .RawHash = ObjectView["RawHash"].AsHash(), // .RawSize = ObjectView["RawSize"].AsUInt64()}); // } // return true; // } // // bool CacheRecord::Format(CbObjectWriter& Writer) const // { // WriteCacheRequestKey(Writer, Key); // Writer.BeginArray("Values"); // for (const CacheRecordValue& Value : Values) // { // Writer.BeginObject(); // { // Writer.AddObjectId("Id", Value.Id); // Writer.AddHash("RawHash", Value.RawHash); // Writer.AddInteger("RawSize", Value.RawSize); // } // Writer.EndObject(); // } // Writer.EndArray(); // return true; // } #if ZEN_WITH_TESTS static bool operator==(const PutCacheRecordRequestValue& Lhs, const PutCacheRecordRequestValue& Rhs) { const IoHash LhsRawHash = Lhs.RawHash != IoHash::Zero ? Lhs.RawHash : Lhs.Body.DecodeRawHash(); const IoHash RhsRawHash = Rhs.RawHash != IoHash::Zero ? Rhs.RawHash : Rhs.Body.DecodeRawHash(); return Lhs.Id == Rhs.Id && LhsRawHash == RhsRawHash && Lhs.Body.GetCompressed().Flatten().GetView().EqualBytes(Rhs.Body.GetCompressed().Flatten().GetView()); } static bool operator==(const zen::CacheValuePolicy& Lhs, const zen::CacheValuePolicy& Rhs) { return (Lhs.Id == Rhs.Id) && (Lhs.Policy == Rhs.Policy); } static bool operator==(const std::span& Lhs, const std::span& Rhs) { if (Lhs.size() != Lhs.size()) { return false; } for (size_t Idx = 0; Idx < Lhs.size(); ++Idx) { if (Lhs[Idx] != Rhs[Idx]) { return false; } } return true; } static bool operator==(const zen::CacheRecordPolicy& Lhs, const zen::CacheRecordPolicy& Rhs) { return (Lhs.GetRecordPolicy() == Rhs.GetRecordPolicy()) && (Lhs.GetBasePolicy() == Rhs.GetBasePolicy()) && (Lhs.GetValuePolicies() == Rhs.GetValuePolicies()); } static bool operator==(const std::optional& Lhs, const std::optional& Rhs) { return (Lhs.has_value() == Rhs.has_value()) && (!Lhs || (*Lhs == *Rhs)); } static bool operator==(const PutCacheRecordRequest& Lhs, const PutCacheRecordRequest& Rhs) { return (Lhs.Key == Rhs.Key) && (Lhs.Values == Rhs.Values) && (Lhs.Policy == Rhs.Policy); } static bool operator==(const PutCacheRecordsRequest& Lhs, const PutCacheRecordsRequest& Rhs) { return (Lhs.DefaultPolicy == Rhs.DefaultPolicy) && (Lhs.Namespace == Rhs.Namespace) && (Lhs.Requests == Rhs.Requests); } static bool operator==(const PutCacheRecordsResult& Lhs, const PutCacheRecordsResult& Rhs) { return (Lhs.Success == Rhs.Success); } static bool operator==(const GetCacheRecordRequest& Lhs, const GetCacheRecordRequest& Rhs) { return (Lhs.Key == Rhs.Key) && (Lhs.Policy == Rhs.Policy); } static bool operator==(const GetCacheRecordsRequest& Lhs, const GetCacheRecordsRequest& Rhs) { return (Lhs.DefaultPolicy == Rhs.DefaultPolicy) && (Lhs.Namespace == Rhs.Namespace) && (Lhs.Requests == Rhs.Requests); } static bool operator==(const GetCacheRecordResultValue& Lhs, const GetCacheRecordResultValue& Rhs) { if ((Lhs.Id != Rhs.Id) || (Lhs.RawHash != Rhs.RawHash) || (Lhs.RawSize != Rhs.RawSize)) { return false; } if (bool(Lhs.Body) != bool(Rhs.Body)) { return false; } if (bool(Lhs.Body) && Lhs.Body.DecodeRawHash() != Rhs.Body.DecodeRawHash()) { return false; } return true; } static bool operator==(const GetCacheRecordResult& Lhs, const GetCacheRecordResult& Rhs) { return Lhs.Key == Rhs.Key && Lhs.Values == Rhs.Values; } static bool operator==(const std::optional& Lhs, const std::optional& Rhs) { if (Lhs.has_value() != Rhs.has_value()) { return false; } return *Lhs == Rhs; } static bool operator==(const GetCacheRecordsResult& Lhs, const GetCacheRecordsResult& Rhs) { return Lhs.Results == Rhs.Results; } static bool operator==(const PutCacheValueRequest& Lhs, const PutCacheValueRequest& Rhs) { if ((Lhs.Key != Rhs.Key) || (Lhs.RawHash != Rhs.RawHash)) { return false; } if (bool(Lhs.Body) != bool(Rhs.Body)) { return false; } if (!Lhs.Body) { return true; } return Lhs.Body.GetCompressed().Flatten().GetView().EqualBytes(Rhs.Body.GetCompressed().Flatten().GetView()); } static bool operator==(const PutCacheValuesRequest& Lhs, const PutCacheValuesRequest& Rhs) { return (Lhs.DefaultPolicy == Rhs.DefaultPolicy) && (Lhs.Namespace == Rhs.Namespace) && (Lhs.Requests == Rhs.Requests); } static bool operator==(const PutCacheValuesResult& Lhs, const PutCacheValuesResult& Rhs) { return (Lhs.Success == Rhs.Success); } static bool operator==(const GetCacheValueRequest& Lhs, const GetCacheValueRequest& Rhs) { return Lhs.Key == Rhs.Key && Lhs.Policy == Rhs.Policy; } static bool operator==(const GetCacheValuesRequest& Lhs, const GetCacheValuesRequest& Rhs) { return Lhs.DefaultPolicy == Rhs.DefaultPolicy && Lhs.Namespace == Rhs.Namespace && Lhs.Requests == Rhs.Requests; } static bool operator==(const CacheValueResult& Lhs, const CacheValueResult& Rhs) { if (Lhs.RawHash != Rhs.RawHash) { return false; }; if (Lhs.Body) { if (!Rhs.Body) { return false; } return Lhs.Body.GetCompressed().Flatten().GetView().EqualBytes(Rhs.Body.GetCompressed().Flatten().GetView()); } return Lhs.RawSize == Rhs.RawSize; } static bool operator==(const CacheValuesResult& Lhs, const CacheValuesResult& Rhs) { return Lhs.Results == Rhs.Results; } static bool operator==(const GetCacheChunkRequest& Lhs, const GetCacheChunkRequest& Rhs) { return Lhs.Key == Rhs.Key && Lhs.ValueId == Rhs.ValueId && Lhs.ChunkId == Rhs.ChunkId && Lhs.RawOffset == Rhs.RawOffset && Lhs.RawSize == Rhs.RawSize && Lhs.Policy == Rhs.Policy; } static bool operator==(const GetCacheChunksRequest& Lhs, const GetCacheChunksRequest& Rhs) { return Lhs.DefaultPolicy == Rhs.DefaultPolicy && Lhs.Namespace == Rhs.Namespace && Lhs.Requests == Rhs.Requests; } static CompressedBuffer MakeCompressedBuffer(size_t Size) { return CompressedBuffer::Compress(SharedBuffer(IoBuffer(Size))); }; TEST_CASE("cacherequests.put.cache.records") { PutCacheRecordsRequest EmptyRequest; CbPackage EmptyRequestPackage; CHECK(EmptyRequest.Format(EmptyRequestPackage)); PutCacheRecordsRequest EmptyRequestCopy; CHECK(!EmptyRequestCopy.Parse(EmptyRequestPackage)); // Namespace is required PutCacheRecordsRequest FullRequest = { .DefaultPolicy = CachePolicy::Remote, .Namespace = "the_namespace", .Requests = {{.Key = {.Bucket = "thebucket", .Hash = IoHash::FromHexString("177030568fdd461bf4fe5ddbf4d463e514e8178e")}, .Values = {{.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(2134)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(213)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(7)}}, .Policy = CachePolicy::StoreLocal}, {.Key = {.Bucket = "thebucket", .Hash = IoHash::FromHexString("d1df59fcab06793a5f2c372d795bb907a15cab15")}, .Values = {{.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(1234)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(99)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(124)}}, .Policy = CachePolicy::Store}, {.Key = {.Bucket = "theotherbucket", .Hash = IoHash::FromHexString("e1ce9e1ac8a6f5953dc14c1fa9512b804ed689df")}, .Values = {{.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(19)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(1248)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(823)}}}}}; CbPackage FullRequestPackage; CHECK(FullRequest.Format(FullRequestPackage)); PutCacheRecordsRequest FullRequestCopy; CHECK(FullRequestCopy.Parse(FullRequestPackage)); CHECK(FullRequest == FullRequestCopy); PutCacheRecordsResult EmptyResult; CbPackage EmptyResponsePackage; CHECK(EmptyResult.Format(EmptyResponsePackage)); PutCacheRecordsResult EmptyResultCopy; CHECK(!EmptyResultCopy.Parse(EmptyResponsePackage)); CHECK(EmptyResult == EmptyResultCopy); PutCacheRecordsResult FullResult = {.Success = {true, false, true, true, false}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); PutCacheRecordsResult FullResultCopy; CHECK(FullResultCopy.Parse(FullResponsePackage)); CHECK(FullResult == FullResultCopy); } TEST_CASE("cacherequests.get.cache.records") { GetCacheRecordsRequest EmptyRequest; CbPackage EmptyRequestPackage; CHECK(EmptyRequest.Format(EmptyRequestPackage)); GetCacheRecordsRequest EmptyRequestCopy; CHECK(!EmptyRequestCopy.Parse(EmptyRequestPackage)); // Namespace is required GetCacheRecordsRequest FullRequest = { .DefaultPolicy = CachePolicy::StoreLocal, .Namespace = "other_namespace", .Requests = {{.Key = {.Bucket = "finebucket", .Hash = IoHash::FromHexString("d1df59fcab06793a5f2c372d795bb907a15cab15")}, .Policy = CachePolicy::Local}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("177030568fdd461bf4fe5ddbf4d463e514e8178e")}, .Policy = CachePolicy::Remote}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("e1ce9e1ac8a6f5953dc14c1fa9512b804ed689df")}}}}; CbPackage FullRequestPackage; CHECK(FullRequest.Format(FullRequestPackage)); GetCacheRecordsRequest FullRequestCopy; CHECK(FullRequestCopy.Parse(FullRequestPackage)); CHECK(FullRequest == FullRequestCopy); CbPackage PartialRequestPackage; CHECK(FullRequest.Format(PartialRequestPackage, std::initializer_list{0, 2})); GetCacheRecordsRequest PartialRequest = FullRequest; PartialRequest.Requests.erase(PartialRequest.Requests.begin() + 1); GetCacheRecordsRequest PartialRequestCopy; CHECK(PartialRequestCopy.Parse(PartialRequestPackage)); CHECK(PartialRequest == PartialRequestCopy); GetCacheRecordsResult EmptyResult; CbPackage EmptyResponsePackage; CHECK(EmptyResult.Format(EmptyResponsePackage)); GetCacheRecordsResult EmptyResultCopy; CHECK(!EmptyResultCopy.Parse(EmptyResponsePackage)); CHECK(EmptyResult == EmptyResultCopy); PutCacheRecordsRequest FullPutRequest = { .DefaultPolicy = CachePolicy::Remote, .Namespace = "the_namespace", .Requests = {{.Key = {.Bucket = "thebucket", .Hash = IoHash::FromHexString("177030568fdd461bf4fe5ddbf4d463e514e8178e")}, .Values = {{.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(2134)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(213)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(7)}}, .Policy = CachePolicy::StoreLocal}, {.Key = {.Bucket = "thebucket", .Hash = IoHash::FromHexString("d1df59fcab06793a5f2c372d795bb907a15cab15")}, .Values = {{.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(1234)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(99)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(124)}}, .Policy = CachePolicy::Store}, {.Key = {.Bucket = "theotherbucket", .Hash = IoHash::FromHexString("e1ce9e1ac8a6f5953dc14c1fa9512b804ed689df")}, .Values = {{.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(19)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(1248)}, {.Id = Oid::NewOid(), .Body = MakeCompressedBuffer(823)}}}}}; CbPackage FullPutRequestPackage; CHECK(FullPutRequest.Format(FullPutRequestPackage)); PutCacheRecordsRequest FullPutRequestCopy; CHECK(FullPutRequestCopy.Parse(FullPutRequestPackage)); GetCacheRecordsResult FullResult = { {GetCacheRecordResult{.Key = FullPutRequestCopy.Requests[0].Key, .Values = {{.Id = FullPutRequestCopy.Requests[0].Values[0].Id, .RawHash = FullPutRequestCopy.Requests[0].Values[0].Body.DecodeRawHash(), .RawSize = FullPutRequestCopy.Requests[0].Values[0].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[0].Values[0].Body}, {.Id = FullPutRequestCopy.Requests[0].Values[1].Id, .RawHash = FullPutRequestCopy.Requests[0].Values[1].Body.DecodeRawHash(), .RawSize = FullPutRequestCopy.Requests[0].Values[1].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[0].Values[1].Body}, {.Id = FullPutRequestCopy.Requests[0].Values[2].Id, .RawHash = FullPutRequestCopy.Requests[0].Values[2].Body.DecodeRawHash(), .RawSize = FullPutRequestCopy.Requests[0].Values[2].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[0].Values[2].Body}}}, {}, // Simulate not have! GetCacheRecordResult{.Key = FullPutRequestCopy.Requests[2].Key, .Values = {{.Id = FullPutRequestCopy.Requests[2].Values[0].Id, .RawHash = FullPutRequestCopy.Requests[2].Values[0].Body.DecodeRawHash(), .RawSize = FullPutRequestCopy.Requests[2].Values[0].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[2].Values[0].Body}, {.Id = FullPutRequestCopy.Requests[2].Values[1].Id, .RawHash = FullPutRequestCopy.Requests[2].Values[1].Body.DecodeRawHash(), .RawSize = FullPutRequestCopy.Requests[2].Values[1].Body.DecodeRawSize(), .Body = {}}, // Simulate not have {.Id = FullPutRequestCopy.Requests[2].Values[2].Id, .RawHash = FullPutRequestCopy.Requests[2].Values[2].Body.DecodeRawHash(), .RawSize = FullPutRequestCopy.Requests[2].Values[2].Body.DecodeRawSize(), .Body = FullPutRequestCopy.Requests[2].Values[2].Body}}}}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); GetCacheRecordsResult FullResultCopy; CHECK(FullResultCopy.Parse(FullResponsePackage)); CHECK(FullResult.Results[0] == FullResultCopy.Results[0]); CHECK(!FullResultCopy.Results[1]); CHECK(FullResult.Results[2] == FullResultCopy.Results[2]); GetCacheRecordsResult PartialResultCopy; CHECK(PartialResultCopy.Parse(FullResponsePackage, std::initializer_list{0, 3, 4})); CHECK(FullResult.Results[0] == PartialResultCopy.Results[0]); CHECK(!PartialResultCopy.Results[1]); CHECK(!PartialResultCopy.Results[2]); CHECK(!PartialResultCopy.Results[3]); CHECK(FullResult.Results[2] == PartialResultCopy.Results[4]); } TEST_CASE("cacherequests.put.cache.values") { PutCacheValuesRequest EmptyRequest; CbPackage EmptyRequestPackage; CHECK(EmptyRequest.Format(EmptyRequestPackage)); PutCacheValuesRequest EmptyRequestCopy; CHECK(!EmptyRequestCopy.Parse(EmptyRequestPackage)); // Namespace is required CompressedBuffer Buffers[3] = {MakeCompressedBuffer(969), MakeCompressedBuffer(3469), MakeCompressedBuffer(9)}; PutCacheValuesRequest FullRequest = { .DefaultPolicy = CachePolicy::StoreLocal, .Namespace = "other_namespace", .Requests = {{.Key = {.Bucket = "finebucket", .Hash = IoHash::FromHexString("d1df59fcab06793a5f2c372d795bb907a15cab15")}, .RawHash = Buffers[0].DecodeRawHash(), .Body = Buffers[0], .Policy = CachePolicy::Local}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("177030568fdd461bf4fe5ddbf4d463e514e8178e")}, .RawHash = Buffers[1].DecodeRawHash(), .Body = Buffers[1], .Policy = CachePolicy::Remote}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("e1ce9e1ac8a6f5953dc14c1fa9512b804ed689df")}, .RawHash = Buffers[2].DecodeRawHash()}}}; CbPackage FullRequestPackage; CHECK(FullRequest.Format(FullRequestPackage)); PutCacheValuesRequest FullRequestCopy; CHECK(FullRequestCopy.Parse(FullRequestPackage)); CHECK(FullRequest == FullRequestCopy); PutCacheValuesResult EmptyResult; CbPackage EmptyResponsePackage; CHECK(!EmptyResult.Format(EmptyResponsePackage)); PutCacheValuesResult FullResult = {.Success = {true, false, true}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); PutCacheValuesResult FullResultCopy; CHECK(FullResultCopy.Parse(FullResponsePackage)); CHECK(FullResult == FullResultCopy); } TEST_CASE("cacherequests.get.cache.values") { GetCacheValuesRequest EmptyRequest; CbPackage EmptyRequestPackage; CHECK(EmptyRequest.Format(EmptyRequestPackage)); GetCacheValuesRequest EmptyRequestCopy; CHECK(!EmptyRequestCopy.Parse(EmptyRequestPackage.GetObject())); // Namespace is required GetCacheValuesRequest FullRequest = { .DefaultPolicy = CachePolicy::StoreLocal, .Namespace = "other_namespace", .Requests = {{.Key = {.Bucket = "finebucket", .Hash = IoHash::FromHexString("d1df59fcab06793a5f2c372d795bb907a15cab15")}, .Policy = CachePolicy::Local}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("177030568fdd461bf4fe5ddbf4d463e514e8178e")}, .Policy = CachePolicy::Remote}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("e1ce9e1ac8a6f5953dc14c1fa9512b804ed689df")}}}}; CbPackage FullRequestPackage; CHECK(FullRequest.Format(FullRequestPackage)); GetCacheValuesRequest FullRequestCopy; CHECK(FullRequestCopy.Parse(FullRequestPackage.GetObject())); CHECK(FullRequest == FullRequestCopy); CbPackage PartialRequestPackage; CHECK(FullRequest.Format(PartialRequestPackage, std::initializer_list{0, 2})); GetCacheValuesRequest PartialRequest = FullRequest; PartialRequest.Requests.erase(PartialRequest.Requests.begin() + 1); GetCacheValuesRequest PartialRequestCopy; CHECK(PartialRequestCopy.Parse(PartialRequestPackage.GetObject())); CHECK(PartialRequest == PartialRequestCopy); CacheValuesResult EmptyResult; CbPackage EmptyResponsePackage; CHECK(EmptyResult.Format(EmptyResponsePackage)); CacheValuesResult EmptyResultCopy; CHECK(!EmptyResultCopy.Parse(EmptyResponsePackage)); CHECK(EmptyResult == EmptyResultCopy); CompressedBuffer Buffers[3][3] = {{MakeCompressedBuffer(123), MakeCompressedBuffer(321), MakeCompressedBuffer(333)}, {MakeCompressedBuffer(6123), MakeCompressedBuffer(8321), MakeCompressedBuffer(7333)}, {MakeCompressedBuffer(5123), MakeCompressedBuffer(2321), MakeCompressedBuffer(2333)}}; CacheValuesResult FullResult = { .Results = {CacheValueResult{.RawSize = 0, .RawHash = Buffers[0][0].DecodeRawHash(), .Body = Buffers[0][0]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[0][1].DecodeRawHash(), .Body = Buffers[0][1]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[0][2].DecodeRawHash(), .Body = Buffers[0][2]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[2][0].DecodeRawHash(), .Body = Buffers[2][0]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[2][1].DecodeRawHash(), .Body = Buffers[2][1]}, CacheValueResult{.RawSize = Buffers[2][2].DecodeRawSize(), .RawHash = Buffers[2][2].DecodeRawHash()}}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); CacheValuesResult FullResultCopy; CHECK(FullResultCopy.Parse(FullResponsePackage)); CHECK(FullResult == FullResultCopy); CacheValuesResult PartialResultCopy; CHECK(PartialResultCopy.Parse(FullResponsePackage, std::initializer_list{0, 3, 4, 5, 6, 9})); CHECK(PartialResultCopy.Results[0] == FullResult.Results[0]); CHECK(PartialResultCopy.Results[1].RawHash == IoHash::Zero); CHECK(PartialResultCopy.Results[2].RawHash == IoHash::Zero); CHECK(PartialResultCopy.Results[3] == FullResult.Results[1]); CHECK(PartialResultCopy.Results[4] == FullResult.Results[2]); CHECK(PartialResultCopy.Results[5] == FullResult.Results[3]); CHECK(PartialResultCopy.Results[6] == FullResult.Results[4]); CHECK(PartialResultCopy.Results[7].RawHash == IoHash::Zero); CHECK(PartialResultCopy.Results[8].RawHash == IoHash::Zero); CHECK(PartialResultCopy.Results[9] == FullResult.Results[5]); } TEST_CASE("cacherequests.get.cache.chunks") { GetCacheChunksRequest EmptyRequest; CbPackage EmptyRequestPackage; CHECK(EmptyRequest.Format(EmptyRequestPackage)); GetCacheChunksRequest EmptyRequestCopy; CHECK(!EmptyRequestCopy.Parse(EmptyRequestPackage.GetObject())); // Namespace is required GetCacheChunksRequest FullRequest = { .DefaultPolicy = CachePolicy::StoreLocal, .Namespace = "other_namespace", .Requests = {{.Key = {.Bucket = "finebucket", .Hash = IoHash::FromHexString("d1df59fcab06793a5f2c372d795bb907a15cab15")}, .ValueId = Oid::NewOid(), .ChunkId = IoHash::FromHexString("ab3917854bfef7e7af2c372d795bb907a15cab15"), .RawOffset = 77, .RawSize = 33, .Policy = CachePolicy::Local}, {.Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("177030568fdd461bf4fe5ddbf4d463e514e8178e")}, .ValueId = Oid::NewOid(), .ChunkId = IoHash::FromHexString("372d795bb907a15cab15ab3917854bfef7e7af2c"), .Policy = CachePolicy::Remote}, { .Key = {.Bucket = "badbucket", .Hash = IoHash::FromHexString("e1ce9e1ac8a6f5953dc14c1fa9512b804ed689df")}, .ChunkId = IoHash::FromHexString("372d795bb907a15cab15ab3917854bfef7e7af2c"), }}}; CbPackage FullRequestPackage; CHECK(FullRequest.Format(FullRequestPackage)); GetCacheChunksRequest FullRequestCopy; CHECK(FullRequestCopy.Parse(FullRequestPackage.GetObject())); CHECK(FullRequest == FullRequestCopy); GetCacheChunksResult EmptyResult; CbPackage EmptyResponsePackage; CHECK(EmptyResult.Format(EmptyResponsePackage)); GetCacheChunksResult EmptyResultCopy; CHECK(!EmptyResultCopy.Parse(EmptyResponsePackage)); CHECK(EmptyResult == EmptyResultCopy); CompressedBuffer Buffers[3][3] = {{MakeCompressedBuffer(123), MakeCompressedBuffer(321), MakeCompressedBuffer(333)}, {MakeCompressedBuffer(6123), MakeCompressedBuffer(8321), MakeCompressedBuffer(7333)}, {MakeCompressedBuffer(5123), MakeCompressedBuffer(2321), MakeCompressedBuffer(2333)}}; GetCacheChunksResult FullResult = { .Results = {CacheValueResult{.RawSize = 0, .RawHash = Buffers[0][0].DecodeRawHash(), .Body = Buffers[0][0]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[0][1].DecodeRawHash(), .Body = Buffers[0][1]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[0][2].DecodeRawHash(), .Body = Buffers[0][2]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[2][0].DecodeRawHash(), .Body = Buffers[2][0]}, CacheValueResult{.RawSize = 0, .RawHash = Buffers[2][1].DecodeRawHash(), .Body = Buffers[2][1]}, CacheValueResult{.RawSize = Buffers[2][2].DecodeRawSize(), .RawHash = Buffers[2][2].DecodeRawHash()}}}; CbPackage FullResponsePackage; CHECK(FullResult.Format(FullResponsePackage)); GetCacheChunksResult FullResultCopy; CHECK(FullResultCopy.Parse(FullResponsePackage)); CHECK(FullResult == FullResultCopy); } TEST_CASE("cachrequests.parse.relative.Uri") { using namespace std::literals; HttpCacheRequestData RootRequest; CHECK(HttpCacheRequestParseRelativeUri("", "!default!", RootRequest)); CHECK(!RootRequest.Namespace.has_value()); CHECK(!RootRequest.Bucket.has_value()); CHECK(!RootRequest.HashKey.has_value()); CHECK(!RootRequest.ValueContentId.has_value()); RootRequest = {}; CHECK(HttpCacheRequestParseRelativeUri("/", "!default!", RootRequest)); CHECK(!RootRequest.Namespace.has_value()); CHECK(!RootRequest.Bucket.has_value()); CHECK(!RootRequest.HashKey.has_value()); CHECK(!RootRequest.ValueContentId.has_value()); HttpCacheRequestData LegacyBucketRequestBecomesNamespaceRequest; CHECK(HttpCacheRequestParseRelativeUri("test", "!default!", LegacyBucketRequestBecomesNamespaceRequest)); CHECK(LegacyBucketRequestBecomesNamespaceRequest.Namespace == "test"sv); CHECK(!LegacyBucketRequestBecomesNamespaceRequest.Bucket.has_value()); CHECK(!LegacyBucketRequestBecomesNamespaceRequest.HashKey.has_value()); CHECK(!LegacyBucketRequestBecomesNamespaceRequest.ValueContentId.has_value()); HttpCacheRequestData LegacyHashKeyRequest; CHECK(HttpCacheRequestParseRelativeUri("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()); HttpCacheRequestData LegacyValueContentIdRequest; CHECK(HttpCacheRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789", "!default!", LegacyValueContentIdRequest)); CHECK(LegacyValueContentIdRequest.Namespace == "!default!"); CHECK(LegacyValueContentIdRequest.Bucket == "test"sv); CHECK(LegacyValueContentIdRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); CHECK(LegacyValueContentIdRequest.ValueContentId == IoHash::FromHexString("56789abcdef12345678956789abcdef123456789"sv)); HttpCacheRequestData V2DefaultNamespaceRequest; CHECK(HttpCacheRequestParseRelativeUri("ue4.ddc", "!default!", V2DefaultNamespaceRequest)); CHECK(V2DefaultNamespaceRequest.Namespace == "ue4.ddc"); CHECK(!V2DefaultNamespaceRequest.Bucket.has_value()); CHECK(!V2DefaultNamespaceRequest.HashKey.has_value()); CHECK(!V2DefaultNamespaceRequest.ValueContentId.has_value()); HttpCacheRequestData V2NamespaceRequest; CHECK(HttpCacheRequestParseRelativeUri("nicenamespace", "!default!", V2NamespaceRequest)); CHECK(V2NamespaceRequest.Namespace == "nicenamespace"sv); CHECK(!V2NamespaceRequest.Bucket.has_value()); CHECK(!V2NamespaceRequest.HashKey.has_value()); CHECK(!V2NamespaceRequest.ValueContentId.has_value()); HttpCacheRequestData V2BucketRequestWithDefaultNamespace; CHECK(HttpCacheRequestParseRelativeUri("ue4.ddc/test", "!default!", V2BucketRequestWithDefaultNamespace)); CHECK(V2BucketRequestWithDefaultNamespace.Namespace == "ue4.ddc"); CHECK(V2BucketRequestWithDefaultNamespace.Bucket == "test"sv); CHECK(!V2BucketRequestWithDefaultNamespace.HashKey.has_value()); CHECK(!V2BucketRequestWithDefaultNamespace.ValueContentId.has_value()); HttpCacheRequestData V2BucketRequestWithNamespace; CHECK(HttpCacheRequestParseRelativeUri("nicenamespace/test", "!default!", V2BucketRequestWithNamespace)); CHECK(V2BucketRequestWithNamespace.Namespace == "nicenamespace"sv); CHECK(V2BucketRequestWithNamespace.Bucket == "test"sv); CHECK(!V2BucketRequestWithNamespace.HashKey.has_value()); CHECK(!V2BucketRequestWithNamespace.ValueContentId.has_value()); HttpCacheRequestData V2HashKeyRequest; CHECK(HttpCacheRequestParseRelativeUri("test/0123456789abcdef12340123456789abcdef1234", "!default!", V2HashKeyRequest)); CHECK(V2HashKeyRequest.Namespace == "!default!"); CHECK(V2HashKeyRequest.Bucket == "test"); CHECK(V2HashKeyRequest.HashKey == IoHash::FromHexString("0123456789abcdef12340123456789abcdef1234"sv)); CHECK(!V2HashKeyRequest.ValueContentId.has_value()); HttpCacheRequestData V2ValueContentIdRequest; CHECK(HttpCacheRequestParseRelativeUri( "nicenamespace/test/0123456789abcdef12340123456789abcdef1234/56789abcdef12345678956789abcdef123456789", "!default!", 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)); HttpCacheRequestData Invalid; CHECK(!HttpCacheRequestParseRelativeUri("bad\2_namespace", "!default!", Invalid)); CHECK(!HttpCacheRequestParseRelativeUri("nice/\2\1bucket", "!default!", Invalid)); CHECK(!HttpCacheRequestParseRelativeUri("namespace/bucket/0123456789a", "!default!", Invalid)); CHECK(!HttpCacheRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcdef1234", "!default!", Invalid)); CHECK(!HttpCacheRequestParseRelativeUri("namespace/bucket/pppppppp89abcdef12340123456789abcdef1234", "!default!", Invalid)); CHECK( !HttpCacheRequestParseRelativeUri("namespace/bucket/0123456789abcdef12340123456789abcdef1234/56789abcd", "!default!", Invalid)); CHECK(!HttpCacheRequestParseRelativeUri( "namespace/bucket/0123456789abcdef12340123456789abcdef1234/ppppppppdef12345678956789abcdef123456789", "!default!", Invalid)); } #endif }} // namespace zen::cacherequests