merge from main

This commit is contained in:
greerdv
2021-05-19 12:14:25 +01:00
11816 changed files with 189923 additions and 1002401 deletions
+1 -1
View File
@@ -301,4 +301,4 @@ TEST_F(BehaviorEntityTest, GetComponentConfiguration_Succeeds)
bool configSuccess = m_behaviorEntity.GetComponentConfiguration(rawComponent->GetId(), retrievedConfig);
EXPECT_TRUE(configSuccess);
EXPECT_EQ(rawComponent->m_config.m_brimWidth, retrievedConfig.m_brimWidth);
}
}
+1 -1
View File
@@ -63,4 +63,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
NAME AZ::Framework.Tests
)
endif()
endif()
+142
View File
@@ -0,0 +1,142 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Viewport/ClickDetector.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
namespace AzFramework
{
std::ostream& operator<<(std::ostream& os, const ClickDetector::ClickOutcome clickOutcome)
{
switch (clickOutcome)
{
case ClickDetector::ClickOutcome::Click:
os << "ClickOutcome::Click";
break;
case ClickDetector::ClickOutcome::Move:
os << "ClickOutcome::Move";
break;
case ClickDetector::ClickOutcome::Release:
os << "ClickOutcome::Release";
break;
case ClickDetector::ClickOutcome::Nil:
os << "ClickOutcome::Nil";
break;
}
return os;
}
} // namespace AzFramework
namespace UnitTest
{
using AzFramework::ClickDetector;
using AzFramework::ScreenVector;
class ClickDetectorFixture : public ::testing::Test
{
public:
ClickDetector m_clickDetector;
};
TEST_F(ClickDetectorFixture, ClickIsDetectedWithNoMouseMovementOnMouseUp)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome initialDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
}
TEST_F(ClickDetectorFixture, MoveIsDetectedWithMouseMovementAfterMouseDown)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome initialDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome initialMoveOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move));
}
TEST_F(ClickDetectorFixture, ReleaseIsDetectedAfterMouseMovementOnMouseUp)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome initialDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
// move
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Release));
}
TEST_F(ClickDetectorFixture, MoveIsReturnedOnlyAfterFirstMouseMove)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome initialDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome initialMoveOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
const ClickDetector::ClickOutcome secondaryMoveOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(10, 10));
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(initialMoveOutcome, Eq(ClickDetector::ClickOutcome::Move));
EXPECT_THAT(secondaryMoveOutcome, Eq(ClickDetector::ClickOutcome::Nil));
}
TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterDoubleClick)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome initialDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
const ClickDetector::ClickOutcome secondaryDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome secondaryUpOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // double click
EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered
}
TEST_F(ClickDetectorFixture, ClickIsNotRegisteredAfterIgnoredDoubleClick)
{
using ::testing::Eq;
const ClickDetector::ClickOutcome initialDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Down, ScreenVector(0, 0));
const ClickDetector::ClickOutcome initialUpOutcome = m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
const ClickDetector::ClickOutcome secondaryDownOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Nil, ScreenVector(0, 0));
const ClickDetector::ClickOutcome secondaryUpOutcome =
m_clickDetector.DetectClick(ClickDetector::ClickEvent::Up, ScreenVector(0, 0));
EXPECT_THAT(initialDownOutcome, Eq(ClickDetector::ClickOutcome::Nil));
EXPECT_THAT(initialUpOutcome, Eq(ClickDetector::ClickOutcome::Click));
EXPECT_THAT(secondaryDownOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // ignored double click
EXPECT_THAT(secondaryUpOutcome, Eq(ClickDetector::ClickOutcome::Nil)); // click not registered
}
} // namespace UnitTest
@@ -177,4 +177,4 @@ namespace UnitTest
EXPECT_NE(testRuntimeComponent, nullptr);
}
}
}
@@ -1100,6 +1100,10 @@ namespace UnitTest
void UnregisterComponentDescriptor(const ComponentDescriptor*) override {}
void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override {}
void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override {}
void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override {}
void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override {}
void SignalEntityActivated(Entity*) override {}
void SignalEntityDeactivated(Entity*) override {}
bool AddEntity(Entity*) override { return true; }
bool RemoveEntity(Entity*) override { return true; }
bool DeleteEntity(const EntityId&) override { return true; }
@@ -1125,6 +1129,7 @@ namespace UnitTest
AllocatorsFixture::SetUp();
ComponentApplicationBus::Handler::BusConnect();
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
m_serializeContext.reset(aznew AZ::SerializeContext(true, true));
Entity::Reflect(m_serializeContext.get());
@@ -1139,6 +1144,7 @@ namespace UnitTest
m_descriptors.set_capacity(0);
m_serializeContext.reset();
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
ComponentApplicationBus::Handler::BusDisconnect();
AllocatorsFixture::TearDown();
+54
View File
@@ -0,0 +1,54 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Viewport/CursorState.h>
namespace UnitTest
{
using AzFramework::CursorState;
using AzFramework::ScreenVector;
using AzFramework::ScreenPoint;
class CursorStateFixture : public ::testing::Test
{
public:
CursorState m_cursorState;
};
TEST_F(CursorStateFixture, CursorStateHasZeroDeltaInitially)
{
using ::testing::Eq;
EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0)));
}
TEST_F(CursorStateFixture, CursorStateReturnsZeroDeltaAfterSingleMoveAndUpdate)
{
using ::testing::Eq;
m_cursorState.SetCurrentPosition(ScreenPoint(10, 10));
m_cursorState.Update();
EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(0, 0)));
}
TEST_F(CursorStateFixture, CursorStateReturnsDeltaAfterSecondMoveAndUpdate)
{
using ::testing::Eq;
m_cursorState.SetCurrentPosition(ScreenPoint(10, 10));
m_cursorState.Update();
m_cursorState.SetCurrentPosition(ScreenPoint(15, 22));
EXPECT_THAT(m_cursorState.CursorDelta(), Eq(ScreenVector(5, 12)));
}
} // namespace UnitTest
@@ -83,4 +83,4 @@ namespace UnitTest
AZStd::aligned_storage<sizeof(NoUserSettingsApplication), AZStd::alignment_of<NoUserSettingsApplication>::value>::type m_applicationBuffer;
AzFramework::Application* m_application;
};
}
}
-58
View File
@@ -1,58 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzTest/AzTest.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <GridMate/Session/Session.h>
namespace UnitTest
{
class MockSession
: public GridMate::GridSession
{
public:
MockSession(GridMate::SessionService* service)
: GridSession(service)
{
}
void SetReplicaManager(GridMate::ReplicaManager* replicaManager)
{
m_replicaMgr = replicaManager;
}
MOCK_METHOD4(CreateRemoteMember, GridMate::GridMember*(const GridMate::string&, GridMate::ReadBuffer&, GridMate::RemotePeerMode, GridMate::ConnectionID));
MOCK_METHOD1(OnSessionParamChanged, void(const GridMate::GridSessionParam&));
MOCK_METHOD1(OnSessionParamRemoved, void(const GridMate::string&));
};
class MockSessionService
: public GridMate::SessionService
{
public:
MockSessionService()
: SessionService(GridMate::SessionServiceDesc())
{
}
~MockSessionService()
{
m_activeSearches.clear();
m_gridMate = nullptr;
}
MOCK_CONST_METHOD0(IsReady, bool());
};
}
@@ -1,151 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "GridMocks.h"
#include <GridMate/Replica/Interest/BitmaskInterestHandler.h>
#include <GridMate/Replica/Interest/InterestManager.h>
#include <GridMate/Replica/Interest/ProximityInterestHandler.h>
#include <AzFramework/Network/InterestManagerComponent.h>
#include <AzCore/Socket/AzSocket.h>
#include <AzCore/UnitTest/TestTypes.h>
namespace UnitTest
{
using testing::_;
class MockInterestManagerEvents
: public AzFramework::InterestManagerEventsBus::Handler
{
public:
MockInterestManagerEvents()
{
BusConnect();
}
virtual ~MockInterestManagerEvents()
{
BusDisconnect();
}
MOCK_METHOD1(OnInterestManagerActivate, void(GridMate::InterestManager* im));
MOCK_METHOD1(OnInterestManagerDeactivate, void(GridMate::InterestManager* im));
};
class InterestManagerComponentFixture
: public AllocatorsFixture
{
public:
InterestManagerComponentFixture()
: AllocatorsFixture()
{
}
~InterestManagerComponentFixture()
{
}
void SetUp() override
{
AZ::AzSock::Startup();
AllocatorsFixture::SetUp();
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create();
m_gridMate = GridMate::GridMateCreate(GridMate::GridMateDesc());
m_carrier = GridMate::DefaultCarrier::Create(GridMate::CarrierDesc(), m_gridMate);
m_sessionService = AZStd::make_unique<UnitTest::MockSessionService>();
m_gridSession = AZStd::make_unique<UnitTest::MockSession>(m_sessionService.get());
m_replicaManagerDesc.m_carrier = m_carrier;
m_replicaManagerDesc.m_myPeerId = AZ::Crc32(testing::UnitTest::GetInstance()->current_test_info()->test_case_name());
m_replicaManagerDesc.m_roles = GridMate::ReplicaMgrDesc::Role_SyncHost;
m_replicaManager = AZStd::make_unique<GridMate::ReplicaManager>();
m_replicaManager->Init(m_replicaManagerDesc);
m_gridSession->SetReplicaManager(m_replicaManager.get());
}
void TearDown() override
{
m_gridSession = nullptr;
m_sessionService = nullptr;
m_replicaManager->Shutdown();
m_replicaManager = nullptr;
m_carrier->Shutdown();
delete m_carrier;
GridMate::GridMateDestroy(m_gridMate);
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
AllocatorsFixture::TearDown();
AZ::AzSock::Cleanup();
}
AZStd::unique_ptr<UnitTest::MockSessionService> m_sessionService;
AZStd::unique_ptr<UnitTest::MockSession> m_gridSession;
GridMate::IGridMate* m_gridMate;
GridMate::Carrier* m_carrier;
GridMate::ReplicaMgrDesc m_replicaManagerDesc;
AZStd::unique_ptr<GridMate::ReplicaManager> m_replicaManager;
};
TEST_F(InterestManagerComponentFixture, TestNetworkSessionDeactivate)
{
// Using StrictMock here will ensure that the test fails if any of the events fire (as no EXPECT_CALL has been set).
testing::StrictMock<MockInterestManagerEvents> interestManagerEvents;
AzFramework::InterestManagerComponent interestManagerComponent;
// This will connect the component to the NetBindingSystemEventsBus
interestManagerComponent.Activate();
// Ensure that the interest manager component handles receiving OnNetworkSessionDeactivated for a session that was never activated.
// This can happen in the event of a client failing to connect to a host.
AzFramework::NetBindingSystemEventsBus::Broadcast(
&AzFramework::NetBindingSystemEvents::OnNetworkSessionDeactivated, m_gridSession.get());
interestManagerComponent.Deactivate();
}
TEST_F(InterestManagerComponentFixture, TestNetworkSessionActivateAndDeactivate)
{
// Using StrictMock here will ensure that the test fails if any of the events fire (as no EXPECT_CALL has been set).
testing::StrictMock<MockInterestManagerEvents> interestManagerEvents;
AzFramework::InterestManagerComponent interestManagerComponent;
GridMate::ReplicaChunkDescriptorTable::Get().RegisterChunkType<GridMate::BitmaskInterestChunk>();
GridMate::ReplicaChunkDescriptorTable::Get().RegisterChunkType<GridMate::ProximityInterestChunk>();
// This will connect the component to the NetBindingSystemEventsBus
interestManagerComponent.Activate();
// Golden path test that the interest manager component behaves as expected under normal conditions
// (receiving OnNetworkSessionActivated followed by OnNetworkSessionDeactivated).
testing::Expectation activationEvent = EXPECT_CALL(interestManagerEvents, OnInterestManagerActivate(_))
.Times(1);
AzFramework::NetBindingSystemEventsBus::Broadcast(
&AzFramework::NetBindingSystemEvents::OnNetworkSessionActivated, m_gridSession.get());
EXPECT_CALL(interestManagerEvents, OnInterestManagerDeactivate(_))
.Times(1)
.After(activationEvent);
AzFramework::NetBindingSystemEventsBus::Broadcast(
&AzFramework::NetBindingSystemEvents::OnNetworkSessionDeactivated, m_gridSession.get());
interestManagerComponent.Deactivate();
}
}
-600
View File
@@ -1,600 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/std/parallel/thread.h>
#include <AzCore/std/containers/ring_buffer.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzFramework/Network/NetBindingComponent.h>
#include <AzFramework/Network/NetBindingSystemComponent.h>
#include <AzFramework/Network/NetBindable.h>
#include <GridMate/GridMate.h>
#include <GridMate/Session/LANSession.h>
#include <GridMate/Replica/ReplicaChunkDescriptor.h>
#include <GridMate/Replica/ReplicaChunk.h>
#include <GridMate/Replica/ReplicaFunctions.h>
#include <GridMate/Replica/DataSet.h>
#include <GridMate/Replica/RemoteProcedureCall.h>
#include <GridMate/Serialize/DataMarshal.h>
#include <GridMate/Serialize/CompressionMarshal.h>
#include <GridMate/Carrier/Utils.h>
#include <AzCore/Asset/AssetManagerComponent.h>
#include <AzCore/Memory/MemoryComponent.h>
#include <AzCore/Memory/AllocationRecords.h>
#include <AzFramework/Entity/GameEntityContextComponent.h>
namespace UnitTest
{
#if 0
using namespace AZ;
/**
*/
class NetBindingTestComponent
: public AZ::Component
, public AzFramework::NetBindable
{
friend class NetBindingComponentChunk;
public:
AZ_COMPONENT(NetBindingTestComponent, "{DE5CF1C0-B4B6-4BB0-86FE-936B400871E0}", AzFramework::NetBindable);
protected:
class NetChunk
: public GridMate::ReplicaChunk
{
public:
AZ_CLASS_ALLOCATOR(NetChunk, AZ::SystemAllocator, 0);
static const char* GetChunkName() { return "NetBindingTestComponent::NetChunk"; }
bool IsReplicaMigratable() override { return false; }
};
///////////////////////////////////////////////////////////////////////
// NetBindable
GridMate::ReplicaChunkPtr GetNetworkBinding() override
{
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::GetNetworkBinding()\n");
m_chunk = GridMate::CreateReplicaChunk<NetChunk>();
AZ_Assert(m_chunk, "Failed to create NetBindingTestComponent::NetChunk!");
return m_chunk;
}
void SetNetworkBinding(GridMate::ReplicaChunkPtr binding) override
{
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::SetNetworkBinding()\n");
AZ_TEST_ASSERT(binding);
AZ_TEST_ASSERT(binding->GetDescriptor()->GetChunkTypeId() == GridMate::ReplicaChunkClassId(NetChunk::GetChunkName()));
m_chunk = AZStd::static_pointer_cast<NetChunk>(binding);
}
void UnbindFromNetwork() override
{
if (m_chunk)
{
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::UnbindFromNetwork()\n");
m_chunk = nullptr;
}
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// AZ::Component
static void Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<NetBindingTestComponent, AZ::Component, AzFramework::NetBindable>()
;
}
// We also need to register the chunk type, and this would be a good time to do so.
GridMate::ReplicaChunkDescriptorTable::Get().RegisterChunkType<NetChunk>();
}
void Activate() override
{
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::Activate()\n");
}
void Deactivate() override
{
AZ_TracePrintf("NetBinding", "NetBindingTestComponent::Deactivate()\n");
UnbindFromNetwork();
}
///////////////////////////////////////////////////////////////////////
AZStd::intrusive_ptr<NetChunk> m_chunk;
};
/**
* Fakes the behavior of NetBindingSystemContextData on the host side
*/
class FakeNetBindingContextChunk
: public GridMate::ReplicaChunk
{
public:
AZ_CLASS_ALLOCATOR(FakeNetBindingContextChunk, AZ::SystemAllocator, 0);
static const char* GetChunkName() { return "NetBindingSystemContextData"; } // We are pretending to be a NetBindingSystemContextData
FakeNetBindingContextChunk()
: m_bindingContextSequence("BindingContextSequence", AzFramework::UnspecifiedNetBindingContextSequence)
{
}
bool IsReplicaMigratable() override { return true; }
GridMate::DataSet<AZ::u32, GridMate::VlqU32Marshaler> m_bindingContextSequence;
};
/*
* NetBindingSystemComponentLifecycleTest
*/
class NetBindingSystemComponentLifecycleTest
: public GridMate::SessionEventBus::Handler
, public AzFramework::NetBindingHandlerBus::Handler
{
public:
void OnSessionCreated(GridMate::GridSession* session) override
{
if (session == m_session)
{
if (session->IsHost())
{
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
}
}
}
void OnSessionJoined(GridMate::GridSession* session) override
{
if (session == m_session)
{
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
}
}
void OnSessionDelete(GridMate::GridSession* session)
{
if (session == m_session)
{
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionDeactivated, session);
m_session = nullptr;
}
}
void BindToNetwork(GridMate::ReplicaPtr bindTo) override
{
// Verify that BindToNetwork() is not called more than once
AZ_TEST_ASSERT(!m_receivedBindEvent);
m_receivedBindEvent = true;
// Test that now we should be binding to the network
bool shouldBindToNetwork = false;
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
AZ_TEST_ASSERT(shouldBindToNetwork);
// Verify that the context sequence is no longer unspecified
AzFramework::NetBindingContextSequence contextSequence = AzFramework::UnspecifiedNetBindingContextSequence;
EBUS_EVENT_RESULT(contextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(contextSequence != AzFramework::UnspecifiedNetBindingContextSequence);
}
void UnbindFromNetwork() override
{
// Verify that UnbindFromNetwork() is not called more than once
AZ_TEST_ASSERT(!m_receivedUnbindEvent);
m_receivedUnbindEvent = true;
}
void run()
{
// Setup
AZ::ComponentApplication app;
AZ::ComponentApplication::Descriptor appDesc;
appDesc.m_recordsMode = AZ::Debug::AllocationRecords::RECORD_FULL;
AZ::Entity* systemEntity = app.Create(appDesc);
app.RegisterComponentDescriptor(AzFramework::NetBindingSystemComponent::CreateDescriptor());
app.RegisterComponentDescriptor(AzFramework::GameEntityContextComponent::CreateDescriptor());
systemEntity->Init();
systemEntity->CreateComponent<AZ::MemoryComponent>();
systemEntity->CreateComponent<AZ::AssetManagerComponent>();
systemEntity->CreateComponent<AzFramework::GameEntityContextComponent>();
systemEntity->CreateComponent<AzFramework::NetBindingSystemComponent>();
systemEntity->Activate();
AzFramework::NetBindingHandlerBus::Handler::BusConnect();
GridMate::GridMateDesc gridMateDesc;
GridMate::IGridMate* gridMate = GridMate::GridMateCreate(gridMateDesc);
GridMate::GridMateAllocatorMP::Descriptor allocDesc;
allocDesc.m_stackRecordLevels = 15;
allocDesc.m_custom = &AZ::AllocatorInstance<AZ::SystemAllocator>::Get();
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create(allocDesc);
if (AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Get().GetRecords())
{
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Get().GetRecords()->SetMode(AZ::Debug::AllocationRecords::RECORD_FULL);
}
GridMate::StartGridMateService<GridMate::LANSessionService>(gridMate, GridMate::SessionServiceDesc());
GridMate::SessionEventBus::Handler::BusConnect(gridMate);
// Test offline behavior
{
bool shouldBindToNetwork = true;
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
AZ_TEST_ASSERT(!shouldBindToNetwork);
AzFramework::NetBindingContextSequence offlineContextSequence = 0xBADF00D;
EBUS_EVENT_RESULT(offlineContextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(offlineContextSequence == AzFramework::UnspecifiedNetBindingContextSequence);
}
// Test host-side behavior
{
m_receivedBindEvent = m_receivedUnbindEvent = false;
// Host a session
GridMate::CarrierDesc carrierDesc;
carrierDesc.m_enableDisconnectDetection = true;
GridMate::LANSessionParams sessionParams;
sessionParams.m_numPublicSlots = 10;
sessionParams.m_flags = 0;
sessionParams.m_port = HOST_PORT;
sessionParams.m_params[sessionParams.m_numParams].m_id = "filter";
sessionParams.m_params[sessionParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
sessionParams.m_numParams++;
m_session = gridMate->GetMultiplayerService()->HostSession(&sessionParams, carrierDesc);
int nFrame = 0;
while (m_session)
{
if (nFrame == 10)
{
// Verify that BindToNetwork() has been called
AZ_TEST_ASSERT(m_receivedBindEvent);
// Verify that we have a valid context sequence
AzFramework::NetBindingContextSequence contextSequence1 = AzFramework::UnspecifiedNetBindingContextSequence;
EBUS_EVENT_RESULT(contextSequence1, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(contextSequence1 != AzFramework::UnspecifiedNetBindingContextSequence);
EBUS_EVENT(AzFramework::GameEntityContextRequestBus, ResetGameContext);
// Verify that the context sequence was incremented
AzFramework::NetBindingContextSequence contextSequence2 = contextSequence1;
EBUS_EVENT_RESULT(contextSequence2, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(contextSequence2 != AzFramework::UnspecifiedNetBindingContextSequence);
AZ_TEST_ASSERT(contextSequence2 > contextSequence1);
m_session->Leave(false);
}
app.Tick();
gridMate->Update();
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
nFrame++;
}
// Verify that we should no longer bind to the network
bool shouldBindToNetwork = true;
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
AZ_TEST_ASSERT(!shouldBindToNetwork);
// Verify that the context sequence was reset to unspecified
AzFramework::NetBindingContextSequence offlineContextSequence = 0xBADF00D;
EBUS_EVENT_RESULT(offlineContextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(offlineContextSequence == AzFramework::UnspecifiedNetBindingContextSequence);
}
// Test nonhost-side behavior by faking the behavior on the host side and then joining the host session.
{
m_receivedBindEvent = m_receivedUnbindEvent = false;
// Host a session
GridMate::CarrierDesc carrierDesc;
carrierDesc.m_enableDisconnectDetection = true;
GridMate::LANSessionParams sessionParams;
sessionParams.m_numPublicSlots = 10;
sessionParams.m_flags = 0;
sessionParams.m_port = HOST_PORT;
sessionParams.m_params[sessionParams.m_numParams].m_id = "filter";
sessionParams.m_params[sessionParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
sessionParams.m_numParams++;
GridMate::GridSession* hostSession = gridMate->GetMultiplayerService()->HostSession(&sessionParams, carrierDesc);
// Add the fake context replica on the host and set the context sequence to 1
GridMate::ReplicaPtr replica = GridMate::Replica::CreateReplica("Potato");
FakeNetBindingContextChunk* contextChunk = GridMate::CreateReplicaChunk<FakeNetBindingContextChunk>();
replica->AttachReplicaChunk(contextChunk);
while (!hostSession->IsReady())
{
gridMate->Update();
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
}
hostSession->GetReplicaMgr()->AddMaster(replica);
contextChunk->m_bindingContextSequence.Set(1);
int nFrame = 0;
while (m_session)
{
if (nFrame == 10)
{
// Join the hosted session
GridMate::SessionIdInfo sessionInfo;
sessionInfo.m_sessionId = hostSession->GetId();
m_session = gridMate->GetMultiplayerService()->JoinSession(&sessionInfo, GridMate::JoinParams(), carrierDesc);
}
if (nFrame == 20)
{
// Verify that BindToNetwork() has been called
AZ_TEST_ASSERT(m_receivedBindEvent);
// Verify that we have a valid context sequence
AzFramework::NetBindingContextSequence contextSequence = AzFramework::UnspecifiedNetBindingContextSequence;
EBUS_EVENT_RESULT(contextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(contextSequence == contextChunk->m_bindingContextSequence.Get());
// Simulate a context switch on the host
contextChunk->m_bindingContextSequence.Set(contextChunk->m_bindingContextSequence.Get() + 1);
}
if (nFrame == 30)
{
// Verify that the context sequence was incremented
AzFramework::NetBindingContextSequence contextSequence = AzFramework::UnspecifiedNetBindingContextSequence;
EBUS_EVENT_RESULT(contextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(contextSequence == contextChunk->m_bindingContextSequence.Get());
hostSession->Leave(false);
}
app.Tick();
gridMate->Update();
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
nFrame++;
}
// Verify that we should no longer bind to the network
bool shouldBindToNetwork = true;
EBUS_EVENT_RESULT(shouldBindToNetwork, AzFramework::NetBindingSystemBus, ShouldBindToNetwork);
AZ_TEST_ASSERT(!shouldBindToNetwork);
// Verify that the context sequence was reset to unspecified
AzFramework::NetBindingContextSequence offlineContextSequence = 0xBADF00D;
EBUS_EVENT_RESULT(offlineContextSequence, AzFramework::NetBindingSystemBus, GetCurrentContextSequence);
AZ_TEST_ASSERT(offlineContextSequence == AzFramework::UnspecifiedNetBindingContextSequence);
}
// Clean up
GridMate::SessionEventBus::Handler::BusDisconnect();
GridMate::GridMateDestroy(gridMate);
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
AzFramework::NetBindingHandlerBus::Handler::BusDisconnect();
app.Destroy();
}
static const int HOST_PORT = 5000;
GridMate::GridSession* m_session;
bool m_receivedBindEvent;
bool m_receivedUnbindEvent;
};
/*
* NetBindingFeatureTest (requires two instances)
*/
class NetBindingFeatureTest
: public GridMate::SessionEventBus::Handler
{
public:
void OnSessionCreated(GridMate::GridSession* session) override
{
if (session == m_session)
{
if (session->IsHost())
{
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
}
}
}
void OnSessionJoined(GridMate::GridSession* session) override
{
if (session == m_session)
{
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionActivated, session);
}
}
void OnSessionDelete(GridMate::GridSession* session)
{
if (session == m_session)
{
EBUS_EVENT(AzFramework::NetBindingSystemBus, OnNetworkSessionDeactivated, session);
m_session = nullptr;
}
}
void OnGridSearchComplete(GridMate::GridSearch* results) override
{
if (results == m_search)
{
GridMate::CarrierDesc carrierDesc;
carrierDesc.m_enableDisconnectDetection = true;
// Create an entity before we get in the session
AZ_TracePrintf("NetBinding", "Spawning master entity...\n");
AZ::Entity* newEntity = nullptr;
newEntity = aznew Entity;
newEntity->CreateComponent<NetBindingTestComponent>();
newEntity->CreateComponent<AzFramework::NetBindingComponent>();
newEntity->Init();
newEntity->Activate();
m_entities.push_back(newEntity);
if (results->GetNumResults() == 0)
{
// Host a session instead
GridMate::LANSessionParams sessionParams;
sessionParams.m_numPublicSlots = 10;
sessionParams.m_flags = 0;
sessionParams.m_port = HOST_PORT;
sessionParams.m_params[sessionParams.m_numParams].m_id = "filter";
sessionParams.m_params[sessionParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
sessionParams.m_numParams++;
m_session = m_gridMate->GetMultiplayerService()->HostSession(&sessionParams, carrierDesc);
m_search->Release();
}
else
{
// Join the session
GridMate::JoinParams joinParams;
m_session = m_gridMate->GetMultiplayerService()->JoinSession(results->GetResult(0), joinParams, carrierDesc);
}
m_search = nullptr;
}
}
void OnMemberJoined(GridMate::GridSession* session, GridMate::GridMember* member) override
{
if (session == m_session)
{
if (session->IsHost())
{
if (member != session->GetMyMember())
{
// Spawn an entity after session creation
AZ_TracePrintf("NetBinding", "Spawning master entity...\n");
AZ::Entity* newEntity = nullptr;
EBUS_EVENT_RESULT(newEntity, AzFramework::GameEntityContextRequestBus, CreateGameEntity, "ReplicatedEntity2");
newEntity->CreateComponent<NetBindingTestComponent>();
newEntity->CreateComponent<AzFramework::NetBindingComponent>();
newEntity->Init();
newEntity->Activate();
m_entities.push_back(newEntity);
}
}
}
}
void run()
{
m_gridMate = nullptr;
m_session = nullptr;
AZ::ComponentApplication app;
AZ::ComponentApplication::Descriptor appDesc;
AZ::Entity* systemEntity = app.Create(appDesc);
app.RegisterComponentDescriptor(AzFramework::NetBindingSystemComponent::CreateDescriptor());
app.RegisterComponentDescriptor(AzFramework::NetBindingComponent::CreateDescriptor());
app.RegisterComponentDescriptor(NetBindingTestComponent::CreateDescriptor());
app.RegisterComponentDescriptor(AzFramework::GameEntityContextComponent::CreateDescriptor());
systemEntity->Init();
systemEntity->CreateComponent<AZ::MemoryComponent>();
systemEntity->CreateComponent<AZ::AssetManagerComponent>();
systemEntity->CreateComponent<AzFramework::GameEntityContextComponent>();
systemEntity->CreateComponent<AzFramework::NetBindingSystemComponent>();
systemEntity->Activate();
GridMate::GridMateDesc gridMateDesc;
m_gridMate = GridMate::GridMateCreate(gridMateDesc);
GridMate::GridMateAllocatorMP::Descriptor allocDesc;
allocDesc.m_custom = &AZ::AllocatorInstance<AZ::SystemAllocator>::Get();
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create(allocDesc);
GridMate::StartGridMateService<GridMate::LANSessionService>(m_gridMate, GridMate::SessionServiceDesc());
GridMate::SessionEventBus::Handler::BusConnect(m_gridMate);
// Search for an existing session
// If a session is not found, we will host a session from within the search callback.
{
GridMate::LANSearchParams searchParams;
searchParams.m_serverPort = HOST_PORT;
searchParams.m_params[searchParams.m_numParams].m_id = "filter";
searchParams.m_params[searchParams.m_numParams].m_value = GridMate::Utils::GetMachineAddress();
searchParams.m_params[searchParams.m_numParams].m_op = GridMate::GridSessionSearchOperators::SSO_OPERATOR_EQUAL;
searchParams.m_numParams++;
m_search = m_gridMate->GetMultiplayerService()->StartGridSearch(&searchParams);
while (m_search)
{
m_gridMate->Update();
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
}
}
// Tick for a while
//static int nTicks = 100;
for (int i = 0; m_session; ++i)
{
if (m_session->IsHost())
{
if (i > 4000 && m_session->GetNumberOfMembers() == 1)
{
m_session->Leave(false);
}
}
m_gridMate->Update();
app.Tick();
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(10));
}
GridMate::SessionEventBus::Handler::BusDisconnect();
GridMate::GridMateDestroy(m_gridMate);
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
for (AZ::Entity* entity : m_entities)
{
AzFramework::EntityContextId contextId = AzFramework::EntityContextId::CreateNull();
EBUS_EVENT_ID_RESULT(contextId, entity->GetId(), AzFramework::EntityIdContextQueryBus, GetOwningContextId);
if (contextId.IsNull())
{
delete entity;
}
else
{
EBUS_EVENT(AzFramework::GameEntityContextRequestBus, DestroyGameEntity, entity);
}
}
app.Destroy();
}
static const int HOST_PORT = 6000;
GridMate::IGridMate* m_gridMate;
GridMate::GridSession* m_session;
GridMate::GridSearch* m_search;
AZStd::fixed_vector<AZ::Entity*, 10> m_entities;
};
#endif
}
AZ_TEST_SUITE(NetBinding)
//AZ_TEST(UnitTest::NetBindingSystemComponentLifecycleTest)
//AZ_TEST(UnitTest::NetBindingFeatureTest)
AZ_TEST_SUITE_END
-330
View File
@@ -1,330 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#ifndef AZCORE_UNITTEST_NETBINDINGMOCKS_H
#define AZCORE_UNITTEST_NETBINDINGMOCKS_H
#include <AzTest/AzTest.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Entity/SliceGameEntityOwnershipServiceBus.h>
#include <AzCore/Slice/SliceComponent.h>
#include <AzFramework/Network/NetBindingHandlerBus.h>
namespace UnitTest
{
class MockGameEntityContext
: public AzFramework::GameEntityContextRequestBus::Handler
, public AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler
{
public:
MockGameEntityContext()
{
AzFramework::GameEntityContextRequestBus::Handler::BusConnect();
AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusConnect();
}
~MockGameEntityContext()
{
AzFramework::SliceGameEntityOwnershipServiceRequestBus::Handler::BusDisconnect();
AzFramework::GameEntityContextRequestBus::Handler::BusDisconnect();
}
MOCK_METHOD3(InstantiateDynamicSlice, AzFramework::SliceInstantiationTicket(const AZ::Data::Asset<AZ::Data::AssetData>&, const AZ::Transform&, const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper&));
MOCK_METHOD0(GetGameEntityContextId, AzFramework::EntityContextId());
MOCK_METHOD1(CreateGameEntity, AZ::Entity*(const char*));
MOCK_METHOD1(AddGameEntity, void (AZ::Entity*));
MOCK_METHOD1(DestroyGameEntity, void (const AZ::EntityId&));
MOCK_METHOD1(DestroyGameEntityAndDescendants, void (const AZ::EntityId&));
MOCK_METHOD1(ActivateGameEntity, void (const AZ::EntityId&));
MOCK_METHOD1(DeactivateGameEntity, void (const AZ::EntityId&));
MOCK_METHOD1(DestroyDynamicSliceByEntity, bool (const AZ::EntityId&));
MOCK_METHOD2(LoadFromStream, bool (AZ::IO::GenericStream&, bool));
MOCK_METHOD0(ResetGameContext, void ());
MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&));
MOCK_METHOD1(DestroySliceByEntity, bool(const AZ::EntityId&));
MOCK_METHOD1(CreateGameEntityForBehaviorContext, AzFramework::BehaviorEntity (const char *));
MOCK_METHOD1(CancelDynamicSliceInstantiation, void (const AzFramework::SliceInstantiationTicket &));
};
class MockNetBindingSystemContextData
: public AzFramework::NetBindingSystemContextData
{
public:
AZ_CLASS_ALLOCATOR(MockNetBindingSystemContextData, AZ::SystemAllocator, 0);
static const char* GetChunkName()
{
return "MockNetBindingSystemContextData";
}
MOCK_METHOD1(OnAttachedToReplica, void (GridMate::Replica*));
MOCK_METHOD1(OnDetachedFromReplica, void (GridMate::Replica*));
MOCK_METHOD1(UpdateChunk, void (const GridMate::ReplicaContext&));
MOCK_METHOD1(UpdateFromChunk, void (const GridMate::ReplicaContext&));
MOCK_METHOD2(AcceptChangeOwnership, bool (GridMate::PeerId, const GridMate::ReplicaContext&));
MOCK_METHOD1(OnReplicaChangeOwnership, void (const GridMate::ReplicaContext&));
MOCK_METHOD0(IsUpdateFromReplicaEnabled, bool ());
MOCK_CONST_METHOD1(ShouldSendToPeer, bool (GridMate::ReplicaPeer*));
MOCK_METHOD1(CalculateDirtyDataSetMask, AZ::u32 (GridMate::MarshalContext&));
MOCK_METHOD1(OnDataSetChanged, void (const GridMate::DataSetBase&));
MOCK_METHOD2(Marshal, void (GridMate::MarshalContext&, AZ::u32));
MOCK_METHOD2(Unmarshal, void (GridMate::UnmarshalContext&, AZ::u32));
MOCK_METHOD0(IsReplicaMigratable, bool ());
MOCK_METHOD0(IsBroadcast, bool ());
MOCK_METHOD1(OnReplicaActivate, void (const GridMate::ReplicaContext&));
MOCK_METHOD1(OnReplicaDeactivate, void (const GridMate::ReplicaContext&));
/**
* \brief Helper method for GoogleMock to call NetBindingSystemContextData::OnReplicaActivate
*/
void Base_OnReplicaActivate(const GridMate::ReplicaContext& rc)
{
NetBindingSystemContextData::OnReplicaActivate(rc);
}
MOCK_METHOD0(GetReplicaManager, GridMate::ReplicaManager* ());
MOCK_METHOD0(ShouldBindToNetwork, bool ());
};
class MockReplicaManager
: public GridMate::ReplicaManager
{
public:
MOCK_METHOD2(OnIncomingConnection, void (GridMate::Carrier*, GridMate::ConnectionID));
MOCK_METHOD3(OnFailedToConnect, void (GridMate::Carrier*, GridMate::ConnectionID, GridMate::CarrierDisconnectReason));
MOCK_METHOD3(OnDriverError, void (GridMate::Carrier*, GridMate::ConnectionID, const GridMate::DriverError&));
MOCK_METHOD3(OnSecurityError, void (GridMate::Carrier*, GridMate::ConnectionID, const GridMate::SecurityError&));
MOCK_METHOD1(Destroy, bool (GridMate::Replica*));
MOCK_METHOD2(GetReplicaContext, void (const GridMate::Replica*, GridMate::ReplicaContext&));
MOCK_METHOD2(OnConnectionEstablished, void (GridMate::Carrier*, GridMate::ConnectionID));
MOCK_METHOD3(OnDisconnect, void (GridMate::Carrier*, GridMate::ConnectionID, GridMate::CarrierDisconnectReason));
MOCK_METHOD3(OnRateChange, void (GridMate::Carrier*, GridMate::ConnectionID, AZ::u32));
MOCK_METHOD1(FindReplica, GridMate::ReplicaPtr (GridMate::ReplicaId));
};
class MockAssetHandler
: public AZ::Data::AssetHandler
{
public:
AZ_CLASS_ALLOCATOR(MockAssetHandler, AZ::SystemAllocator, 0)
MOCK_METHOD2(CreateAsset, AZ::Data::AssetPtr (const AZ::Data::AssetId&, const AZ::Data::AssetType&));
MOCK_METHOD3(LoadAssetData, AZ::Data::AssetHandler::LoadResult (
const AZ::Data::Asset<AZ::Data::AssetData>&,
AZStd::shared_ptr<AZ::Data::AssetDataStream>,
const AZ::Data::AssetFilterCB&));
MOCK_METHOD2(SaveAssetData, bool (const AZ::Data::Asset<AZ::Data::AssetData>&, AZ::IO::GenericStream*));
MOCK_METHOD3(InitAsset, void (const AZ::Data::Asset<AZ::Data::AssetData>&, bool, bool));
MOCK_METHOD1(DestroyAsset, void (AZ::Data::AssetPtr));
MOCK_METHOD1(GetHandledAssetTypes, void (AZStd::vector<AZ::Data::AssetType>&));
MOCK_CONST_METHOD1(CanHandleAsset, bool (const AZ::Data::AssetId&));
};
class MockAsset
: public AZ::DynamicSliceAsset
{
public:
AZ_RTTI(MockAsset, "{78ABC204-452E-4621-A552-F04D3ABF1690}", DynamicSliceAsset);
MockAsset(const AZ::Data::AssetId& assetId = AZ::Data::AssetId())
: DynamicSliceAsset(assetId)
{
}
~MockAsset() = default;
};
class MockSliceReference
: public AZ::SliceComponent::SliceReference
{
public:
using SliceReference::SliceReference;
MOCK_METHOD1(CreateInstance, AZ::SliceComponent::SliceInstance*(const AZ::IdUtils::Remapper<AZ::EntityId>::IdMapper&));
MOCK_METHOD2(CloneInstance, AZ::SliceComponent::SliceInstance*(AZ::SliceComponent::SliceInstance*, AZ::SliceComponent::EntityIdToEntityIdMap&));
MOCK_METHOD1(FindInstance, AZ::SliceComponent::SliceInstance*(const AZ::SliceComponent::SliceInstanceId&));
MOCK_METHOD1(RemoveInstance, bool(AZ::SliceComponent::SliceInstance*));
MOCK_METHOD3(RemoveEntity, bool(AZ::EntityId, bool, AZ::SliceComponent::SliceInstance*));
MOCK_CONST_METHOD0(GetInstances, const AZ::SliceComponent::SliceReference::SliceInstances&());
MOCK_CONST_METHOD0(GetSliceAsset, const AZ::Data::Asset<AZ::SliceAsset>& ());
MOCK_CONST_METHOD0(GetSliceComponent, AZ::SliceComponent*());
MOCK_CONST_METHOD0(IsInstantiated, bool ());
MOCK_CONST_METHOD3(GetInstanceEntityAncestry, bool(const AZ::EntityId&, AZ::SliceComponent::EntityAncestorList&, AZ::u32));
MOCK_METHOD0(ComputeDataPatch, void());
};
class MockSliceInstance
: public AZ::SliceComponent::SliceInstance
{
public:
using SliceInstance::SliceInstance;
void SetMockInstantiatedContainer(AZ::SliceComponent::InstantiatedContainer* newContainer)
{
m_instantiated = newContainer;
for (AZ::Entity* entity : m_instantiated->m_entities)
{
m_entityIdToBaseCache.insert(AZStd::make_pair(entity->GetId(), entity->GetId()));
}
for (AZ::Entity* entity : m_instantiated->m_entities)
{
m_baseToNewEntityIdMap.insert(AZStd::make_pair(entity->GetId(), entity->GetId()));
}
}
MOCK_CONST_METHOD0(GetInstantiated, const AZ::SliceComponent::InstantiatedContainer*());
MOCK_CONST_METHOD0(GetDataPatch, const AZ::DataPatch&());
MOCK_CONST_METHOD0(GetDataFlags, const AZ::SliceComponent::DataFlagsPerEntity&());
MOCK_METHOD0(GetDataFlags, AZ::SliceComponent::DataFlagsPerEntity&());
MOCK_CONST_METHOD0(GetEntityIdMap, const AZ::SliceComponent::EntityIdToEntityIdMap& ());
MOCK_CONST_METHOD0(GetEntityIdToBaseMap, const AZ::SliceComponent::EntityIdToEntityIdMap& ());
MOCK_CONST_METHOD0(GetId, const AZ::SliceComponent::SliceInstanceId& ());
MOCK_CONST_METHOD0(GetMetadataEntity, AZ::Entity* ());
};
class MockEntity
: public AZ::Entity
{
public:
~MockEntity() override {}
MOCK_METHOD0(Init, void ());
MOCK_METHOD0(Activate, void ());
MOCK_METHOD0(Deactivate, void ());
/**
* \brief Helper method for GoogleMock to call base class method
*/
void Base_Init()
{
Entity::Init();
}
/**
* \brief Helper method for GoogleMock to mark an entity as activated
*/
void Base_Activate()
{
m_state = State::Active;
}
/**
* \brief Helper method for GoogleMock to mark an entity as deactivated
*/
void Base_Deactivate()
{
m_state = State::Init;
}
};
class MockComponentApplication
: public AZ::ComponentApplicationBus::Handler
{
public:
MockComponentApplication()
{
AZ::ComponentApplicationBus::Handler::BusConnect();
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
}
~MockComponentApplication()
{
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
AZ::ComponentApplicationBus::Handler::BusDisconnect();
}
AZStd::vector<AZ::Entity*> m_mockEntities;
bool AddEntity(AZ::Entity* entity) override
{
const auto it = AZStd::find(m_mockEntities.begin(), m_mockEntities.end(), entity);
if (it == m_mockEntities.end())
{
m_mockEntities.push_back(entity);
return true;
}
return false;
}
AZ::Entity* FindEntity(const AZ::EntityId& id) override
{
const auto it = AZStd::find_if(m_mockEntities.begin(), m_mockEntities.end(), [id](AZ::Entity* entity)
{
return entity->GetId() == id;
});
if (it != m_mockEntities.end())
{
return *it;
}
return nullptr;
}
MOCK_METHOD0(Destroy, void ());
MOCK_METHOD1(RegisterComponentDescriptor, void (const AZ::ComponentDescriptor*));
MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*));
MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&));
MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&));
MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*));
MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&));
MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&));
MOCK_METHOD1(EnumerateEntities, void (const ComponentApplicationRequests::EntityCallback&));
MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ());
MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ());
MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
MOCK_CONST_METHOD0(GetAppRoot, const char* ());
MOCK_CONST_METHOD0(GetEngineRoot, const char* ());
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
MOCK_METHOD0(GetTickDeltaTime, float ());
MOCK_METHOD0(GetTimeAtCurrentTick, AZ::ScriptTimePoint ());
MOCK_METHOD1(Tick, void (float));
MOCK_METHOD0(TickSystem, void ());
MOCK_CONST_METHOD0(GetRequiredSystemComponents, AZ::ComponentTypeList ());
MOCK_METHOD1(ResolveModulePath, void (AZ::OSString&));
MOCK_METHOD0(RegisterCoreComponents, void ());
MOCK_METHOD1(Reflect, void (AZ::ReflectContext*));
MOCK_CONST_METHOD1(QueryApplicationType, void(AZ::ApplicationTypeQuery&));
};
class MockBindingComponent
: public AZ::Component
, public AzFramework::NetBindingHandlerBus::Handler
{
public:
AZ_COMPONENT(MockBindingComponent, "{8393809A-3256-4865-97A9-1CCA43073B4A}", NetBindingHandlerInterface);
static void Reflect(AZ::ReflectContext*) {}
MOCK_METHOD0(Init, void ());
MOCK_METHOD0(Activate, void ());
MOCK_METHOD0(Deactivate, void ());
MOCK_METHOD1(ReadInConfig, bool (const AZ::ComponentConfig*));
MOCK_CONST_METHOD1(WriteOutConfig, bool (AZ::ComponentConfig*));
MOCK_METHOD1(BindToNetwork, void (GridMate::ReplicaPtr));
MOCK_METHOD0(UnbindFromNetwork, void ());
MOCK_METHOD0(IsEntityBoundToNetwork, bool ());
MOCK_METHOD0(IsEntityAuthoritative, bool ());
MOCK_METHOD0(MarkAsLevelSliceEntity, void ());
MOCK_METHOD1(SetSliceInstanceId, void (const AZ::SliceComponent::SliceInstanceId&));
MOCK_METHOD1(SetReplicaPriority, void (GridMate::ReplicaPriority));
MOCK_METHOD1(RequestEntityChangeOwnership, void (GridMate::PeerId));
MOCK_CONST_METHOD0(GetReplicaPriority, GridMate::ReplicaPriority ());
};
}
#endif // AZCORE_UNITTEST_NETBINDINGMOCKS_H
@@ -1,605 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Component/ComponentApplication.h>
#include <AzFramework/Network/NetBindingSystemImpl.h>
#include <AzFramework/Network/NetBindable.h>
#include <AzFramework/Network/NetBindingSystemComponent.h>
#include <AzCore/Asset/AssetManagerComponent.h>
#include <AzCore/Memory/AllocationRecords.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <GridMate/Serialize/CompressionMarshal.h>
#include <GridMate/Replica/ReplicaFunctions.h>
#include <AzCore/Asset/AssetManager.h>
#include "NetBindingMocks.h"
#include <gmock/gmock-matchers.h>
#include <gmock/gmock-more-actions.h>
#include <gmock/gmock-spec-builders.h>
#include <AzCore/Slice/SliceComponent.h>
namespace UnitTest
{
using namespace AZ;
using namespace AzFramework;
using namespace GridMate;
class NetBindingWithSlicesTest
: public ScopedAllocatorSetupFixture
{
public:
const NetBindingContextSequence k_fakeContextSeq = 1;
const AZ::SliceComponent::SliceInstanceId k_fakeSliceInstanceId = Uuid::CreateRandom();
const AZ::SliceComponent::SliceInstanceId k_fakeSliceInstanceId_Another = Uuid::CreateRandom();
SliceInstantiationTicket m_sliceTicket = SliceInstantiationTicket(EntityContextId::CreateName("Test"), 1);
const Data::AssetId k_fakeAssetId = Data::AssetId(Uuid::CreateRandom(), 0);
const EntityId k_fakeEntityId_One = EntityId(9001);
const ReplicaId k_repId_One = 1001;
const EntityId k_fakeEntityId_Two = EntityId(9002);
const ReplicaId k_repId_Two = 1002;
AZStd::unique_ptr<NetBindingSystemImpl> m_netBindingImpl;
AZStd::unique_ptr<MockComponentApplication> m_componentApplication;
AZStd::unique_ptr<SerializeContext> m_applicationContext;
AZStd::unique_ptr<MockGameEntityContext> m_gameEntityMock;
AZStd::unique_ptr<MockReplicaManager> m_replicaManagerMock;
ReplicaPtr m_replicaMock;
ComponentDescriptor* m_netBindingSystemComponentDescriptor = nullptr;
AZStd::intrusive_ptr<MockNetBindingSystemContextData> m_contextChunkMock;
MockAssetHandler* m_myAssetHandlerAndCatalog = nullptr; // owned by AssetManager
AZStd::unique_ptr<MockAsset> m_fakeAsset;
const float k_wayOverSliceTimeout = NetBindingSystemImpl::s_sliceBindingTimeout.count() * 2.f;
const float k_smallStep = 0.1f;
void SetUpFakeAssetManager()
{
using namespace testing;
const Data::AssetManager::Descriptor desc;
Data::AssetManager::Create(desc);
m_myAssetHandlerAndCatalog = aznew NiceMock<MockAssetHandler>;
ON_CALL(*m_myAssetHandlerAndCatalog, CreateAsset(_, _))
.WillByDefault(Invoke([this](const Data::AssetId&, const Data::AssetType&) -> Data::AssetPtr
{
m_fakeAsset = AZStd::make_unique<NiceMock<MockAsset>>(k_fakeAssetId);
return m_fakeAsset.get();
}));
ON_CALL(*m_myAssetHandlerAndCatalog, DestroyAsset(_))
.WillByDefault(Invoke([this](const Data::AssetPtr asset)
{
EXPECT_EQ(asset, m_fakeAsset.get());
m_fakeAsset.reset();
}));
Data::AssetManager::Instance().RegisterHandler(m_myAssetHandlerAndCatalog, AzTypeInfo<DynamicSliceAsset>::Uuid());
Data::AssetManager::Instance().RegisterHandler(m_myAssetHandlerAndCatalog, AzTypeInfo<MockAsset>::Uuid());
}
void SetUp() override
{
using namespace testing;
m_applicationContext.reset(aznew SerializeContext());
AllocatorInstance<GridMateAllocatorMP>::Create();
AllocatorInstance<ThreadPoolAllocator>::Create();
DefaultValue<SliceInstantiationTicket>::Set(m_sliceTicket);
m_gameEntityMock = AZStd::make_unique<NiceMock<MockGameEntityContext>>();
m_componentApplication = AZStd::make_unique<NiceMock<MockComponentApplication>>();
ON_CALL(*m_componentApplication, GetSerializeContext())
.WillByDefault(Invoke([this]()
{
return m_applicationContext.get();
}));
ON_CALL(*m_gameEntityMock, GetGameEntityContextId())
.WillByDefault(Return(EntityContextId::CreateRandom()));
m_netBindingSystemComponentDescriptor = NetBindingSystemComponent::CreateDescriptor();
ReplicaChunkDescriptorTable::Get().RegisterChunkType<MockNetBindingSystemContextData>();
m_contextChunkMock.reset(CreateReplicaChunk<NiceMock<MockNetBindingSystemContextData>>());
ON_CALL(*m_contextChunkMock, ShouldBindToNetwork())
.WillByDefault(Return(true));
m_replicaManagerMock = AZStd::make_unique<NiceMock<MockReplicaManager>>();
ON_CALL(*m_contextChunkMock, GetReplicaManager())
.WillByDefault(Invoke([this]()
{
return m_replicaManagerMock.get();
}));
m_replicaMock = Replica::CreateReplica("unittest");
ON_CALL(*m_replicaManagerMock, FindReplica(_))
.WillByDefault(Invoke([this](ReplicaId id) -> ReplicaPtr
{
AZ_UNUSED(id);
return m_replicaMock;
}));
ON_CALL(*m_contextChunkMock, OnReplicaActivate(_))
.WillByDefault(Invoke(m_contextChunkMock.get(), &MockNetBindingSystemContextData::Base_OnReplicaActivate));
m_netBindingImpl = AZStd::make_unique<AzFramework::NetBindingSystemImpl>();
m_netBindingImpl->Init();
m_contextChunkMock->OnReplicaActivate(ReplicaContext(nullptr, TimeContext()));
SetUpFakeAssetManager();
}
void TearDown() override
{
Data::AssetManager::Destroy();
m_replicaMock.reset();
m_replicaManagerMock.reset();
m_contextChunkMock.reset();
m_fakeAsset.reset();
m_netBindingImpl->Shutdown();
m_netBindingImpl.reset();
ReplicaChunkDescriptorTable::Get().UnregisterReplicaChunkDescriptor(ReplicaChunkClassId(MockNetBindingSystemContextData::GetChunkName()));
m_netBindingSystemComponentDescriptor->ReleaseDescriptor();
m_componentApplication.reset();
m_gameEntityMock.reset();
AllocatorInstance<GridMateAllocatorMP>::Destroy();
AllocatorInstance<ThreadPoolAllocator>::Destroy();
m_applicationContext.reset();
}
};
TEST_F(NetBindingWithSlicesTest, SameSliceInstanceId_InstantiateDynamicSlice_CallOnce)
{
using namespace testing;
EXPECT_CALL(*m_gameEntityMock, InstantiateDynamicSlice(_, _, _))
.Times(1);
EXPECT_CALL(*m_gameEntityMock, CancelDynamicSliceInstantiation(_))
.Times(1);
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
}
// this should kick off NetBindingSystemImpl::ProcessBindRequests
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
}
TEST_F(NetBindingWithSlicesTest, DifferentSliceInstanceId_InstantiateDynamicSlice_CalledTwice)
{
using namespace testing;
EXPECT_CALL(*m_gameEntityMock, InstantiateDynamicSlice(_, _, _))
.Times(2);
EXPECT_CALL(*m_gameEntityMock, CancelDynamicSliceInstantiation(_))
.Times(2);
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId_Another; // different slice entity
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
}
// this should kick off NetBindingSystemImpl::ProcessBindRequests
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
}
TEST_F(NetBindingWithSlicesTest, AssetManagerDestroyed_InstantiateDynamicSlice_NotCalled)
{
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
Data::AssetManager::Destroy();
// this should kick off NetBindingSystemImpl::ProcessBindRequests, but InstantiateDynamicSlice will not be called
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
}
class ExtendedBindingWithSlicesTest
: public NetBindingWithSlicesTest
{
public:
void SetUp() override
{
NetBindingWithSlicesTest::SetUp();
}
void TearDown() override
{
using namespace testing;
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_One))
.Times(AtMost(1));
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
.Times(AtMost(1));
NetBindingWithSlicesTest::TearDown();
}
class InstantiateMockSlice
{
public:
explicit InstantiateMockSlice(ExtendedBindingWithSlicesTest* parent)
{
using namespace testing;
m_mockSliceRef = AZStd::make_unique<MockSliceReference>();
m_mockSliceInstance = AZStd::make_unique<MockSliceInstance>();
// container owns the entities and will delete them
auto mockContainer = AZStd::make_unique<SliceComponent::InstantiatedContainer>();
auto binding1 = AZStd::make_unique<NiceMock<MockBindingComponent>>();
mockContainer->m_entities.push_back(CreateMockEntity(parent->k_fakeEntityId_One, binding1.release()));
auto binding2 = AZStd::make_unique<NiceMock<MockBindingComponent>>();
mockContainer->m_entities.push_back(CreateMockEntity(parent->k_fakeEntityId_Two, binding2.release()));
m_mockSliceInstance->SetMockInstantiatedContainer(mockContainer.release());
SliceComponent::SliceInstanceAddress sliceInstanceAddress(m_mockSliceRef.get(), m_mockSliceInstance.get());
// This will pass our mock slice to NetBindingSystem
EBUS_EVENT_ID(parent->m_sliceTicket, SliceInstantiationResultBus, OnSlicePreInstantiate, parent->k_fakeAssetId, sliceInstanceAddress);
EBUS_EVENT_ID(parent->m_sliceTicket, SliceInstantiationResultBus, OnSliceInstantiated, parent->k_fakeAssetId, sliceInstanceAddress);
}
Entity* CreateMockEntity(const EntityId& id, Component* optional = nullptr)
{
using namespace testing;
auto mock = AZStd::make_unique<NiceMock<MockEntity>>();
mock->SetId(EntityId(id));
if (optional)
{
mock->AddComponent(optional); // entity owns the component
}
ON_CALL(*mock, Init())
.WillByDefault(Invoke(mock.get(), &MockEntity::Base_Init));
mock->Init();
ON_CALL(*mock, Activate())
.WillByDefault(Invoke(mock.get(), &MockEntity::Base_Activate));
ON_CALL(*mock, Deactivate())
.WillByDefault(Invoke(mock.get(), &MockEntity::Base_Deactivate));
return mock.release();
}
AZStd::unique_ptr<MockSliceReference> m_mockSliceRef;
AZStd::unique_ptr<MockSliceInstance> m_mockSliceInstance;
};
AZStd::unique_ptr<InstantiateMockSlice> m_slice;
void CreateMockSlice()
{
m_slice = AZStd::make_unique<InstantiateMockSlice>(this);
}
};
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_EntitiesThatWerentBounded_StayDeactivated)
{
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
CreateMockSlice();
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
EXPECT_CALL(*mock1, Activate()).
Times(1);
MockEntity* mock2 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_Two));
EXPECT_CALL(*mock2, Activate()).
Times(0);
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
.Times(0);
// Now it should time out the slice handler and the second entity should remain deactivated since we didn't give binding request for it
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
}
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_SpawnSecondEntity_AfterLongDelay_InSameSlicenInstance)
{
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
.Times(0);
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
CreateMockSlice();
MockEntity* mock2 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_Two));
EXPECT_CALL(*mock2, Activate()).
Times(0);
// This should not trigger removal of the second entity yet
auto halfTimeoutInSeconds = AZStd::chrono::seconds(NetBindingSystemImpl::s_sliceBindingTimeout).count() * 10.f;
EBUS_EVENT(AZ::TickBus, OnTick, halfTimeoutInSeconds, AZ::ScriptTimePoint());
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
}
EXPECT_CALL(*mock2, Activate()).
Times(1);
// This should give net binding system time to bind the second entity
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
// Let the slice timeout, this should lead to no destruction since both entities ought to have been bound by now
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
}
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_DespawnLastEntity_DespawnWholeSliceAfterTimeout)
{
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
CreateMockSlice();
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
EXPECT_CALL(*mock1, Activate()).
Times(1);
// This should not trigger removal of the second entity yet
auto halfTimeoutInSeconds = AZStd::chrono::seconds(NetBindingSystemImpl::s_sliceBindingTimeout).count() * 10.f;
EBUS_EVENT(AZ::TickBus, OnTick, halfTimeoutInSeconds, AZ::ScriptTimePoint());
EXPECT_CALL(*mock1, Deactivate()).
Times(1);
EBUS_EVENT(NetBindingSystemBus, UnbindGameEntity, k_fakeEntityId_One, k_fakeSliceInstanceId);
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_One))
.Times(1);
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
.Times(1);
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
}
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_DespawnLastEntityBeforeSliceInstantiation_DespawnWholeSlice)
{
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
EBUS_EVENT(NetBindingSystemBus, UnbindGameEntity, k_fakeEntityId_One, k_fakeSliceInstanceId);
CreateMockSlice();
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
EXPECT_CALL(*mock1, Activate()).
Times(0);
auto halfTimeoutInSeconds = AZStd::chrono::seconds(NetBindingSystemImpl::s_sliceBindingTimeout).count() * 10.f;
EBUS_EVENT(AZ::TickBus, OnTick, halfTimeoutInSeconds, AZ::ScriptTimePoint());
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
}
TEST_F(ExtendedBindingWithSlicesTest, ActiveSlice_ReuseEntity)
{
EXPECT_CALL(*m_gameEntityMock, DestroyGameEntity(k_fakeEntityId_Two))
.Times(0);
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
}
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
CreateMockSlice();
MockEntity* mock2 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_Two));
EXPECT_CALL(*mock2, Activate()).
Times(1);
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
EXPECT_CALL(*mock2, Deactivate()).
Times(1);
// some time later the second entity goes away and comes back
EBUS_EVENT(NetBindingSystemBus, UnbindGameEntity, k_fakeEntityId_Two, k_fakeSliceInstanceId);
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_Two;
spawnContext.m_staticEntityId = k_fakeEntityId_Two;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId; // both mock entities come from the same slice
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_Two, spawnContext);
}
// The same entity should be activated for the second time
EXPECT_CALL(*mock2, Activate()).
Times(1); // Note, Google Mock treats each expect_call separately and satisfies them separately. That's why it's 1 here, despite being a second call.
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
}
TEST_F(ExtendedBindingWithSlicesTest, SliceFailedToSpawn)
{
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
EBUS_EVENT_ID(m_sliceTicket, SliceInstantiationResultBus, OnSliceInstantiationFailed, k_fakeAssetId);
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
EXPECT_TRUE(m_componentApplication->FindEntity(k_fakeEntityId_One) == nullptr);
}
TEST_F(ExtendedBindingWithSlicesTest, SliceSpawned_AfterTimeout)
{
{
NetBindingSliceContext spawnContext;
spawnContext.m_contextSequence = k_fakeContextSeq;
spawnContext.m_sliceAssetId = k_fakeAssetId;
spawnContext.m_runtimeEntityId = k_fakeEntityId_One;
spawnContext.m_staticEntityId = k_fakeEntityId_One;
spawnContext.m_sliceInstanceId = k_fakeSliceInstanceId;
EBUS_EVENT(NetBindingSystemBus, SpawnEntityFromSlice, k_repId_One, spawnContext);
}
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
EBUS_EVENT(AZ::TickBus, OnTick, k_wayOverSliceTimeout, AZ::ScriptTimePoint());
CreateMockSlice();
MockEntity* mock1 = static_cast<MockEntity*>(m_componentApplication->FindEntity(k_fakeEntityId_One));
EXPECT_CALL(*mock1, Activate()).
Times(1);
EBUS_EVENT(AZ::TickBus, OnTick, k_smallStep, AZ::ScriptTimePoint());
}
}
-801
View File
@@ -1,801 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzFramework/Network/NetworkContext.h>
#include <AzFramework/Application/Application.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/Memory/MemoryComponent.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <GridMate/Replica/ReplicaChunk.h>
#include <GridMate/Replica/DataSet.h>
#include <GridMate/Replica/RemoteProcedureCall.h>
#include <GridMate/Serialize/DataMarshal.h>
#include <GridMate/Serialize/UtilityMarshal.h>
#include <GridMate/Serialize/ContainerMarshal.h>
#include <GridMate/Replica/ReplicaMgr.h>
#include <AzFramework/Network/InterestManagerComponent.h>
namespace UnitTest
{
using namespace AZ;
using namespace AzFramework;
class TestComponentExternalChunk
: public AZ::Component
, public NetBindable
{
public:
AZ_COMPONENT(TestComponentExternalChunk, "{73BB3B15-7C4D-4BD5-9568-F3B2DCBC7725}", AZ::Component);
static void Reflect(ReflectContext* context);
void Init() override
{
NetBindable::NetInit();
}
void Activate() override {}
void Deactivate() override {}
bool SetPos(float x, float y, const RpcContext&)
{
m_x = x;
m_y = y;
return true;
}
void OnFloatChanged(const float&, const TimeContext&)
{
m_floatChanged = true;
}
bool m_floatChanged = false;
private:
float m_x = 0, m_y = 0;
};
class TestComponentReplicaChunk
: public ReplicaChunkBase
, public ReplicaChunkInterface
{
public:
GM_CLASS_ALLOCATOR(TestComponentReplicaChunk);
static const char* GetChunkName() { return "TestComponentReplicaChunk"; }
bool IsReplicaMigratable() override { return true; }
public:
TestComponentReplicaChunk()
: m_int("m_int", 42)
, m_float("m_float", 96.4f)
, SetInt("SetInt")
, SetPos("SetPos")
{
}
bool SetIntImpl(int newValue, const RpcContext&)
{
m_int.Set(newValue);
return true;
}
DataSet<int> m_int;
DataSet<float>::BindInterface<TestComponentExternalChunk, &TestComponentExternalChunk::OnFloatChanged> m_float;
GridMate::Rpc<GridMate::RpcArg<int, Marshaler<int> > >::BindInterface<TestComponentReplicaChunk, &TestComponentReplicaChunk::SetIntImpl> SetInt;
GridMate::Rpc<GridMate::RpcArg<float>, GridMate::RpcArg<float> >::BindInterface<TestComponentExternalChunk, &TestComponentExternalChunk::SetPos> SetPos;
};
void TestComponentExternalChunk::Reflect(ReflectContext* context)
{
NetworkContext* netContext = azrtti_cast<NetworkContext*>(context);
if (netContext)
{
netContext->Class<TestComponentExternalChunk>()
->Chunk<TestComponentReplicaChunk>()
->Field("m_int", &TestComponentReplicaChunk::m_int)
->Field("m_float", &TestComponentReplicaChunk::m_float)
->RPC("SetInt", &TestComponentReplicaChunk::SetInt)
->RPC("SetPos", &TestComponentReplicaChunk::SetPos);
}
}
class TestComponentAutoChunk
: public AZ::Component
, public NetBindable
{
public:
enum TestEnum
{
TEST_Value0 = 0,
TEST_Value1 = 1,
TEST_Value255 = 255
};
AZ_COMPONENT(TestComponentAutoChunk, "{003FD1BC-8456-43D5-9879-1B3804327A4F}", AZ::Component);
static void Reflect(ReflectContext* context)
{
NetworkContext* netContext = azrtti_cast<NetworkContext*>(context);
if (netContext)
{
netContext->Class<TestComponentAutoChunk>()
->Field("m_int", &TestComponentAutoChunk::m_int)
->Field("m_float", &TestComponentAutoChunk::m_float)
->Field("m_enum", &TestComponentAutoChunk::m_enum)
->RPC("SetInt", &TestComponentAutoChunk::SetInt)
->CtorData("CtorInt", &TestComponentAutoChunk::GetCtorInt, &TestComponentAutoChunk::SetCtorInt)
->CtorData("CtorVec", &TestComponentAutoChunk::GetCtorVec, &TestComponentAutoChunk::SetCtorVec);
}
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<TestComponentAutoChunk, AZ::Component>()
->Version(1)
->Field("m_int", &TestComponentAutoChunk::m_int)
->Field("m_float", &TestComponentAutoChunk::m_float)
->Field("m_enum", &TestComponentAutoChunk::m_enum)
->Field("ctorInt", &TestComponentAutoChunk::m_ctorInt)
->Field("ctorVec", &TestComponentAutoChunk::m_ctorVec);
}
}
void Init() override
{
NetBindable::NetInit();
}
void Activate() override {}
void Deactivate() override {}
void SetNetworkBinding(ReplicaChunkPtr chunk) override {}
void UnbindFromNetwork() override {}
bool SetIntImpl(int val, const RpcContext&)
{
m_int = val;
return true;
}
void OnFloatChanged(const float&, const TimeContext&)
{
}
int GetCtorInt() const { return m_ctorInt; }
void SetCtorInt(const int& ctorInt) { m_ctorInt = ctorInt; }
AZStd::vector<int>& GetCtorVec() { return m_ctorVec; }
void SetCtorVec(const AZStd::vector<int>& vec) { m_ctorVec = vec; }
int m_ctorInt;
AZStd::vector<int> m_ctorVec;
Field<int> m_int;
BoundField<float, TestComponentAutoChunk, &TestComponentAutoChunk::OnFloatChanged> m_float;
Field<TestEnum, GridMate::ConversionMarshaler<AZ::u8, TestEnum> > m_enum;
Rpc<int>::Binder<TestComponentAutoChunk, &TestComponentAutoChunk::SetIntImpl> SetInt;
};
class NetContextReflectionTest
: public AllocatorsTestFixture
{
public:
void SetUp() override
{
AllocatorsTestFixture::SetUp();
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create();
}
void TearDown() override
{
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
AllocatorsTestFixture::TearDown();
}
void run()
{
AzFramework::Application app;
AzFramework::Application::Descriptor appDesc;
appDesc.m_recordingMode = Debug::AllocationRecords::RECORD_NO_RECORDS;
appDesc.m_allocationRecords = false;
appDesc.m_enableDrilling = false;
app.Start(appDesc);
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
AzFramework::NetworkContext* netContext = nullptr;
EBUS_EVENT_RESULT(netContext, NetSystemRequestBus, GetNetworkContext);
AZ_TEST_ASSERT(netContext);
AZ::ComponentDescriptor* descTestComponentExternalChunk = TestComponentExternalChunk::CreateDescriptor();
app.RegisterComponentDescriptor(descTestComponentExternalChunk);
AZ::ComponentDescriptor* descTestComponentAutoChunk = TestComponentAutoChunk::CreateDescriptor();
app.RegisterComponentDescriptor(descTestComponentAutoChunk);
AZ::Entity* testEntity = aznew AZ::Entity("TestEntity");
testEntity->Init();
testEntity->CreateComponent<TestComponentAutoChunk>();
testEntity->CreateComponent<TestComponentExternalChunk>();
testEntity->Activate();
// test field binding/auto reflection/creation
{
TestComponentAutoChunk* testComponent = testEntity->FindComponent<TestComponentAutoChunk>();
AZ_TEST_ASSERT(testComponent);
testComponent->SetInt(2048); // should happen locally
AZ_TEST_ASSERT(testComponent->m_int == 2048);
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
AZ_TEST_ASSERT(chunk);
GridMate::ReplicaChunkDescriptor* desc = chunk->GetDescriptor();
AZ_TEST_ASSERT(desc);
testComponent->m_ctorInt = 8192;
for (int n = 0; n < 16; ++n)
{
testComponent->m_ctorVec.push_back(n);
}
GridMate::WriteBufferDynamic wb(GridMate::EndianType::IgnoreEndian);
desc->MarshalCtorData(chunk.get(), wb);
{
// Create a chunk from the recorded ctor data, ensure that it stores
// the ctor data in preparation for copying it to the instance
GridMate::TimeContext tc;
GridMate::ReplicaContext rc(nullptr, tc);
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
GridMate::UnmarshalContext ctx(rc);
ctx.m_hasCtorData = true;
ctx.m_iBuf = &rb;
ReplicaChunkPtr chunk2 = desc->CreateFromStream(ctx);
AZ_TEST_ASSERT(chunk2); // ensure a new chunk was created
ReflectedReplicaChunkBase* refChunk = static_cast<ReflectedReplicaChunkBase*>(chunk2.get());
AZ_TEST_ASSERT(refChunk->m_ctorBuffer.Size() == sizeof(int) + sizeof(AZ::u16) + (sizeof(int) * testComponent->m_ctorVec.size()));
}
{
// discard a ctor data stream and ensure that the stream is emptied
GridMate::TimeContext tc;
GridMate::ReplicaContext rc(nullptr, tc);
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
GridMate::UnmarshalContext ctx(rc);
ctx.m_hasCtorData = true;
ctx.m_iBuf = &rb;
desc->DiscardCtorStream(ctx);
AZ_TEST_ASSERT(rb.IsEmptyIgnoreTrailingBits()); // should have discarded the whole stream
}
{
// Make another chunk and bind it to a new component and make sure the ctor data matches
AZ::Entity* testEntity2 = aznew AZ::Entity("TestEntity2");
testEntity2->Init();
testEntity2->CreateComponent<TestComponentAutoChunk>();
testEntity2->Activate();
GridMate::TimeContext tc;
GridMate::ReplicaContext rc(nullptr, tc);
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
GridMate::UnmarshalContext ctx(rc);
ctx.m_hasCtorData = true;
ctx.m_iBuf = &rb;
ReplicaChunkPtr chunk2 = desc->CreateFromStream(ctx);
TestComponentAutoChunk* testComponent2 = testEntity2->FindComponent<TestComponentAutoChunk>();
netContext->Bind(testComponent2, chunk2, NetworkContextBindMode::NonAuthoritative);
// Ensure values match after ctor data is applied
AZ_TEST_ASSERT(testComponent2->m_ctorInt == testComponent->m_ctorInt);
AZ_TEST_ASSERT(testComponent2->m_ctorVec == testComponent->m_ctorVec);
}
testComponent->SetInt(4096);
AZ_TEST_ASSERT(testComponent->m_int == 4096);
testComponent->m_int = 42; // now it should change
AZ_TEST_ASSERT(testComponent->m_int == 42);
testComponent->m_enum = TestComponentAutoChunk::TEST_Value1;
chunk.reset(); // should cause netContext->DestroyReplicaChunk()
}
// test chunk binding/creation
{
TestComponentExternalChunk* testComponent = testEntity->FindComponent<TestComponentExternalChunk>();
AZ_TEST_ASSERT(testComponent);
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
AZ_TEST_ASSERT(chunk);
TestComponentReplicaChunk* testChunk = static_cast<TestComponentReplicaChunk*>(chunk.get());
// for now, this will throw a warning, but will at least attempt the dispatch
testChunk->SetPos(42.0f, 96.0f);
AZ_TEST_ASSERT(testComponent->m_floatChanged == false);
testChunk->m_float.Set(1024.0f);
// I would like to test that the notify fired, but without a Replica, cant :(
testComponent->UnbindFromNetwork();
chunk.reset(); ///// CRASHES FROM HERE
}
// test serialization of NetBindable::Fields
{
TestComponentAutoChunk* testComponent = testEntity->FindComponent<TestComponentAutoChunk>();
AZStd::vector<AZ::u8> buffer;
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > saveStream(&buffer);
bool saved = AZ::Utils::SaveObjectToStream(saveStream, AZ::DataStream::ST_XML, testComponent);
AZ_TEST_ASSERT(saved);
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > loadStream(&buffer);
TestComponentAutoChunk* testCopy = AZ::Utils::LoadObjectFromStream<TestComponentAutoChunk>(loadStream);
AZ_TEST_ASSERT(testCopy);
delete testCopy;
}
testEntity->Deactivate();
delete testEntity;
descTestComponentExternalChunk->ReleaseDescriptor();
descTestComponentAutoChunk->ReleaseDescriptor();
app.Stop();
}
};
TEST_F(NetContextReflectionTest, Test)
{
run();
}
template <typename ComponentType>
class NetContextFixture
: public ::testing::Test
{
public:
NetContextFixture() = default;
~NetContextFixture() = default;
void SetUp() override
{
AZ::AllocatorInstance<SystemAllocator>::Create();
m_app = AZStd::make_unique<AzFramework::Application>();
m_app->Start(AzFramework::Application::Descriptor());
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
AzFramework::NetworkContext* netContext = nullptr;
EBUS_EVENT_RESULT(netContext, NetSystemRequestBus, GetNetworkContext);
AZ_TEST_ASSERT(netContext);
m_descTestComponentAutoChunk = ComponentType::CreateDescriptor();
m_app->RegisterComponentDescriptor(m_descTestComponentAutoChunk);
m_entity = AZStd::make_unique<AZ::Entity>("TestEntity");
m_entity->Init();
m_entity->CreateComponent<ComponentType>();
m_entity->Activate();
}
void TearDown() override
{
m_descTestComponentAutoChunk->ReleaseDescriptor();
m_entity->Deactivate();
m_entity.reset();
m_app->Stop();
m_app.reset();
AZ::AllocatorInstance<SystemAllocator>::Destroy();
}
void RunTest()
{
const ComponentType* testComponent = m_entity->FindComponent<ComponentType>();
AZStd::vector<AZ::u8> buffer;
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > saveStream(&buffer);
const bool saved = AZ::Utils::SaveObjectToStream(saveStream, AZ::DataStream::ST_XML, testComponent);
AZ_TEST_ASSERT(saved);
AZ::IO::ByteContainerStream<AZStd::vector<AZ::u8> > loadStream(&buffer);
const AZStd::unique_ptr<ComponentType> testCopy(AZ::Utils::LoadObjectFromStream<ComponentType>(loadStream));
AZ_TEST_ASSERT(testCopy);
}
AZStd::unique_ptr<AzFramework::Application> m_app;
AZStd::unique_ptr<AZ::Entity> m_entity;
AZ::ComponentDescriptor* m_descTestComponentAutoChunk = nullptr;
};
class TestComponent_EmptyNetContext
: public AZ::Component
, public NetBindable
{
public:
AZ_COMPONENT(TestComponent_EmptyNetContext, "{B1E2E2DD-DA70-4D59-A185-AF9A5CCF1574}", AZ::Component, NetBindable);
static void Reflect(ReflectContext* context)
{
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<TestComponent_EmptyNetContext, AZ::Component>()
->Version(1);
}
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
{
netContext->Class<TestComponent_EmptyNetContext>();
}
}
void Activate() override {}
void Deactivate() override {}
};
using NetContextEmpty = NetContextFixture<TestComponent_EmptyNetContext>;
TEST_F(NetContextEmpty, SerializationTests)
{
RunTest();
}
template<typename FieldType>
class TestComponent_OneField
: public AZ::Component
, public NetBindable
{
public:
AZ_COMPONENT(TestComponent_OneField, "{A7BCDBEF-3D4F-4D04-A6FA-DF48D4B66ABE}", AZ::Component, NetBindable);
using ThisComponentType = TestComponent_OneField<FieldType>;
static void Reflect(ReflectContext* context)
{
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<TestComponent_OneField, AZ::Component>()
->Field("Field", &TestComponent_OneField::m_field)
->Version(1);
}
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
{
netContext->Class<TestComponent_OneField>()
->Field("Field", &TestComponent_OneField::m_field);
}
}
void Activate() override {}
void Deactivate() override {}
Field<FieldType> m_field;
};
TYPED_TEST_CASE_P(NetContextFixture);
TYPED_TEST_P(NetContextFixture, SerializationTests)
{
this->RunTest();
}
REGISTER_TYPED_TEST_CASE_P(NetContextFixture, SerializationTests);
/*
* Testing the basic common types.
*/
using CommonTypes = ::testing::Types<
TestComponent_OneField<bool>,
TestComponent_OneField<float>,
TestComponent_OneField<AZ::u32>,
TestComponent_OneField<AZ::EntityId>,
TestComponent_OneField<AZ::Vector2>,
TestComponent_OneField<AZ::Vector3>,
TestComponent_OneField<AZ::Quaternion>
>;
INSTANTIATE_TYPED_TEST_CASE_P(NetContextCommonSerialization, NetContextFixture, CommonTypes);
/*
* And some less common types.
*/
using LessCommonTypes = ::testing::Types<
TestComponent_OneField<AZStd::string>,
TestComponent_OneField<AZ::Transform>,
TestComponent_OneField<AZ::Color>,
TestComponent_OneField<AZStd::vector<int>>,
TestComponent_OneField<AZ::Uuid>
>;
INSTANTIATE_TYPED_TEST_CASE_P(NetContextLessCommonSerialization, NetContextFixture, LessCommonTypes);
/*
* Next up are marshal and unmarshal tests.
*/
template <typename ComponentType>
class NetContextMarshalFixture
: public UnitTest::AllocatorsTestFixture
{
public:
NetContextMarshalFixture() = default;
~NetContextMarshalFixture() = default;
void SetUp() override
{
UnitTest::AllocatorsTestFixture::SetUp();
AZ::AllocatorInstance<GridMate::GridMateAllocator>::Create();
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Create();
m_app = AZStd::make_unique<AzFramework::Application>();
m_app->Start(AzFramework::Application::Descriptor());
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
// shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
AzFramework::NetworkContext* netContext = nullptr;
EBUS_EVENT_RESULT(netContext, NetSystemRequestBus, GetNetworkContext);
AZ_TEST_ASSERT(netContext);
m_descTestComponentAutoChunk = ComponentType::CreateDescriptor();
m_app->RegisterComponentDescriptor(m_descTestComponentAutoChunk);
m_entityFrom = AZStd::make_unique<AZ::Entity>("TestEntityFrom");
m_entityFrom->Init();
m_componentFrom = m_entityFrom->CreateComponent<ComponentType>();
m_entityFrom->Activate();
m_entityTo = AZStd::make_unique<AZ::Entity>("TestEntityTo");
m_entityTo->Init();
m_componentTo = m_entityTo->CreateComponent<ComponentType>();
m_entityTo->Activate();
}
void MarshalUnMarshal()
{
AzFramework::NetworkContext* netContext = nullptr;
NetSystemRequestBus::BroadcastResult(netContext, &NetSystemRequestBus::Events::GetNetworkContext);
AZ_TEST_ASSERT(netContext);
ComponentType* testComponent = m_entityFrom->FindComponent<ComponentType>();
AZ_TEST_ASSERT(testComponent);
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
AZ_TEST_ASSERT(chunk);
m_outReplica = AZStd::make_unique<GridMate::Replica>("ReplicaTo");
{
m_outManager = AZStd::make_unique<GridMate::ReplicaManager>();
m_outPeer = AZStd::make_unique<GridMate::ReplicaPeer>(m_outManager.get());
GridMate::WriteBufferDynamic wb(GridMate::EndianType::IgnoreEndian);
{
GridMate::TimeContext tc;
const GridMate::ReplicaContext rc(nullptr, tc);
GridMate::MarshalContext mc(GridMate::ReplicaMarshalFlags::FullSync, &wb, nullptr, rc);
mc.m_peer = m_outPeer.get();
mc.m_rm = m_outManager.get();
chunk->Debug_PrepareData(wb.GetEndianType(), GridMate::ReplicaMarshalFlags::FullSync);
chunk->Debug_Marshal(mc, 0);
}
// and now unmarshal into the other entity
{
GridMate::TimeContext tc;
const GridMate::ReplicaContext rc(nullptr, tc);
GridMate::ReadBuffer rb(wb.GetEndianType(), wb.Get(), wb.Size());
GridMate::UnmarshalContext ctx(rc);
ctx.m_hasCtorData = false;
ctx.m_iBuf = &rb;
ctx.m_peer = m_outPeer.get();
ctx.m_rm = m_outManager.get();
m_outReplicaChunk = chunk->GetDescriptor()->CreateFromStream(ctx);
m_outReplicaChunk->Debug_AttachedToReplica(m_outReplica.get());
ctx.m_peer->Debug_Add(m_outReplica.get());
m_outReplicaChunk->Debug_Unmarshal(ctx, 0);
/*
* Note the order: unmarshal first to populate the chunk with data, then apply it to a component.
* The expectation is that the valid will apply to NetBindable::Field without being overwritten.
*/
m_componentTo->SetNetworkBinding(m_outReplicaChunk);
// the main test body can now test for the equality
}
}
}
void TearDown() override
{
m_outReplicaChunk.reset();
m_outManager.reset();
m_outPeer.reset();
m_outReplica.release(); // Replica is held by as an intrusive pointer in @m_outPeer and is destroyed there.
if (m_entityFrom)
{
m_entityFrom->Deactivate();
m_entityFrom.reset();
}
if (m_entityTo)
{
m_entityTo->Deactivate();
m_entityTo.reset();
}
m_descTestComponentAutoChunk->ReleaseDescriptor();
m_app->Stop();
m_app.reset();
AZ::AllocatorInstance<GridMate::GridMateAllocatorMP>::Destroy();
AZ::AllocatorInstance<GridMate::GridMateAllocator>::Destroy();
UnitTest::AllocatorsTestFixture::TearDown();
}
AZStd::unique_ptr<AzFramework::Application> m_app;
AZStd::unique_ptr<AZ::Entity> m_entityFrom;
AZStd::unique_ptr<AZ::Entity> m_entityTo;
ComponentType* m_componentFrom = nullptr;
ComponentType* m_componentTo = nullptr;
AZ::ComponentDescriptor* m_descTestComponentAutoChunk = nullptr;
GridMate::ReplicaChunkPtr m_outReplicaChunk;
AZStd::unique_ptr<GridMate::Replica> m_outReplica;
AZStd::unique_ptr<GridMate::ReplicaManager> m_outManager;
AZStd::unique_ptr<GridMate::ReplicaPeer> m_outPeer;
};
using NetContextVector3 = NetContextMarshalFixture<TestComponent_OneField<AZ::Vector3>>;
TEST_F(NetContextVector3, SerializationTests)
{
const Vector3 value = AZ::Vector3::CreateAxisZ( 1.f );
m_componentFrom->m_field = value;
MarshalUnMarshal();
AZ_TEST_ASSERT(m_componentTo->m_field.Get() == value);
}
/*
* Now the same test but with NetBindable::BoundField<>
*/
template<typename FieldType>
class TestComponent_OneBoundField
: public AZ::Component
, public NetBindable
{
public:
AZ_COMPONENT(TestComponent_OneBoundField, "{2B283821-41DF-46BB-BE8E-66EF7301B62A}", AZ::Component, NetBindable);
using ThisComponentType = TestComponent_OneBoundField<FieldType>;
static void Reflect(ReflectContext* context)
{
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<ThisComponentType, AZ::Component>()
->Field("Field", &ThisComponentType::m_boundField)
->Version(1);
}
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
{
netContext->Class<ThisComponentType>()
->Field("Field", &ThisComponentType::m_boundField);
}
}
void Activate() override {}
void Deactivate() override {}
void OnBoundFieldChanged( const FieldType&, const GridMate::TimeContext& ) {}
BoundField<FieldType, ThisComponentType, &ThisComponentType::OnBoundFieldChanged> m_boundField;
};
using NetContextBoundVector2 = NetContextMarshalFixture<TestComponent_OneBoundField<AZ::Vector2>>;
TEST_F(NetContextBoundVector2, SerializationTests)
{
const Vector2 value = AZ::Vector2::CreateAxisX( 4.f );
m_componentFrom->m_boundField = value;
MarshalUnMarshal();
AZ_TEST_ASSERT(m_componentTo->m_boundField.Get() == value);
}
TEST_F(NetContextBoundVector2, Delete_Authoritative_Entity)
{
using ThisComponentType = TestComponent_OneBoundField<AZ::Vector2>;
AzFramework::NetworkContext* netContext = nullptr;
NetSystemRequestBus::BroadcastResult(netContext, &NetSystemRequestBus::Events::GetNetworkContext);
AZ_TEST_ASSERT(netContext);
ThisComponentType* testComponent = m_entityFrom->FindComponent<ThisComponentType>();
AZ_TEST_ASSERT(testComponent);
ReplicaChunkPtr chunk = testComponent->GetNetworkBinding();
// Testing early deletion of an entity on the server.
m_entityFrom->Deactivate();
m_entityFrom.reset();
// This test passes if it doesn't crash on cleanup.
chunk.reset();
}
template<typename FieldType>
class TestComponent_OneBoundField_ServerCallback
: public AZ::Component
, public NetBindable
{
public:
AZ_COMPONENT(TestComponent_OneBoundField_ServerCallback, "{74F5B232-0544-45CA-B207-9846052ED1AD}", AZ::Component, NetBindable);
using ThisComponentType = TestComponent_OneBoundField_ServerCallback<FieldType>;
static void Reflect(ReflectContext* context)
{
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<ThisComponentType, AZ::Component>()
->Field("Field", &ThisComponentType::m_boundField)
->Version(1);
}
if (NetworkContext* netContext = azrtti_cast<NetworkContext*>(context))
{
netContext->Class<ThisComponentType>()
->Field("Field", &ThisComponentType::m_boundField);
}
}
void Activate() override {}
void Deactivate() override {}
void OnBoundFieldChanged( const FieldType&, const GridMate::TimeContext& )
{
++m_callbacksInvokeCount;
}
AZ::u8 m_callbacksInvokeCount = 0;
BoundField<FieldType, ThisComponentType, &ThisComponentType::OnBoundFieldChanged> m_boundField;
};
using NetContextBoundVector2WithCallbackCount = NetContextMarshalFixture<TestComponent_OneBoundField_ServerCallback<AZ::Vector2>>;
TEST_F(NetContextBoundVector2WithCallbackCount, BoundField_Invoke_OnServer_Test)
{
MarshalUnMarshal();
m_componentFrom->m_callbacksInvokeCount = 0; // resetting the count
const Vector2 value = AZ::Vector2::CreateAxisX( 4.f );
m_componentFrom->m_boundField = value;
AZ_TEST_ASSERT(m_componentFrom->m_callbacksInvokeCount == 1);
}
}
-552
View File
@@ -1,552 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "TestTypes.h"
#include <AzCore/Math/Random.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzFramework/Network/EntityIdMarshaler.h>
#include <AzFramework/Network/DynamicSerializableFieldMarshaler.h>
#include <GridMate/Serialize/Buffer.h>
namespace UnitTest
{
template<class T>
class MarshalerTester
: public AllocatorsFixture
{
public:
MarshalerTester()
: m_writeBuffer(GridMate::EndianType::BigEndian)
, m_readBuffer(GridMate::EndianType::BigEndian)
{
}
void SetUp() override
{
AllocatorsFixture::SetUp();
m_random.SetSeed(AZStd::chrono::milliseconds().count());
}
void PopulateReadBuffer()
{
m_readBuffer = GridMate::ReadBuffer(m_writeBuffer.GetEndianType(), m_writeBuffer.Get(), m_writeBuffer.Size());
}
AZ::SimpleLcgRandom m_random;
GridMate::Marshaler<T> m_marshaler;
GridMate::WriteBufferStatic<> m_writeBuffer;
GridMate::ReadBuffer m_readBuffer;
};
// EntityIdMarshalerTest
typedef MarshalerTester<AZ::EntityId> EntityIdMarshalerTest;
TEST_F(EntityIdMarshalerTest, SingleMarshalUnmarshalTest_EquivalentEmptyValue)
{
AZ::EntityId initialId;
m_marshaler.Marshal(m_writeBuffer, initialId);
PopulateReadBuffer();
AZ::EntityId receivedId;
m_marshaler.Unmarshal(receivedId, m_readBuffer);
EXPECT_EQ(initialId,receivedId);
EXPECT_FALSE(receivedId.IsValid());
}
TEST_F(EntityIdMarshalerTest, SingleMarshalUnmarshalTest_EquivalentRandomValue)
{
AZ::EntityId initialId = AZ::EntityId(m_random.GetRandom());
m_marshaler.Marshal(m_writeBuffer, initialId);
PopulateReadBuffer();
AZ::EntityId receivedId;
m_marshaler.Unmarshal(receivedId, m_readBuffer);
EXPECT_EQ(initialId,receivedId);
}
TEST_F(EntityIdMarshalerTest, MultipleMarshalUnmarshalTest_EquivalentEmptyRandomEmptyRandomValueChain)
{
AZ::EntityId sentId1_empty;
AZ::EntityId sentId2_random = AZ::EntityId(m_random.GetRandom());
AZ::EntityId sentId3_empty;
AZ::EntityId sentId4_random = AZ::EntityId(m_random.GetRandom());
m_marshaler.Marshal(m_writeBuffer, sentId1_empty);
m_marshaler.Marshal(m_writeBuffer, sentId2_random);
m_marshaler.Marshal(m_writeBuffer, sentId3_empty);
m_marshaler.Marshal(m_writeBuffer, sentId4_random);
PopulateReadBuffer();
AZ::EntityId receivedId1_empty;
AZ::EntityId receivedId2_random;
AZ::EntityId receivedId3_empty;
AZ::EntityId receivedId4_random;
m_marshaler.Unmarshal(receivedId1_empty, m_readBuffer);
m_marshaler.Unmarshal(receivedId2_random, m_readBuffer);
m_marshaler.Unmarshal(receivedId3_empty, m_readBuffer);
m_marshaler.Unmarshal(receivedId4_random, m_readBuffer);
EXPECT_EQ(sentId1_empty, receivedId1_empty);
EXPECT_EQ(sentId2_random, receivedId2_random);
EXPECT_EQ(sentId3_empty, receivedId3_empty);
EXPECT_EQ(sentId4_random, receivedId4_random);
}
// AZ::DynamicSerializableFieldMarshaler
class FooSerializable
{
public:
AZ_RTTI(FooSerializable, "{A60F0B2B-6085-4FF1-BD17-A0B0143BB03D}");
AZ_CLASS_ALLOCATOR(FooSerializable, AZ::SystemAllocator,0);
static void Reflect(AZ::SerializeContext& serializeContext)
{
serializeContext.Class<FooSerializable>()
->Version(1)
->Field("IntValue", &FooSerializable::m_intValue)
->Field("FloatValue", &FooSerializable::m_floatValue)
;
}
FooSerializable()
: m_intValue(0)
, m_floatValue(0.0f)
{
}
bool operator==(const FooSerializable& other) const
{
return m_intValue == other.m_intValue && AZ::IsClose(m_floatValue, other.m_floatValue,0.0001f);
}
AZ::u32 m_intValue;
float m_floatValue;
};
class BarSerializable
{
public:
AZ_RTTI(BarSerializable, "{2389C23F-D247-420B-A385-71AB8455CD2E}");
AZ_CLASS_ALLOCATOR(BarSerializable, AZ::SystemAllocator,0);
static void Reflect(AZ::SerializeContext& serializeContext)
{
serializeContext.Class<BarSerializable>()
->Version(1)
->Field("LongValue", &BarSerializable::m_longValue)
->Field("DoubleValue", &BarSerializable::m_doubleValue)
;
}
BarSerializable()
: m_longValue(0)
, m_doubleValue(0.0)
{
}
bool operator==(const BarSerializable& other) const
{
return m_longValue == other.m_longValue && AZ::IsClose(m_doubleValue,other.m_doubleValue,0.0001);
}
long m_longValue;
double m_doubleValue;
};
class ComplexSerializable
{
public:
AZ_RTTI(ComplexSerializable,"{055CB45C-702C-499F-8221-E9ABB21CF1D4}");
AZ_CLASS_ALLOCATOR(ComplexSerializable, AZ::SystemAllocator,0);
static void Reflect(AZ::SerializeContext& serializeContext)
{
serializeContext.Class<ComplexSerializable>()
->Version(1)
->Field("FooSerializable",&ComplexSerializable::m_fooField)
->Field("BarSerializable",&ComplexSerializable::m_barField)
;
}
bool operator==(const ComplexSerializable& other) const
{
return m_fooField == other.m_fooField && m_barField == other.m_barField;
}
FooSerializable m_fooField;
BarSerializable m_barField;
};
class DynamicSerializableFieldMarshalerTest
: public MarshalerTester<AZ::DynamicSerializableField>
, public AZ::ComponentApplicationBus::Handler
{
public:
DynamicSerializableFieldMarshalerTest()
: MarshalerTester<AZ::DynamicSerializableField>()
{
}
void SetUp() override
{
MarshalerTester<AZ::DynamicSerializableField>::SetUp();
FooSerializable::Reflect(m_serializeContext);
BarSerializable::Reflect(m_serializeContext);
ComplexSerializable::Reflect(m_serializeContext);
// Create the Marshaler with access to our custom serialize context.
m_marshaler = GridMate::Marshaler<AZ::DynamicSerializableField>(&m_serializeContext);
AZ::ComponentApplicationBus::Handler::BusConnect();
}
void TearDown() override
{
MarshalerTester<AZ::DynamicSerializableField>::TearDown();
AZ::ComponentApplicationBus::Handler::BusDisconnect();
}
FooSerializable* GenerateFooSerializable()
{
FooSerializable* field = new FooSerializable();
RandomizeFooSerializable((*field));
return field;
}
void RandomizeFooSerializable(FooSerializable& serializable)
{
serializable.m_intValue = m_random.GetRandom();
serializable.m_floatValue = m_random.GetRandomFloat();
}
BarSerializable* GenerateBarSerializable()
{
BarSerializable* field = new BarSerializable();
return field;
}
void RandomizeBarSerializable(BarSerializable& serializable)
{
serializable.m_longValue = static_cast<long>(m_random.GetRandom());
serializable.m_doubleValue = static_cast<double>(m_random.GetRandomFloat());
}
ComplexSerializable* GenerateComplexSerializable()
{
ComplexSerializable* complexField = new ComplexSerializable();
RandomizeFooSerializable(complexField->m_fooField);
RandomizeBarSerializable(complexField->m_barField);
return complexField;
}
// Used Component Application Methods
AZ::SerializeContext* GetSerializeContext() { return &m_serializeContext; }
// Unused ComponentApplication methods
void RegisterComponentDescriptor(const AZ::ComponentDescriptor* descriptor) override { (void)descriptor; AZ_Assert(false,"Unsupported method in Unit Test"); }
void UnregisterComponentDescriptor(const AZ::ComponentDescriptor* descriptor) override { (void)descriptor; AZ_Assert(false,"Unsupported method in Unit Test"); }
AZ::ComponentApplication* GetApplication() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
bool AddEntity(AZ::Entity* entity) override { (void)entity; AZ_Assert(false,"Unsupported method in Unit Test"); return false; }
bool RemoveEntity(AZ::Entity* entity) override { (void)entity; AZ_Assert(false,"Unsupported method in Unit Test"); return false; }
bool DeleteEntity(const AZ::EntityId& id) override { (void)id; AZ_Assert(false,"Unsupported method in Unit Test"); return false; }
AZ::Entity* FindEntity(const AZ::EntityId& id) override { (void)id; AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
void EnumerateEntities(const EntityCallback& callback) override { (void)callback; AZ_Assert(false,"Unsupported method in Unit Test"); }
AZ::BehaviorContext* GetBehaviorContext() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
const char* GetAppRoot() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
const char* GetExecutableFolder() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
AZ::Debug::DrillerManager* GetDrillerManager() override { AZ_Assert(false,"Unsupported method in Unit Test"); return nullptr; }
void ReloadModule(const char* moduleFullPath) override { (void)moduleFullPath; AZ_Assert(false,"Unsupported method in Unit Test"); }
AZ::SerializeContext m_serializeContext;
};
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentEmptyValue)
{
AZ::DynamicSerializableField sentField;
m_marshaler.Marshal(m_writeBuffer, sentField);
PopulateReadBuffer();
AZ::DynamicSerializableField receivedField;
m_marshaler.Unmarshal(receivedField,m_readBuffer);
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
}
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentFooValue)
{
AZ::DynamicSerializableField sentField;
FooSerializable* fooSerializable = GenerateFooSerializable();
sentField.Set(fooSerializable);
m_marshaler.Marshal(m_writeBuffer, sentField);
PopulateReadBuffer();
AZ::DynamicSerializableField receivedField;
m_marshaler.Unmarshal(receivedField,m_readBuffer);
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
sentField.DestroyData(&m_serializeContext);
receivedField.DestroyData(&m_serializeContext);
}
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentBarValue)
{
AZ::DynamicSerializableField sentField;
BarSerializable* barSerializable = GenerateBarSerializable();
sentField.Set(barSerializable);
m_marshaler.Marshal(m_writeBuffer, sentField);
PopulateReadBuffer();
AZ::DynamicSerializableField receivedField;
m_marshaler.Unmarshal(receivedField,m_readBuffer);
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
sentField.DestroyData(&m_serializeContext);
receivedField.DestroyData(&m_serializeContext);
}
TEST_F(DynamicSerializableFieldMarshalerTest, SingleMarshalUnmarshalTest_EquivalentComplexValue)
{
AZ::DynamicSerializableField sentField;
ComplexSerializable* complexSerializable = GenerateComplexSerializable();
sentField.Set(complexSerializable);
m_marshaler.Marshal(m_writeBuffer, sentField);
PopulateReadBuffer();
AZ::DynamicSerializableField receivedField;
m_marshaler.Unmarshal(receivedField,m_readBuffer);
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
sentField.DestroyData(&m_serializeContext);
receivedField.DestroyData(&m_serializeContext);
}
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_EmptyEmptyChainEquivalentValue)
{
AZ::DynamicSerializableField sentField1;
AZ::DynamicSerializableField sentField2;
m_marshaler.Marshal(m_writeBuffer, sentField1);
m_marshaler.Marshal(m_writeBuffer, sentField2);
PopulateReadBuffer();
AZ::DynamicSerializableField receivedField1;
AZ::DynamicSerializableField receivedField2;
m_marshaler.Unmarshal(receivedField1,m_readBuffer);
m_marshaler.Unmarshal(receivedField2,m_readBuffer);
EXPECT_TRUE(sentField1.IsEqualTo(receivedField1, &m_serializeContext));
EXPECT_TRUE(sentField2.IsEqualTo(receivedField2, &m_serializeContext));
sentField1.DestroyData(&m_serializeContext);
sentField2.DestroyData(&m_serializeContext);
receivedField1.DestroyData(&m_serializeContext);
receivedField2.DestroyData(&m_serializeContext);
}
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_FooBarComplexChainEquivalentValue)
{
AZ::DynamicSerializableField sentField1;
FooSerializable* fooSerializable = GenerateFooSerializable();
sentField1.Set(fooSerializable);
AZ::DynamicSerializableField sentField2;
BarSerializable* barSerializable = GenerateBarSerializable();
sentField2.Set(barSerializable);
AZ::DynamicSerializableField sentField3;
ComplexSerializable* complexSerializable = GenerateComplexSerializable();
sentField3.Set(complexSerializable);
m_marshaler.Marshal(m_writeBuffer, sentField1);
m_marshaler.Marshal(m_writeBuffer, sentField2);
m_marshaler.Marshal(m_writeBuffer, sentField3);
PopulateReadBuffer();
AZ::DynamicSerializableField receivedField1;
AZ::DynamicSerializableField receivedField2;
AZ::DynamicSerializableField receivedField3;
m_marshaler.Unmarshal(receivedField1, m_readBuffer);
m_marshaler.Unmarshal(receivedField2, m_readBuffer);
m_marshaler.Unmarshal(receivedField3, m_readBuffer);
EXPECT_TRUE(sentField1.IsEqualTo(receivedField1, &m_serializeContext));
EXPECT_TRUE(sentField2.IsEqualTo(receivedField2, &m_serializeContext));
EXPECT_TRUE(sentField3.IsEqualTo(receivedField3, &m_serializeContext));
sentField1.DestroyData(&m_serializeContext);
sentField2.DestroyData(&m_serializeContext);
sentField3.DestroyData(&m_serializeContext);
receivedField1.DestroyData(&m_serializeContext);
receivedField2.DestroyData(&m_serializeContext);
receivedField3.DestroyData(&m_serializeContext);
}
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_EmptyFooEmptyBarEmptyComplexChainEquivalentValue)
{
AZ::DynamicSerializableField emptyField;
AZ::DynamicSerializableField sentField1;
FooSerializable* fooSerializable = GenerateFooSerializable();
sentField1.Set(fooSerializable);
AZ::DynamicSerializableField sentField2;
BarSerializable* barSerializable = GenerateBarSerializable();
sentField2.Set(barSerializable);
AZ::DynamicSerializableField sentField3;
ComplexSerializable* complexSerializable = GenerateComplexSerializable();
sentField3.Set(complexSerializable);
m_marshaler.Marshal(m_writeBuffer, emptyField);
m_marshaler.Marshal(m_writeBuffer, sentField1);
m_marshaler.Marshal(m_writeBuffer, emptyField);
m_marshaler.Marshal(m_writeBuffer, sentField2);
m_marshaler.Marshal(m_writeBuffer, emptyField);
m_marshaler.Marshal(m_writeBuffer, sentField3);
m_marshaler.Marshal(m_writeBuffer, emptyField);
PopulateReadBuffer();
AZ::DynamicSerializableField receivedEmptyField1;
AZ::DynamicSerializableField receivedField1;
AZ::DynamicSerializableField receivedEmptyField2;
AZ::DynamicSerializableField receivedField2;
AZ::DynamicSerializableField receivedEmptyField3;
AZ::DynamicSerializableField receivedField3;
AZ::DynamicSerializableField receivedEmptyField4;
m_marshaler.Unmarshal(receivedEmptyField1, m_readBuffer);
m_marshaler.Unmarshal(receivedField1, m_readBuffer);
m_marshaler.Unmarshal(receivedEmptyField2, m_readBuffer);
m_marshaler.Unmarshal(receivedField2, m_readBuffer);
m_marshaler.Unmarshal(receivedEmptyField3, m_readBuffer);
m_marshaler.Unmarshal(receivedField3, m_readBuffer);
m_marshaler.Unmarshal(receivedEmptyField4, m_readBuffer);
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField1, &m_serializeContext));
EXPECT_TRUE(sentField1.IsEqualTo(receivedField1, &m_serializeContext));
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField2, &m_serializeContext));
EXPECT_TRUE(sentField2.IsEqualTo(receivedField2, &m_serializeContext));
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField3, &m_serializeContext));
EXPECT_TRUE(sentField3.IsEqualTo(receivedField3, &m_serializeContext));
EXPECT_TRUE(emptyField.IsEqualTo(receivedEmptyField4, &m_serializeContext));
emptyField.DestroyData(&m_serializeContext);
sentField1.DestroyData(&m_serializeContext);
sentField2.DestroyData(&m_serializeContext);
sentField3.DestroyData(&m_serializeContext);
receivedEmptyField1.DestroyData(&m_serializeContext);
receivedField1.DestroyData(&m_serializeContext);
receivedEmptyField2.DestroyData(&m_serializeContext);
receivedField2.DestroyData(&m_serializeContext);
receivedEmptyField3.DestroyData(&m_serializeContext);
receivedField3.DestroyData(&m_serializeContext);
receivedEmptyField4.DestroyData(&m_serializeContext);
}
TEST_F(DynamicSerializableFieldMarshalerTest, MultipleMarshalUnmarshalTest_RandomChainEquivalentValue)
{
// Need to watch out for the size of the WriteBuffer. It's about ~2048 bytes, at worst case here, I'll write ~100 Bytes to the field per test object)
// So I need to keep this ~20 elements.
int numValues = 5 + m_random.GetRandom()%10;
AZStd::vector< AZ::DynamicSerializableField > sentValues;
AZStd::vector< AZ::DynamicSerializableField > receivedValues;
sentValues.resize(numValues);
receivedValues.resize(numValues);
for (auto& currentField : sentValues)
{
int value = m_random.GetRandom() % 4;
switch (value)
{
case 0:
{
currentField.Set(GenerateFooSerializable());
}
break;
case 1:
{
currentField.Set(GenerateBarSerializable());
}
break;
case 2:
{
currentField.Set(GenerateComplexSerializable());
}
break;
case 3:
default:
// Empty field
break;
}
}
for (auto& currentField : sentValues)
{
m_marshaler.Marshal(m_writeBuffer,currentField);
}
PopulateReadBuffer();
for (auto& currentField : receivedValues)
{
m_marshaler.Unmarshal(currentField,m_readBuffer);
}
for (unsigned int i=0; i < sentValues.size(); ++i)
{
AZ::DynamicSerializableField& sentField = sentValues[i];
AZ::DynamicSerializableField& receivedField = receivedValues[i];
EXPECT_TRUE(sentField.IsEqualTo(receivedField, &m_serializeContext));
sentField.DestroyData(&m_serializeContext);
receivedField.DestroyData(&m_serializeContext);
}
}
}
@@ -11,4 +11,4 @@
*/
#pragma once
#include <AzFrameworkTests_Traits_Android.h>
#include <AzFrameworkTests_Traits_Android.h>
@@ -11,4 +11,4 @@
*/
#pragma once
#include <AzFrameworkTests_Traits_Linux.h>
#include <AzFrameworkTests_Traits_Linux.h>
@@ -11,4 +11,4 @@
*/
#pragma once
#include <AzFrameworkTests_Traits_Mac.h>
#include <AzFrameworkTests_Traits_Mac.h>
@@ -11,4 +11,4 @@
*/
#pragma once
#include <AzFrameworkTests_Traits_Windows.h>
#include <AzFrameworkTests_Traits_Windows.h>
@@ -11,4 +11,4 @@
*/
#pragma once
#include <AzFrameworkTests_Traits_iOS.h>
#include <AzFrameworkTests_Traits_iOS.h>
+90 -118
View File
@@ -130,6 +130,8 @@ namespace SceneUnitTest
m_systemEntity->CreateComponent<AZ::JobManagerComponent>();
m_systemEntity->CreateComponent<AZ::StreamerComponent>();
m_systemEntity->Activate();
m_sceneSystem = AzFramework::SceneSystemInterface::Get();
}
void TearDown() override
@@ -146,167 +148,119 @@ namespace SceneUnitTest
AZ::IO::FileIOBase* m_prevFileIO;
AZ::ComponentApplication m_app;
AZ::Entity* m_systemEntity = nullptr;
AzFramework::ISceneSystem* m_sceneSystem = nullptr;
};
TEST_F(SceneTest, CreateScene)
{
Scene* scene = nullptr;
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
{
// A scene should be able to be created with a given name.
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene("TestScene");
EXPECT_TRUE(createSceneOutcome.IsSuccess()) << "Unable to create a scene.";
// The scene pointer returned should be valid
scene = createSceneOutcome.GetValue();
EXPECT_TRUE(scene != nullptr) << "Scene creation reported success, but no scene actually was actually returned.";
AZStd::shared_ptr<Scene> scene = createSceneOutcome.TakeValue();
EXPECT_NE(scene, nullptr) << "Scene creation reported success, but no scene actually was actually returned.";
// Attempting to create another scene with the same name should fail.
createSceneOutcome = AZ::Failure<AZStd::string>("");
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
createSceneOutcome = m_sceneSystem->CreateScene("TestScene");
EXPECT_TRUE(!createSceneOutcome.IsSuccess()) << "Should not be able to create two scenes with the same name.";
}
TEST_F(SceneTest, GetScene)
{
Scene* createdScene = nullptr;
Scene* retrievedScene = nullptr;
Scene* nullScene = nullptr;
const static AZStd::string_view s_sceneName = "TestScene";
constexpr AZStd::string_view sceneName = "TestScene";
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, s_sceneName);
createdScene = createSceneOutcome.GetValue();
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
AZStd::shared_ptr<Scene> createdScene = createSceneOutcome.TakeValue();
// Should be able to get a scene by name, and it should match the scene that was created.
AzFramework::SceneSystemRequestBus::BroadcastResult(retrievedScene, &AzFramework::SceneSystemRequestBus::Events::GetScene, s_sceneName);
EXPECT_TRUE(retrievedScene != nullptr) << "Attempting to get scene by name resulted in nullptr.";
EXPECT_TRUE(retrievedScene == createdScene) << "Retrieved scene does not match created scene.";
AZStd::shared_ptr<Scene> retrievedScene = m_sceneSystem->GetScene(sceneName);
EXPECT_NE(retrievedScene, nullptr) << "Attempting to get scene by name resulted in nullptr.";
EXPECT_EQ(retrievedScene, createdScene) << "Retrieved scene does not match created scene.";
// An invalid name should return a null scene.
AzFramework::SceneSystemRequestBus::BroadcastResult(nullScene, &AzFramework::SceneSystemRequestBus::Events::GetScene, "non-existant scene");
EXPECT_TRUE(nullScene == nullptr) << "Should not be able to retrieve a scene that wasn't created.";
AZStd::shared_ptr<Scene> nullScene = m_sceneSystem->GetScene("non-existant scene");
EXPECT_EQ(nullScene, nullptr) << "Should not be able to retrieve a scene that wasn't created.";
}
TEST_F(SceneTest, RemoveScene)
{
Scene* createdScene = nullptr;
const static AZStd::string_view s_sceneName = "TestScene";
constexpr AZStd::string_view sceneName = "TestScene";
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, s_sceneName);
createdScene = createSceneOutcome.GetValue();
bool success = false;
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveScene, s_sceneName);
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
bool success = m_sceneSystem->RemoveScene(sceneName);
EXPECT_TRUE(success) << "Failed to remove the scene that was just created.";
success = true;
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveScene, "non-existant scene");
success = m_sceneSystem->RemoveScene("non-existant scene");
EXPECT_FALSE(success) << "Remove scene returned success for a non-existant scene.";
}
TEST_F(SceneTest, GetAllScenes)
TEST_F(SceneTest, IterateActiveScenes)
{
constexpr size_t NumScenes = 5;
Scene* scenes[NumScenes] = { nullptr };
AZStd::shared_ptr<Scene> scenes[NumScenes] = {nullptr};
for (size_t i = 0; i < NumScenes; ++i)
{
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
AZStd::string sceneName = AZStd::string::format("scene %zu", i);
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, sceneName);
scenes[i] = createSceneOutcome.GetValue();
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
scenes[i] = createSceneOutcome.TakeValue();
}
AZStd::vector<Scene*> retrievedScenes;
AzFramework::SceneSystemRequestBus::BroadcastResult(retrievedScenes, &AzFramework::SceneSystemRequestBus::Events::GetAllScenes);
EXPECT_EQ(NumScenes, retrievedScenes.size()) << "GetAllScenes() returned a different number of scenes than those created.";
for (size_t i = 0; i < NumScenes; ++i)
{
EXPECT_EQ(scenes[i], retrievedScenes.at(i)) << "GetAllScenes() returned scenes in a different order than they were created.";
}
size_t index = 0;
m_sceneSystem->IterateActiveScenes([&index, &scenes](const AZStd::shared_ptr<Scene>& scene)
{
EXPECT_EQ(scenes[index++], scene);
return true;
});
}
TEST_F(SceneTest, EntityContextSceneMapping)
TEST_F(SceneTest, IterateZombieScenes)
{
AZStd::unique_ptr<SliceEntityOwnershipService> m_entityOwnershipService =
AZStd::make_unique<AzFramework::SliceEntityOwnershipService>(AZ::Uuid::CreateNull(), m_app.GetSerializeContext());
// Create the entity context, entity, and component
EntityContext* testEntityContext = new EntityContext(AZ::Uuid::CreateRandom(), AZStd::move(m_entityOwnershipService));
testEntityContext->InitContext();
EntityContextId testEntityContextId = testEntityContext->GetContextId();
AZ::Entity* testEntity = testEntityContext->CreateEntity("TestEntity");
TestComponent* testComponent = testEntity->CreateComponent<TestComponent>();
constexpr size_t NumScenes = 5;
// Try to activate an entity and get the scene before a scene has been set. This should fail.
TestComponentConfig failConfig;
failConfig.m_activateFunction = [](TestComponent* component)
AZStd::shared_ptr<Scene> scenes[NumScenes] = {nullptr};
// Create zombies.
for (size_t i = 0; i < NumScenes; ++i)
{
(void)component;
Scene* scene = nullptr;
EntityContextId entityContextId = EntityContextId::CreateNull();
AZStd::string sceneName = AZStd::string::format("scene %zu", i);
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene(sceneName);
scenes[i] = createSceneOutcome.TakeValue();
m_sceneSystem->RemoveScene(sceneName);
}
AzFramework::EntityIdContextQueryBus::BroadcastResult(entityContextId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
// Check to make sure there are no more active scenes.
size_t index = 0;
m_sceneSystem->IterateActiveScenes([&index, &scenes](const AZStd::shared_ptr<Scene>&)
{
index++;
return true;
});
EXPECT_EQ(0, index);
// A null scene should be returned since a scene has not been set for this entity context.
AzFramework::SceneSystemRequestBus::BroadcastResult(scene, &AzFramework::SceneSystemRequestBus::Events::GetSceneFromEntityContextId, entityContextId);
EXPECT_TRUE(scene == nullptr) << "Found a scene when one shouldn't exist.";
};
testComponent->SetConfiguration(failConfig);
testComponent->Activate();
testComponent->Deactivate();
// Check that the scenes are still returned as zombies.
index = 0;
m_sceneSystem->IterateZombieScenes([&index, &scenes](Scene& scene)
{
EXPECT_EQ(scenes[index++].get(), &scene);
return true;
});
// Create the scene
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
Scene* scene = createSceneOutcome.GetValue();
// Map the Entity context to the scene
bool success = false;
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::SetSceneForEntityContextId, testEntityContextId, scene);
EXPECT_TRUE(success) << "Unable to associate an entity context with a scene.";
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::SetSceneForEntityContextId, testEntityContextId, scene);
EXPECT_FALSE(success) << "Attempting to map an entity context to a scene that's already mapped, this should not work.";
// Now it should be possible to get the scene from the entity context within an Entity's Activate()
TestComponentConfig successConfig;
successConfig.m_activateFunction = [](TestComponent* component)
// Check that all scenes are removed when there are no more handles.
for (size_t i = 0; i < NumScenes; ++i)
{
(void)component;
Scene* scene = nullptr;
EntityContextId entityContextId = EntityContextId::CreateNull();
AzFramework::EntityIdContextQueryBus::BroadcastResult(entityContextId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
// A scene should be returned since a scene has been set for this entity context.
AzFramework::SceneSystemRequestBus::BroadcastResult(scene, &AzFramework::SceneSystemRequestBus::Events::GetSceneFromEntityContextId, entityContextId);
EXPECT_TRUE(scene != nullptr) << "Could not find a scene for the entity context.";
};
testComponent->SetConfiguration(successConfig);
testComponent->Activate();
testComponent->Deactivate();
// Now remove the entity context / scene association and make sure things fail again.
success = false;
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveSceneForEntityContextId, testEntityContextId, nullptr);
EXPECT_FALSE(success) << "Should not be able to remove an entity context from a scene it's not associated with.";
AzFramework::SceneSystemRequestBus::BroadcastResult(success, &AzFramework::SceneSystemRequestBus::Events::RemoveSceneForEntityContextId, testEntityContextId, scene);
EXPECT_TRUE(success) << "Was not able to remove an entity context from a scene it's associated with.";
testComponent->SetConfiguration(failConfig);
testComponent->Activate();
testComponent->Deactivate();
delete testEntityContext; // This should also clean up owned entities / components.
scenes[i].reset();
}
index = 0;
m_sceneSystem->IterateZombieScenes([&index, &scenes](Scene&) {
index++;
return true;
});
EXPECT_EQ(0, index);
}
// Test classes for use in the SceneSystem test. These can't be defined in the test itself due to some functions created by AZ_RTTI not having a body which breaks VS2015.
@@ -324,30 +278,48 @@ namespace SceneUnitTest
TEST_F(SceneTest, SceneSystem)
{
// Create the scene
AZ::Outcome<Scene*, AZStd::string> createSceneOutcome = AZ::Failure<AZStd::string>("");
AzFramework::SceneSystemRequestBus::BroadcastResult(createSceneOutcome, &AzFramework::SceneSystemRequestBus::Events::CreateScene, "TestScene");
AzFramework::Scene* scene = createSceneOutcome.GetValue();
AZ::Outcome<AZStd::shared_ptr<Scene>, AZStd::string> createSceneOutcome = m_sceneSystem->CreateScene("TestScene");
EXPECT_TRUE(createSceneOutcome.IsSuccess());
AZStd::shared_ptr<Scene> scene = createSceneOutcome.TakeValue();
// Set a class on the Scene
Foo1* foo1a = new Foo1();
EXPECT_TRUE(scene->SetSubsystem(foo1a));
// Get that class back from the Scene
EXPECT_EQ(foo1a, scene->GetSubsystem<Foo1>());
EXPECT_EQ(foo1a, *scene->FindSubsystem<Foo1*>());
// Try to set the same class type twice, this should fail.
Foo1* foo1b = new Foo1();
EXPECT_FALSE(scene->SetSubsystem(foo1b));
delete foo1b;
// Add a child scene
createSceneOutcome = m_sceneSystem->CreateSceneWithParent("ChildScene", scene);
EXPECT_TRUE(createSceneOutcome.IsSuccess());
AZStd::shared_ptr<Scene> childScene = createSceneOutcome.TakeValue();
// Get class back from parent scene.
EXPECT_EQ(foo1a, *childScene->FindSubsystem<Foo1*>());
// Find overloaded version of class on child scene.
Foo1* foo1c = new Foo1();
EXPECT_TRUE(childScene->SetSubsystem(foo1c));
EXPECT_EQ(foo1c, *childScene->FindSubsystem<Foo1*>());
// Unset system on child scene, using alternative unset function.
EXPECT_TRUE(childScene->UnsetSubsystem(foo1c));
delete foo1c;
// Try to un-set a class that was never set, this should fail.
EXPECT_FALSE(scene->UnsetSubsystem<Foo2>());
// Unset the class that was previously set
EXPECT_TRUE(scene->UnsetSubsystem<Foo1>());
delete foo1a;
// Make sure that the previsouly set class was really removed.
EXPECT_EQ(nullptr, scene->GetSubsystem<Foo1>());
// Make sure that the previously set class was really removed.
EXPECT_EQ(nullptr, scene->FindSubsystem<Foo1*>());
}
} // UnitTest
@@ -17,7 +17,6 @@
#include <AzCore/Script/ScriptContext.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AzToolsFramework/ToolsComponents/ScriptEditorComponent.h>
#include <AzFramework/Script/ScriptNetBindings.h>
#include "EntityTestbed.h"
@@ -63,8 +62,6 @@ namespace UnitTest
EBUS_EVENT_RESULT(m_behaviorContext, AZ::ComponentApplicationBus, GetBehaviorContext);
EBUS_EVENT_RESULT(m_serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
NetBindable::Reflect(m_serializeContext);
AzToolsFramework::Components::ScriptEditorComponent::CreateDescriptor(); // descriptor is deleted by app
AzToolsFramework::Components::ScriptEditorComponent::Reflect(m_serializeContext);
@@ -228,63 +225,4 @@ namespace UnitTest
EXPECT_NE(scriptComponent->GetScriptProperty("myNum"), nullptr);
}
TEST_F(ScriptComponentTest, UpdateNetSynchedProperty)
{
// Make sure altering a netsynched property in script only affects the single entity instance
const AZStd::string script = "local test = {\
Properties = {\
myNetSynchedNum = { default = 41, netSynched ={} },\
doUpdate = { default = false },\
},\
}\
function test:OnActivate()\
self.tickBusHandler = TickBus.Connect(self, self.entityId)\
end\
function test:OnDeactivate()\
self.tickBusHandler:Disconnect()\
end\
function test:OnTick(deltaTime, timePoint)\
if self.Properties.doUpdate then\
self.Properties.myNetSynchedNum = self.Properties.myNetSynchedNum+1\
end\
end\
return test";
const Data::Asset<ScriptAsset> scriptAsset = CreateAndLoadScriptAsset(script);
Entity entity1, entity2;
ScriptComponent* scriptComponentInstance1 = BuildGameEntity(scriptAsset, entity1);
ScriptComponent* scriptComponentInstance2 = BuildGameEntity(scriptAsset, entity2);
// Change the value of entity1's doUpdate to true.
// This way entity1's myNetSynchedNum should be incremented during OnTick
auto* doUpdateScriptProperty = azrtti_cast<ScriptPropertyBoolean*>(scriptComponentInstance1->GetScriptProperty("doUpdate"));
ASSERT_NE(doUpdateScriptProperty, nullptr);
doUpdateScriptProperty->m_value = true;
entity1.Init();
entity2.Init();
entity1.Activate();
entity2.Activate();
// Tick in order to call OnTick in our lua script.
m_app.Tick();
m_app.TickSystem();
// Ensure Entity1's myNetSynchedNum updated, but not Entity2
auto* netSynchedProperty1 = scriptComponentInstance1->GetNetworkedScriptProperty("myNetSynchedNum");
auto* netSynchedProperty2 = scriptComponentInstance2->GetNetworkedScriptProperty("myNetSynchedNum");
ASSERT_NE(netSynchedProperty1, nullptr);
ASSERT_NE(netSynchedProperty2, nullptr);
auto* num1 = azrtti_cast<const ScriptPropertyNumber*>(netSynchedProperty1);
auto* num2 = azrtti_cast<const ScriptPropertyNumber*>(netSynchedProperty2);
ASSERT_NE(num1, nullptr);
ASSERT_NE(num2, nullptr);
EXPECT_EQ(num1->m_value, 42);
EXPECT_EQ(num2->m_value, 41);
}
} // namespace UnitTest
@@ -888,37 +888,6 @@ namespace UnitTest
const char* m_objectStreamBuffer = nullptr;
};
class TransformComponentConvertFromV2
: public TransformComponentVersionConverter
{
public:
TransformComponentConvertFromV2()
{
m_objectStreamBuffer =
R"DELIMITER(<ObjectStream version="1">
<Class name="TransformComponent" field="element" version="2" type="{22B10178-39B6-4C12-BB37-77DB45FDD3B6}">
<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
<Class name="AZ::u64" field="Id" value="18023671824091307142" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
</Class>
<Class name="NetBindable" field="BaseClass2" type="{80206665-D429-4703-B42E-94434F82F381}">
<Class name="bool" field="m_isSyncEnabled" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
</Class>
<Class name="EntityId" field="Parent" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
<Class name="AZ::u64" field="id" value="4294967295" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
</Class>
<Class name="Transform" field="Transform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
<Class name="Transform" field="LocalTransform" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000" type="{5D9958E9-9F1E-4985-B532-FFFDE75FEDFD}"/>
<Class name="unsigned int" field="ParentActivationTransformMode" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
</Class>
</ObjectStream>)DELIMITER";
}
};
TEST_F(TransformComponentConvertFromV2, IsStatic_False)
{
EXPECT_FALSE(m_transformInterface->IsStaticTransform());
}
///////////////////////////////////////////////////////////////////////////
// TransformConfig
@@ -12,4 +12,4 @@
set(FILES
Utils/Utils.h
Utils/Utils.cpp
)
)
@@ -17,6 +17,8 @@ set(FILES
BinToTextEncode.cpp
ComponentAddRemove.cpp
ComponentAdapterTests.cpp
ClickDetectorTests.cpp
CursorStateTests.cpp
EntityContext.cpp
EntityTestbed.h
FileFunc.cpp
@@ -26,8 +28,6 @@ set(FILES
GenAppDescriptors.cpp
GenericComponentWrapperTest.cpp
InstanceDataHierarchy.cpp
NetBinding.cpp
NetworkContext.cpp
OctreePerformanceTests.cpp
OctreeTests.cpp
Slices.cpp
@@ -35,12 +35,8 @@ set(FILES
Script/ScriptEntityTests.cpp
AssetCatalog.cpp
AssetProcessorConnection.cpp
NetBindingSystemImplTest.cpp
NetBindingMocks.h
NativeWindow.cpp
TransformComponent.cpp
GridMocks.h
InterestManagerComponentTests.cpp
SQLiteConnectionTests.cpp
ProcessLaunchParseTests.cpp
Application.cpp