// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "NetworkAutomationTest.h" #include "NetworkAutomationTestMacros.h" #include "ReplicatedTestObject.h" #include "Iris/Serialization/NetBitStreamReader.h" #include "Iris/Serialization/NetBitStreamWriter.h" #include "HAL/PlatformMath.h" #include "Iris/DataStream/DataStreamDefinitions.h" #include "Iris/DataStream/DataStreamManager.h" #include "Iris/ReplicationSystem/NetTokenStore.h" #include "Iris/ReplicationSystem/NetTokenDataStream.h" #include "Iris/ReplicationSystem/ReplicationDataStream.h" #include "Iris/ReplicationSystem/ReplicationSystem.h" #include "Net/Core/Misc/ResizableCircularQueue.h" namespace UE::Net { // Utility class to use DataStreams in test code class FDataStreamTestUtil { public: FDataStreamTestUtil(); void SetUp(); void TearDown(); class UMyDataStreamDefinitions : public UDataStreamDefinitions { public: void FixupDefinitions() { return UDataStreamDefinitions::FixupDefinitions(); } }; void StoreDataStreamDefinitions(); void RestoreDataStreamDefinitions(); struct FAddDataStreamDefinitionParams { bool bAutoCreate = false; bool bDynamicCreate = false; bool bValid = true; }; void AddDataStreamDefinition(const TCHAR* StreamName, const TCHAR* ClassPath, const FAddDataStreamDefinitionParams& Params); void AddDataStreamDefinition(const TCHAR* StreamName, const TCHAR* ClassPath) { AddDataStreamDefinition(StreamName, ClassPath, FAddDataStreamDefinitionParams()); } void FixupDefinitions() { DataStreamDefinitions->FixupDefinitions(); } protected: UMyDataStreamDefinitions* DataStreamDefinitions; TArray* CurrentDataStreamDefinitions; TArray PreviousDataStreamDefinitions; bool* PointerToFixupComplete; }; class FNetTokenDataStoreTestUtil { public: void SetUp(); void TearDown(); void StoreNetTokenStoreConfig(); void RestoreNetTokenStoreConfig(); void AddNetTokenStoreTypeIdPair(FString StoreTypeName, uint32 TypeID); private: UNetTokenTypeIdConfig* NetTokenTypeIdConfig = nullptr; TArray OriginalReservedTypeIds; }; // Implements everything we need to drive the replication system to test the system class FReplicationSystemTestNode { public: uint32 MaxSendPacketSize = 2048U; struct FPacketData { enum { MaxPacketSize = 2048U }; alignas(16) uint8 PacketBuffer[MaxPacketSize]; uint32 BitCount; uint32 PacketId; FString Desc; }; struct FConnectionInfo { UDataStreamManager* DataStreamManager = nullptr; TResizableCircularQueue WriteRecords; TResizableCircularQueue WrittenPackets; uint32 ConnectionId = 0; }; struct FReplicationSystemParamsOverride { uint32 MaxReplicatedObjectCount = 0; uint32 InitialNetObjectListCount = 0; uint32 NetObjectListGrowCount = 0; bool bUseRemoteObjectReferences = false; }; enum EDelaySetup { DelaySetup=0 }; public: FReplicationSystemTestNode(bool bIsServer, const TCHAR* Name); explicit FReplicationSystemTestNode(FReplicationSystemTestNode::EDelaySetup); virtual ~FReplicationSystemTestNode(); void Setup(bool bIsServer, const TCHAR* Name, const FReplicationSystemTestNode::FReplicationSystemParamsOverride* ParamsOverride=nullptr); template T* CreateObject() { T* CreatedObject = NewObject(); if (Cast(CreatedObject)) { CreatedObjects.Add(TStrongObjectPtr(CreatedObject)); // Add it to the bridge for replication ReplicationBridge->BeginReplication(CreatedObject); return CreatedObject; } return nullptr; } template T* CreateSubObject(FNetRefHandle OwnerHandle, FNetRefHandle InsertRelativeToSubObjectHandle = FNetRefHandle::GetInvalid(), UReplicationBridge::ESubObjectInsertionOrder InsertionOrder = UReplicationBridge::ESubObjectInsertionOrder::None) { T* CreatedObject = NewObject(); if (Cast(CreatedObject)) { CreatedObjects.Add(TStrongObjectPtr(CreatedObject)); // Add it to the bridge for replication ReplicationBridge->BeginReplication(OwnerHandle, CreatedObject, InsertRelativeToSubObjectHandle, InsertionOrder); return CreatedObject; } return nullptr; } template T* GetObjectAs(FNetRefHandle Handle) { return static_cast(ReplicationBridge->GetReplicatedObject(Handle)); } UTestReplicatedIrisObject* CreateObject(const UObjectReplicationBridge::FRootObjectReplicationParams& Params, UTestReplicatedIrisObject::FComponents* ComponentsToCreate=nullptr); UTestReplicatedIrisObject* CreateObject(uint32 NumComponents, uint32 NumIrisComponents); UTestReplicatedIrisObject* CreateSubObject(FNetRefHandle Owner, uint32 NumComponents, uint32 NumIrisComponents); UTestReplicatedIrisObject* CreateObject(const UTestReplicatedIrisObject::FComponents& Components = UTestReplicatedIrisObject::FComponents()); UTestReplicatedIrisObject* CreateSubObject(FNetRefHandle Owner, const UTestReplicatedIrisObject::FComponents& Components = UTestReplicatedIrisObject::FComponents()); UTestReplicatedIrisObject* CreateObjectWithDynamicState(uint32 NumComponents, uint32 NumIrisComponents, uint32 NumDynamicStateComponents); void DestroyObject(UReplicatedTestObject*, EEndReplicationFlags EndReplicationFlags = EEndReplicationFlags::Destroy); // Returns true if the NetRefHandle can still be resolved to an object. bool IsResolvableNetRefHandle(FNetRefHandle RefHandle); // Returns true if the NetRefHandleManager considers the NetRefHandle valid. bool IsValidNetRefHandle(FNetRefHandle RefHandle); // Connection uint32 AddConnection(); void RemoveConnection(uint32 ConnectionId); // System Update void NetUpdate(); void TickPostReceive(); // Update methods for server connections bool SendUpdate(uint32 ConnectionId, const TCHAR* Desc = nullptr); bool SendUpdate(const TCHAR* Desc = nullptr) { return SendUpdate(1, Desc); } void PostSendUpdate(); void DeliverTo(FReplicationSystemTestNode& Dest, uint32 LocalConnectionId, uint32 RemoteConnectionId, bool bDeliver); void RecvUpdate(uint32 ConnectionId, FNetSerializationContext& Context); void RecvUpdate(FNetSerializationContext& Context) { RecvUpdate(1, Context); } UReplicatedTestObjectBridge* GetReplicationBridge() { return ReplicationBridge; } UReplicationSystem* GetReplicationSystem() { return ReplicationSystem; } uint32 GetReplicationSystemId() const; void SetMaxSendPacketSize(uint32 InMaxSendPacketSize) { MaxSendPacketSize = InMaxSendPacketSize; } FConnectionInfo& GetConnectionInfo(uint32 ConnectionId) { return Connections[ConnectionId - 1]; } uint32 GetNetTraceId() const; float ConvertPollPeriodIntoFrequency(uint32 PollPeriod) const; public: TUniquePtr NetTokenStore; UReplicationSystem* ReplicationSystem = nullptr; UReplicatedTestObjectBridge* ReplicationBridge = nullptr; TArray> CreatedObjects; EReplicationSystemSendPass CurrentSendPass = EReplicationSystemSendPass::Invalid; private: FNetTokenDataStoreTestUtil NetTokenDataStoreUtil; TArray Connections; uint32 PacketId = 0U; }; class FReplicationSystemTestClient : public FReplicationSystemTestNode { public: FReplicationSystemTestClient(const TCHAR* Name); explicit FReplicationSystemTestClient(FReplicationSystemTestNode::EDelaySetup Delay) : FReplicationSystemTestNode(Delay) {} // Tick and send packets to the server bool UpdateAndSend(class FReplicationSystemTestServer* Server, bool bDeliver = true, const TCHAR* Desc = nullptr); uint32 ConnectionIdOnServer; uint32 LocalConnectionId; }; class FReplicationSystemTestServer : public FReplicationSystemTestNode { public: explicit FReplicationSystemTestServer(const TCHAR* Name); explicit FReplicationSystemTestServer(FReplicationSystemTestNode::EDelaySetup Delay) : FReplicationSystemTestNode(Delay) {} // Send data and deliver to the client if bDeliver is true bool SendAndDeliverTo(FReplicationSystemTestClient* Client, bool bDeliver, const TCHAR* Desc = nullptr); // Send data, return true if data was written bool SendTo(FReplicationSystemTestClient* Client, const TCHAR* Desc = nullptr); // Explicitly set delivery status void DeliverTo(FReplicationSystemTestClient* Client, bool bDeliver); // Tick and send packets to one or all clients bool UpdateAndSend(const TArrayView& Clients, bool bDeliver=true, const TCHAR* Desc = nullptr); }; class FReplicationSystemServerClientTestFixture : public FNetworkAutomationTestSuiteFixture { public: FReplicationSystemServerClientTestFixture() : FNetworkAutomationTestSuiteFixture() {} protected: enum : bool { DoNotDeliverPacket = false, DeliverPacket = true, }; virtual void SetUp() override; virtual void TearDown() override; FReplicationSystemTestClient* CreateClient(); void DestroyClient(FReplicationSystemTestClient* Client); FDataStreamTestUtil DataStreamUtil; FNetTokenDataStoreTestUtil NetTokenDataStoreUtil; FReplicationSystemTestServer* Server; TArray Clients; }; }