Files
UnrealEngineUWP/Engine/Source/Developer/DerivedDataCache/Private/Tests/CacheStoreTest.cpp
zousar shaker f3b211baa8 Bump CacheStoreTest version as the AWS file share has had some test values put into it that are expected not to exist, meaning that the test always fails when using AWS as the shared cache.
#rb matt.peters
#jira UE-141632
#preflight 6206deaec663666c89b2df53
#lockdown aurel.cordonnier

#ROBOMERGE-AUTHOR: zousar.shaker
#ROBOMERGE-SOURCE: CL 18963345 in //UE5/Release-5.0/... via CL 18963931 via CL 18964734
#ROBOMERGE-BOT: UE5 (Release-Engine-Test -> Main) (v917-18934589)

[CL 18964750 by zousar shaker in ue5-main branch]
2022-02-11 18:17:49 -05:00

386 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Misc/AutomationTest.h"
#if WITH_DEV_AUTOMATION_TESTS
#include "Containers/Array.h"
#include "Containers/ArrayView.h"
#include "Containers/Map.h"
#include "DerivedDataCache.h"
#include "DerivedDataRequestOwner.h"
#include "Hash/Blake3.h"
#include "Misc/CommandLine.h"
#include "Misc/Parse.h"
#include "Misc/StringBuilder.h"
IMPLEMENT_SIMPLE_AUTOMATION_TEST(FCacheStoreTest, "System.DerivedDataCache.CacheStore",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter);
bool FCacheStoreTest::RunTest(const FString& Parameters)
{
using namespace UE::DerivedData;
ICache& Cache = GetCache();
FStringView TestVersion = TEXTVIEW("D6B05C93623D46D891D354BB22FCB584");
FRequestOwner Owner(EPriority::Blocking);
FCacheBucket DDCTestBucket(TEXT("DDCTest"));
static bool bExpectUpstream = FParse::Param(FCommandLine::Get(), TEXT("CacheStoreTestUpstream"));
static bool bExpectWarm = FParse::Param(FCommandLine::Get(), TEXT("CacheStoreTestWarm"));
// NumKeys = (2 Value vs Record)*(2 SkipData vs Default)*(2 ForceMiss vs Not)*(2 use local)
// *(2 use remote)*(2 UseValue Policy vs not)*(4 cases per type)
constexpr int32 NumKeys = 256;
constexpr int32 NumValues = 4;
TArray<FCachePutRequest> PutRequests;
TArray<FCachePutValueRequest> PutValueRequests;
TArray<FCacheGetRequest> GetRequests;
TArray<FCacheGetValueRequest> GetValueRequests;
TArray<FCacheGetChunkRequest> ChunkRequests;
FValueId ValueIds[NumValues];
for (int32 ValueIndex = 0; ValueIndex < NumValues; ++ValueIndex)
{
ValueIds[ValueIndex] = FValueId::FromName(*WriteToString<16>(TEXT("ValueId_"), ValueIndex));
}
struct FKeyData;
struct FUserData
{
FUserData& Set(FKeyData* InKeyData, int32 InValueIndex)
{
KeyData = InKeyData;
ValueIndex = InValueIndex;
return *this;
}
FKeyData* KeyData = nullptr;
int32 ValueIndex = 0;
};
struct FKeyData
{
FValue BufferValues[NumValues];
uint64 IntValues[NumValues];
FUserData ValueUserData[NumValues];
bool ReceivedChunk[NumValues];
FCacheKey Key;
FUserData KeyUserData;
uint32 KeyIndex = 0;
bool bGetRequestsData = true;
bool bUseValueAPI = false;
bool bUseValuePolicy = false;
bool bForceMiss = false;
bool bUseLocal = true;
bool bUseRemote = true;
bool bShouldBeHit = true;
bool bReceivedPut = false;
bool bReceivedGet = false;
bool bReceivedPutValue = false;
bool bReceivedGetValue = false;
};
FKeyData KeyDatas[NumKeys];
for (uint32 KeyIndex = 0; KeyIndex < NumKeys; ++KeyIndex)
{
FBlake3 KeyWriter;
KeyWriter.Update(*TestName, TestName.Len() * sizeof(TestName[0]));
KeyWriter.Update(TestVersion.GetData(), TestVersion.Len() * sizeof(TestVersion[0]));
KeyWriter.Update(&KeyIndex, sizeof(KeyIndex));
FIoHash KeyHash = KeyWriter.Finalize();
FSharedString Name(WriteToString<16>(TEXT("Key_"), KeyIndex));
FKeyData& KeyData = KeyDatas[KeyIndex];
KeyData.Key = FCacheKey{ DDCTestBucket, KeyHash };
KeyData.KeyIndex = KeyIndex;
KeyData.bGetRequestsData = (KeyIndex & (1 << 1)) == 0;
KeyData.bUseValueAPI = (KeyIndex & (1 << 2)) != 0;
KeyData.bUseValuePolicy = (KeyIndex & (1 << 3)) != 0;
KeyData.bForceMiss = (KeyIndex & (1 << 4)) == 0;
KeyData.bUseLocal = (KeyIndex & (1 << 5)) == 0;
KeyData.bUseRemote = (KeyIndex & (1 << 6)) == 0;
KeyData.bShouldBeHit = !KeyData.bForceMiss && (KeyData.bUseLocal || (KeyData.bUseRemote && bExpectUpstream));
ECachePolicy SharedPolicy = KeyData.bUseLocal ? ECachePolicy::Local : ECachePolicy::None;
SharedPolicy |= KeyData.bUseRemote ? ECachePolicy::Remote : ECachePolicy::None;
ECachePolicy PutPolicy = SharedPolicy;
ECachePolicy GetPolicy = SharedPolicy;
GetPolicy |= !KeyData.bGetRequestsData ? ECachePolicy::SkipData : ECachePolicy::None;
FCacheKey& Key = KeyData.Key;
for (int32 ValueIndex = 0; ValueIndex < NumValues; ++ValueIndex)
{
KeyData.IntValues[ValueIndex] = static_cast<uint64>(KeyIndex) | (static_cast<uint64>(ValueIndex) << 32);
KeyData.BufferValues[ValueIndex] = FValue::Compress(FSharedBuffer::MakeView(&KeyData.IntValues[ValueIndex], sizeof(KeyData.IntValues[ValueIndex])));
KeyData.ReceivedChunk[ValueIndex] = false;
}
static_assert(sizeof(uint64) == sizeof(FUserData*), "Storing pointers in the UserData");
FUserData& KeyUserData = KeyData.KeyUserData.Set(&KeyData, -1);
for (uint32 ValueIndex = 0; ValueIndex < NumValues; ++ValueIndex)
{
KeyData.ValueUserData[ValueIndex].Set(&KeyData, ValueIndex);
}
if (!KeyData.bUseValueAPI)
{
FCacheRecordBuilder Builder(Key);
for (uint32 ValueIndex = 0; ValueIndex < NumValues; ++ValueIndex)
{
Builder.AddValue(ValueIds[ValueIndex], KeyData.BufferValues[ValueIndex]);
}
FCacheRecordPolicy PutRecordPolicy;
FCacheRecordPolicy GetRecordPolicy;
if (!KeyData.bUseValuePolicy)
{
PutRecordPolicy = FCacheRecordPolicy(PutPolicy);
GetRecordPolicy = FCacheRecordPolicy(GetPolicy);
}
else
{
// Switch the SkipData field in the Record policy so that if the CacheStore ignores the ValuePolicies
// it will use the wrong value for SkipData and fail our tests.
FCacheRecordPolicyBuilder PutBuilder(PutPolicy ^ ECachePolicy::SkipData);
FCacheRecordPolicyBuilder GetBuilder(GetPolicy ^ ECachePolicy::SkipData);
for (int32 ValueIndex = 0; ValueIndex < NumValues; ++ValueIndex)
{
PutBuilder.AddValuePolicy(ValueIds[ValueIndex], PutPolicy);
GetBuilder.AddValuePolicy(ValueIds[ValueIndex], GetPolicy);
}
PutRecordPolicy = PutBuilder.Build();
GetRecordPolicy = GetBuilder.Build();
}
if (!KeyData.bForceMiss)
{
PutRequests.Add(FCachePutRequest{ Name, Builder.Build(), PutRecordPolicy, reinterpret_cast<uint64>(&KeyUserData) });
}
GetRequests.Add(FCacheGetRequest{ Name, Key, GetRecordPolicy, reinterpret_cast<uint64>(&KeyUserData) });
for (uint32 ValueIndex = 0; ValueIndex < NumValues; ++ValueIndex)
{
FUserData& ValueUserData = KeyData.ValueUserData[ValueIndex];
ChunkRequests.Add(FCacheGetChunkRequest{ Name, Key, ValueIds[ValueIndex],
0, MAX_uint64, FIoHash(), GetPolicy, reinterpret_cast<uint64>(&ValueUserData) });
}
}
else
{
if (!KeyData.bForceMiss)
{
PutValueRequests.Add(FCachePutValueRequest{ Name, Key, KeyData.BufferValues[0], PutPolicy, reinterpret_cast<uint64>(&KeyUserData) });
}
GetValueRequests.Add(FCacheGetValueRequest{ Name, Key, GetPolicy, reinterpret_cast<uint64>(&KeyUserData) });
ChunkRequests.Add(FCacheGetChunkRequest{ Name, Key, FValueId(),
0, MAX_uint64, FIoHash(), GetPolicy, reinterpret_cast<uint64>(&KeyUserData) });
}
}
if (!bExpectWarm)
{
{
FRequestBarrier Barrier(Owner);
Cache.Put(PutRequests, Owner, [this](FCachePutResponse&& Response)
{
FUserData* UserData = reinterpret_cast<FUserData*>(Response.UserData);
FKeyData* KeyData = UserData->KeyData;
TestTrue(TEXT("Valid UserData in Put Callback"), KeyData != nullptr);
if (KeyData)
{
KeyData->bReceivedPut = true;
}
});
Cache.PutValue(PutValueRequests, Owner, [this](FCachePutValueResponse&& Response)
{
FUserData* UserData = reinterpret_cast<FUserData*>(Response.UserData);
FKeyData* KeyData = UserData->KeyData;
TestTrue(TEXT("Valid UserData in PutValue Callback"), KeyData != nullptr);
if (KeyData)
{
KeyData->bReceivedPutValue = true;
}
});
}
Owner.Wait();
for (FKeyData& KeyData : KeyDatas)
{
int32 n = KeyData.KeyIndex;
if (!KeyData.bForceMiss)
{
if (!KeyData.bUseValueAPI)
{
TestTrue(*WriteToString<16>(TEXT("Put "), n, TEXT(" received")), KeyData.bReceivedPut);
}
else
{
TestTrue(*WriteToString<16>(TEXT("PutValue "), n, TEXT(" received")), KeyData.bReceivedPutValue);
}
}
}
}
{
FRequestBarrier Barrier(Owner);
Cache.Get(GetRequests, Owner, [&ValueIds, this, NumValues](FCacheGetResponse&& Response)
{
FUserData* UserData = reinterpret_cast<FUserData*>(Response.UserData);
FKeyData* KeyData = UserData->KeyData;
TestTrue(TEXT("Valid UserData in Get Callback"), KeyData != nullptr);
if (KeyData)
{
int32 n = (int32)KeyData->KeyIndex;
KeyData->bReceivedGet = true;
if (KeyData->bShouldBeHit)
{
TestEqual(*WriteToString<32>(TEXT("Get "), n, TEXT(" succeeded")), Response.Status, EStatus::Ok);
}
else if (KeyData->bForceMiss)
{
TestEqual(*WriteToString<32>(TEXT("Get "), n, TEXT(" failed as expected")), Response.Status, EStatus::Error);
}
if (!KeyData->bForceMiss && Response.Status == EStatus::Ok)
{
FCacheRecord& Record = Response.Record;
TConstArrayView<FValueWithId> Values = Record.GetValues();
if (TestEqual(*WriteToString<32>(TEXT("Get "), n, TEXT(" ValuesLen")), Values.Num(), NumValues))
{
for (int32 ActualValueIndex = 0; ActualValueIndex < NumValues; ++ActualValueIndex)
{
const FValueWithId& ActualValue = Values[ActualValueIndex];
int32 ExpectedValueIndex = TArrayView<const FValueId>(ValueIds).Find(ActualValue.GetId());
const FValueId& ExpectedValueId = ExpectedValueIndex >= 0 ? ValueIds[ExpectedValueIndex] : FValueId();
TestTrue(*WriteToString<32>(TEXT("Get "), n, TEXT(" ValueId")), ExpectedValueIndex >= 0);
if (ExpectedValueIndex >= 0)
{
FValue& ExpectedValue = KeyData->BufferValues[ExpectedValueIndex];
TestEqual(*WriteToString<32>(TEXT("Get "), n, TEXT(" Hash")),
ActualValue.GetRawHash(), ExpectedValue.GetRawHash());
TestEqual(*WriteToString<32>(TEXT("Get "), n, TEXT(" Size")),
ActualValue.GetRawSize(), ExpectedValue.GetRawSize());
if (KeyData->bGetRequestsData)
{
const FCompressedBuffer& Compressed = ActualValue.GetData();
FSharedBuffer Buffer = Compressed.Decompress();
TestEqual(*WriteToString<32>(TEXT("Get "), n, TEXT(" Data Size")),
Buffer.GetSize(), ActualValue.GetRawSize());
if (Buffer.GetSize())
{
uint64 ActualIntValue = ((const uint64*)Buffer.GetData())[0];
uint64 ExpectedIntValue = KeyData->IntValues[ExpectedValueIndex];
TestEqual(*WriteToString<32>(TEXT("Get "), n, TEXT(" Data Equals"), n),
ActualIntValue, ExpectedIntValue);
}
}
}
}
}
}
}
});
Cache.GetValue(GetValueRequests, Owner, [this](FCacheGetValueResponse&& Response)
{
FUserData* UserData = reinterpret_cast<FUserData*>(Response.UserData);
FKeyData* KeyData = UserData->KeyData;
TestTrue(TEXT("Valid UserData in GetValue Callback"), KeyData != nullptr);
if (KeyData)
{
int32 n = KeyData->KeyIndex;
KeyData->bReceivedGetValue = true;
if (KeyData->bShouldBeHit)
{
TestEqual(*WriteToString<32>(TEXT("GetValue "), n, TEXT(" succeeded")), Response.Status, EStatus::Ok);
}
else if (KeyData->bForceMiss)
{
TestEqual(*WriteToString<32>(TEXT("GetValue "), n, TEXT(" failed as expected")), Response.Status, EStatus::Error);
}
if (!KeyData->bForceMiss && Response.Status == EStatus::Ok)
{
FValue& ActualValue = Response.Value;
FValue& ExpectedValue = KeyData->BufferValues[0];
TestEqual(*WriteToString<32>(TEXT("GetValue "), n, TEXT(" Hash")),
ActualValue.GetRawHash(), ExpectedValue.GetRawHash());
TestEqual(*WriteToString<32>(TEXT("GetValue "), n, TEXT(" Size")),
ActualValue.GetRawSize(), ExpectedValue.GetRawSize());
if (KeyData->bGetRequestsData)
{
const FCompressedBuffer& Compressed = ActualValue.GetData();
FSharedBuffer Buffer = Compressed.Decompress();
TestEqual(*WriteToString<32>(TEXT("GetValue "), n, TEXT(" Data Size")),
Buffer.GetSize(), ActualValue.GetRawSize());
if (Buffer.GetSize())
{
uint64 Value = ((const uint64*)Buffer.GetData())[0];
TestEqual(*WriteToString<32>(TEXT("GetValue "), n, TEXT(" Data Equals")),
Value, KeyData->IntValues[0]);
}
}
}
}
});
Cache.GetChunks(ChunkRequests, Owner, [this](FCacheGetChunkResponse&& Response)
{
FUserData* UserData = reinterpret_cast<FUserData*>(Response.UserData);
FKeyData* KeyData = UserData->KeyData;
TestTrue(TEXT("Valid UserData in GetChunks Callback"), KeyData != nullptr);
if (KeyData != nullptr)
{
int32 n = KeyData->KeyIndex;
int32 ValueIndex = UserData->ValueIndex >= 0 ? UserData->ValueIndex : 0;
TStringBuilder<32> Name;
Name << TEXT("GetChunks (") << n << TEXT(",") << ValueIndex << TEXT(")");
KeyData->ReceivedChunk[ValueIndex] = true;
if (KeyData->bShouldBeHit)
{
TestEqual(*WriteToString<32>(*Name, TEXT(" succeeded")), Response.Status, EStatus::Ok);
}
else if (KeyData->bForceMiss)
{
TestEqual(*WriteToString<32>(*Name, TEXT(" failed as expected")), Response.Status, EStatus::Error);
}
if (KeyData->bShouldBeHit && Response.Status == EStatus::Ok)
{
FValue& ExpectedValue = KeyData->BufferValues[ValueIndex];
TestEqual(*WriteToString<32>(*Name, TEXT(" Hash")),
Response.RawHash, ExpectedValue.GetRawHash());
TestEqual(*WriteToString<32>(*Name, TEXT(" Size")),
Response.RawSize, ExpectedValue.GetRawSize());
if (KeyData->bGetRequestsData)
{
FSharedBuffer Buffer = Response.RawData;
TestEqual(*WriteToString<32>(*Name, TEXT(" Data Size")),
Buffer.GetSize(), Response.RawSize);
if (Buffer.GetSize())
{
uint64 Value = ((const uint64*)Buffer.GetData())[0];
TestEqual(*WriteToString<32>(*Name, TEXT(" Data Equals")),
Value, KeyData->IntValues[ValueIndex]);
}
}
}
}
});
}
Owner.Wait();
for (FKeyData& KeyData : KeyDatas)
{
int32 n = KeyData.KeyIndex;
if (!KeyData.bUseValueAPI)
{
TestTrue(*WriteToString<32>(TEXT("Get "), n, TEXT(" received")), KeyData.bReceivedGet);
for (int32 ValueIndex = 0; ValueIndex < NumValues; ++ValueIndex)
{
TestTrue(*WriteToString<32>(TEXT("GetChunk ("), n, TEXT(","), ValueIndex, TEXT(") received")), KeyData.ReceivedChunk[ValueIndex]);
}
}
else
{
TestTrue(*WriteToString<32>(TEXT("GetValue "), n, TEXT(" received")), KeyData.bReceivedGetValue);
TestTrue(*WriteToString<32>(TEXT("GetChunk ("), n, TEXT(",0) received")), KeyData.ReceivedChunk[0]);
}
}
return true;
}
#endif