Add AWSAttribution feature (#1164)
* LYN-3601: Provide skeleton classes for AWS Attribution (#31) Provide skeleton classes for AWS Attribution, along with some basic unit tests * Add AWS Attribution UI and settings (#56) * Adding AWS Attributions UX and corresponding editor preference s setting * Fix serialized field description * Fixed update frequency to be a day * Handling editor startup with default values for AWSAttribution * Add missing header and remove AWSCoreSystemComponentMock fron test * Generate and post AWSAttribution metric (#69) * Adding AWS Attribution Api service job * Adding support for config endpoint override * Update Api endpoint formatting, fix default region * Remove extra header * Fixes for link issues * Fix Unittest namespace * Instantiating AWSAttributionSystemComponent in AWS.Editor module * Update AttributionMetric with engine version and AWS enabled gems (#77) * Update AttributionMetric with engine version and AWS enabled gems * Fix warnings * Undoing accidental change * Saving level PrefabLevel_OpensLevelWithEntities * Remove overriding editorprefrences.setreg * Revert "Saving level PrefabLevel_OpensLevelWithEntities" This reverts commit 529af70c55ece70fc6bc29ceb83bef60413713a3. * Move AWS preferences to its own temp settings file * Undo accidental file add * Add missing string params in warning messages Co-authored-by: Pip Potter <61438964+lmbr-pip@users.noreply.github.com>
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include "EditorPreferencesPageViewportMovement.h"
|
||||
#include "EditorPreferencesPageViewportDebug.h"
|
||||
#include "EditorPreferencesPageExperimentalLighting.h"
|
||||
#include "EditorPreferencesPageAWS.h"
|
||||
#include "LyViewPaneNames.h"
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
@@ -72,6 +73,7 @@ EditorPreferencesDialog::EditorPreferencesDialog(QWidget* pParent)
|
||||
CEditorPreferencesPage_ViewportMovement::Reflect(*serializeContext);
|
||||
CEditorPreferencesPage_ViewportDebug::Reflect(*serializeContext);
|
||||
CEditorPreferencesPage_ExperimentalLighting::Reflect(*serializeContext);
|
||||
CEditorPreferencesPage_AWS::Reflect(*serializeContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 "EditorDefs.h"
|
||||
|
||||
#include "EditorPreferencesPageAWS.h"
|
||||
|
||||
// AzCore
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Jobs/JobFunction.h>
|
||||
|
||||
void CEditorPreferencesPage_AWS::Reflect(AZ::SerializeContext& serialize)
|
||||
{
|
||||
serialize.Class<UsageOptions>()
|
||||
->Version(1)
|
||||
->Field("AWSAttributionEnabled", &UsageOptions::m_awsAttributionEnabled);
|
||||
|
||||
serialize.Class<CEditorPreferencesPage_AWS>()
|
||||
->Version(1)
|
||||
->Field("UsageOptions", &CEditorPreferencesPage_AWS::m_usageOptions);
|
||||
|
||||
AZ::EditContext* editContext = serialize.GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<UsageOptions>("Options", "")
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &UsageOptions::m_awsAttributionEnabled, "Send Metrics usage to AWS",
|
||||
"Reports Gem usage to AWS on Editor launch");
|
||||
|
||||
editContext->Class<CEditorPreferencesPage_AWS>("AWS Preferences", "AWS Preferences")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_AWS::m_usageOptions, "AWS Usage Data", "AWS Usage Options");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CEditorPreferencesPage_AWS::CEditorPreferencesPage_AWS()
|
||||
{
|
||||
m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
|
||||
InitializeSettings();
|
||||
|
||||
// TODO Update with AWS svg.
|
||||
m_icon = QIcon(":/res/AWS_preferences_icon.svg");
|
||||
}
|
||||
|
||||
CEditorPreferencesPage_AWS::~CEditorPreferencesPage_AWS()
|
||||
{
|
||||
m_settingsRegistry.reset();
|
||||
}
|
||||
|
||||
const char* CEditorPreferencesPage_AWS::GetTitle()
|
||||
{
|
||||
return "AWS";
|
||||
}
|
||||
|
||||
QIcon& CEditorPreferencesPage_AWS::GetIcon()
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
void CEditorPreferencesPage_AWS::OnApply()
|
||||
{
|
||||
m_settingsRegistry->Set(AWSAttributionEnabledKey, m_usageOptions.m_awsAttributionEnabled);
|
||||
SaveSettingsRegistryFile();
|
||||
}
|
||||
|
||||
const CEditorPreferencesPage_AWS::UsageOptions& CEditorPreferencesPage_AWS::GetUsageOptions()
|
||||
{
|
||||
return m_usageOptions;
|
||||
}
|
||||
|
||||
void CEditorPreferencesPage_AWS::SaveSettingsRegistryFile()
|
||||
{
|
||||
AZ::Job* job = AZ::CreateJobFunction(
|
||||
[this]()
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ_Assert(fileIO, "File IO is not initialized.");
|
||||
|
||||
// Resolve path to editor_aws_preferences.setreg
|
||||
AZStd::string editorPreferencesFilePath =
|
||||
AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName);
|
||||
AZStd::array<char, AZ::IO::MaxPathLength> resolvedPath{};
|
||||
fileIO->ResolvePath(editorPreferencesFilePath.c_str(), resolvedPath.data(), resolvedPath.size());
|
||||
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings;
|
||||
dumperSettings.m_prettifyOutput = true;
|
||||
dumperSettings.m_jsonPointerPrefix = AWSAttributionSettingsPrefixKey;
|
||||
|
||||
AZStd::string stringBuffer;
|
||||
AZ::IO::ByteContainerStream stringStream(&stringBuffer);
|
||||
if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(
|
||||
*m_settingsRegistry, AWSAttributionSettingsPrefixKey, stringStream, dumperSettings))
|
||||
{
|
||||
AZ_Warning(
|
||||
"AWSAttributionManager", false, R"(Unable to save changes to the Editor AWS Preferences registry file at "%s"\n)",
|
||||
resolvedPath.data());
|
||||
return;
|
||||
}
|
||||
|
||||
bool saved{};
|
||||
constexpr auto configurationMode =
|
||||
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode))
|
||||
{
|
||||
saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size();
|
||||
}
|
||||
|
||||
AZ_Warning(
|
||||
"AWSAttributionManager", saved, R"(Unable to save Editor AWS Preferences registry file to path "%s"\n)",
|
||||
editorPreferencesFilePath.c_str());
|
||||
},
|
||||
true);
|
||||
job->Start();
|
||||
}
|
||||
|
||||
void CEditorPreferencesPage_AWS::InitializeSettings()
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ_Assert(fileIO, "File IO is not initialized.");
|
||||
|
||||
// Resolve path to editor_aws_preferences.setreg
|
||||
AZStd::string editorAWSPreferencesFilePath =
|
||||
AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName);
|
||||
AZStd::array<char, AZ::IO::MaxPathLength> resolvedPathAWSPreference{};
|
||||
if (!fileIO->ResolvePath(editorAWSPreferencesFilePath.c_str(), resolvedPathAWSPreference.data(), resolvedPathAWSPreference.size()))
|
||||
{
|
||||
AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.data());
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileIO->Exists(resolvedPathAWSPreference.data()))
|
||||
{
|
||||
m_settingsRegistry->MergeSettingsFile(resolvedPathAWSPreference.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
|
||||
}
|
||||
|
||||
if (!m_settingsRegistry->Get(m_usageOptions.m_awsAttributionEnabled, AWSAttributionEnabledKey))
|
||||
{
|
||||
// If key is missing default to on.
|
||||
m_usageOptions.m_awsAttributionEnabled = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 "Include/IPreferencesPage.h"
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <QIcon>
|
||||
|
||||
class CEditorPreferencesPage_AWS
|
||||
: public IPreferencesPage
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(CEditorPreferencesPage_AWS, "{51FB9557-ABA3-4FD7-803A-1784F5B06F5F}", IPreferencesPage)
|
||||
|
||||
static void Reflect(AZ::SerializeContext& serialize);
|
||||
|
||||
CEditorPreferencesPage_AWS();
|
||||
virtual ~CEditorPreferencesPage_AWS();
|
||||
|
||||
// IPreferencesPage interface methods.
|
||||
virtual const char* GetCategory() override { return "AWS"; }
|
||||
virtual const char* GetTitle() override;
|
||||
virtual QIcon& GetIcon() override;
|
||||
virtual void OnApply() override;
|
||||
virtual void OnCancel() override {}
|
||||
virtual bool OnQueryCancel() override { return true; }
|
||||
|
||||
protected:
|
||||
struct UsageOptions
|
||||
{
|
||||
AZ_TYPE_INFO(UsageOptions, "{2B7D9B19-D13B-4E54-B724-B2FD8D0828B3}")
|
||||
|
||||
bool m_awsAttributionEnabled;
|
||||
};
|
||||
|
||||
const UsageOptions& GetUsageOptions();
|
||||
|
||||
private:
|
||||
void InitializeSettings();
|
||||
void SaveSettingsRegistryFile();
|
||||
UsageOptions m_usageOptions;
|
||||
QIcon m_icon;
|
||||
AZStd::unique_ptr<AZ::SettingsRegistryImpl> m_settingsRegistry;
|
||||
|
||||
static constexpr char AWSAttributionEnabledKey[] = "/Amazon/AWS/Preferences/AWSAttributionEnabled";
|
||||
static constexpr char EditorPreferencesFileName[] = "editorpreferences.setreg";
|
||||
static constexpr char EditorAWSPreferencesFileName[] = "editor_aws_preferences.setreg";
|
||||
static constexpr char AWSAttributionSettingsPrefixKey[] = "/Amazon/AWS/Preferences";
|
||||
};
|
||||
@@ -143,6 +143,7 @@
|
||||
<file>res/Camera.svg</file>
|
||||
<file>res/Debug.svg</file>
|
||||
<file>res/Experimental.svg</file>
|
||||
<file>res/AWS_preferences_icon.svg</file>
|
||||
<file>res/Files.svg</file>
|
||||
<file>res/Gizmos.svg</file>
|
||||
<file>res/Global.svg</file>
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#include "PreferencesStdPages.h"
|
||||
|
||||
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
||||
|
||||
// Editor
|
||||
#include "EditorPreferencesPageGeneral.h"
|
||||
#include "EditorPreferencesPageFiles.h"
|
||||
@@ -23,6 +25,7 @@
|
||||
#include "EditorPreferencesPageViewportMovement.h"
|
||||
#include "EditorPreferencesPageViewportDebug.h"
|
||||
#include "EditorPreferencesPageExperimentalLighting.h"
|
||||
#include "EditorPreferencesPageAWS.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -42,6 +45,11 @@ CStdPreferencesClassDesc::CStdPreferencesClassDesc()
|
||||
};
|
||||
|
||||
m_pageCreators.push_back([]() { return new CEditorPreferencesPage_ExperimentalLighting(); });
|
||||
|
||||
if (AzToolsFramework::IsComponentWithServiceRegistered(AZ_CRC_CE("AWSCoreEditorService")))
|
||||
{
|
||||
m_pageCreators.push_back([]() { return new CEditorPreferencesPage_AWS(); });
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CStdPreferencesClassDesc::QueryInterface(const IID& riid, void** ppvObj)
|
||||
|
||||
@@ -586,6 +586,8 @@ set(FILES
|
||||
EditorPreferencesPageViewportDebug.cpp
|
||||
EditorPreferencesPageExperimentalLighting.h
|
||||
EditorPreferencesPageExperimentalLighting.cpp
|
||||
EditorPreferencesPageAWS.h
|
||||
EditorPreferencesPageAWS.cpp
|
||||
EditorPreferencesDialog.h
|
||||
EditorPreferencesDialog.cpp
|
||||
EditorPreferencesDialog.ui
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.4629 11.2764C20.6447 10.508 19.5748 10.0719 18.4419 10.0719C17.8965 10.0719 17.351 10.1758 16.8475 10.3834C16.5748 9.26204 15.9664 8.2237 15.1063 7.37226C13.8685 6.16779 12.6717 5.47607 10.4147 5.47607C7.92095 5.47607 6.586 6.16779 5.32725 7.37226C4.08949 8.57673 3.30673 10.1907 3.30673 11.8935C3.30673 12.1635 3.32771 12.4335 3.34869 12.7035C2.84519 12.8281 2.49509 13.0831 2.13844 13.4362C1.57201 13.9761 1.25732 14.7029 1.25732 15.4713C1.25732 17.1534 2.66292 18.5032 4.3832 18.5032L18.2741 18.524C20.7286 18.524 22.7426 16.5927 22.7426 14.2045C22.7217 13.1039 22.2811 12.0656 21.4629 11.2764ZM17.2975 16.6659L4.65419 16.6867C3.62622 16.6867 3.45969 16.0387 3.37771 15.6437C3.30673 15.3017 3.37861 14.7882 3.53455 14.5799C3.74825 14.2944 4.10093 14.1649 4.5273 14.1216C4.76182 14.0979 5.1687 14.0552 5.32721 13.8355C5.43211 13.6901 5.47406 13.5032 5.45308 13.3163C5.36917 12.901 5.32721 12.5272 5.32721 12.1119C5.32721 10.7413 5.6315 9.73925 6.63849 8.76321C7.64549 7.78717 8.98815 7.24724 10.4147 7.24724C11.8413 7.24724 12.9769 7.56395 13.9839 8.53999C14.865 9.39143 15.3895 10.4921 15.5154 11.655C15.5363 11.8627 15.6622 12.0703 15.872 12.1534C16.0608 12.2365 16.3126 12.2365 16.4804 12.1119C17.6342 11.3643 18.848 11.1981 19.876 12.1742C20.4424 12.7141 20.7426 13.4362 20.7426 14.2045C20.7426 15.9074 19.0808 16.6659 17.2975 16.6659Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -64,11 +64,13 @@ if (PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
Include/Public
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzQtComponents
|
||||
3rdParty::Qt::Core
|
||||
3rdParty::Qt::Widgets
|
||||
AZ::AzQtComponents
|
||||
Gem::AWSCore.Static
|
||||
PUBLIC
|
||||
AZ::AzToolsFramework
|
||||
3rdParty::AWSNativeSDK::AWSCore
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
namespace AWSCore
|
||||
{
|
||||
class AWSCoreEditorModule
|
||||
:public AZ::Module
|
||||
: public AZ::Module
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AWSCoreEditorModule, "{C1C9B898-848B-4C2F-A7AA-69642D12BCB5}", AZ::Module);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 <Framework/ServiceRequestJob.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionMetric.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
namespace ServiceAPI
|
||||
{
|
||||
//! Struct for storing the success response.
|
||||
struct AWSAtrributionSuccessResponse
|
||||
{
|
||||
//! Identify the expected property type and provide a location where the property value can be stored.
|
||||
//! @param key Name of the property.
|
||||
//! @param reader JSON reader to read the property.
|
||||
bool OnJsonKey(const char* key, AWSCore::JsonReader& reader);
|
||||
|
||||
AZStd::string result; //!< Processing result for the input record.
|
||||
};
|
||||
|
||||
// Service RequestJobs
|
||||
AWS_FEATURE_GEM_SERVICE(AWSAttribution);
|
||||
|
||||
//! POST request to send attribution metric to the backend.
|
||||
//! The path for this service API is "/prod/metrics".
|
||||
class AWSAttributionRequest
|
||||
: public AWSCore::ServiceRequest
|
||||
{
|
||||
public:
|
||||
SERVICE_REQUEST(AWSAttribution, HttpMethod::HTTP_POST, "/metrics");
|
||||
|
||||
bool UseAWSCredentials()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Request body for the service API request.
|
||||
struct Parameters
|
||||
{
|
||||
//! Build the service API request.
|
||||
//! @request Builder for generating the request.
|
||||
//! @return Whether the request is built successfully.
|
||||
bool BuildRequest(AWSCore::RequestBuilder& request);
|
||||
|
||||
//! Write to the service API request body.
|
||||
//! @param writer JSON writer for the serialization.
|
||||
//! @return Whether the serialization is successful.
|
||||
bool WriteJson(AWSCore::JsonWriter& writer) const;
|
||||
|
||||
AttributionMetric metric;
|
||||
};
|
||||
|
||||
AWSAtrributionSuccessResponse result;
|
||||
Parameters parameters; //! Request parameter.
|
||||
};
|
||||
|
||||
using AWSAttributionRequestJob = AWSCore::ServiceRequestJob<AWSAttributionRequest>;
|
||||
} // ServiceAPI
|
||||
} // AWSMetrics
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! Default metrics attribute keys
|
||||
static constexpr char AwsAttributionAttributeKeyVersion[] = "version";
|
||||
static constexpr char AwsAttributionAttributeKeyO3DEVersion[] = "o3de_version";
|
||||
static constexpr char AwsAttributionAttributeKeyPlatform[] = "platform";
|
||||
static constexpr char AwsAttributionAttributeKeyPlatformVersion[] = "platform_version";
|
||||
static constexpr char AwsAttributionAttributeKeyActiveAWSGems[] = "aws_gems";
|
||||
static constexpr char AwsAttributionAttributeKeyTimestamp[] = "timestamp";
|
||||
|
||||
} // namespace AWSCOre
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <Editor/Attribution/AWSAttributionServiceApi.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! Manages operational metrics for AWS gems
|
||||
class AWSAttributionManager
|
||||
{
|
||||
public:
|
||||
AWSAttributionManager();
|
||||
virtual ~AWSAttributionManager();
|
||||
|
||||
//! Perform initialization
|
||||
void Init();
|
||||
|
||||
//! Run metric check
|
||||
void MetricCheck();
|
||||
|
||||
protected:
|
||||
virtual void SubmitMetric(AttributionMetric& metric);
|
||||
virtual void UpdateMetric(AttributionMetric& metric);
|
||||
void UpdateLastSend();
|
||||
void SetApiEndpointAndRegion(ServiceAPI::AWSAttributionRequestJob::Config* config);
|
||||
|
||||
private:
|
||||
bool ShouldGenerateMetric() const;
|
||||
|
||||
AZStd::string GetEngineVersion() const;
|
||||
AZStd::string GetPlatform() const;
|
||||
void GetActiveAWSGems(AZStd::vector<AZStd::string>& gemNames);
|
||||
|
||||
void SaveSettingsRegistryFile();
|
||||
|
||||
AZStd::unique_ptr<AZ::SettingsRegistryImpl> m_settingsRegistry;
|
||||
};
|
||||
|
||||
} // namespace AWSCore
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
|
||||
* a third party where indicated.
|
||||
*
|
||||
* 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 <Framework/JsonWriter.h>
|
||||
|
||||
#include <AzCore/JSON/document.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
//! Defines the operational metric sent periodically
|
||||
class AttributionMetric
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(MetricsAttribute, "{6483F481-0C18-4171-8B59-A44F2F28EAE5}")
|
||||
|
||||
AttributionMetric();
|
||||
AttributionMetric(const AZStd::string& timestamp);
|
||||
~AttributionMetric() = default;
|
||||
|
||||
void SetO3DEVersion(const AZStd::string& version);
|
||||
void SetPlatform(const AZStd::string& platform, const AZStd::string& platformVersion);
|
||||
void AddActiveGem(const AZStd::string& gemName);
|
||||
|
||||
//! Serialize the metrics object queue to a string.
|
||||
//! @return Serialized string.
|
||||
AZStd::string SerializeToJson();
|
||||
|
||||
//! Serialize the metrics object to JSON for the sending requests.
|
||||
//! @param writer JSON writer for the serialization.
|
||||
//! @return Whether the metrics event is serialized successfully.
|
||||
bool SerializeToJson(AWSCore::JsonWriter& writer) const;
|
||||
|
||||
//! Read from a JSON value to the metrics event.
|
||||
//! @param metricsObjVal JSON value to read from.
|
||||
//! @return Whether the metrics event is created successfully.
|
||||
bool ReadFromJson(rapidjson::Value& metricsObjVal);
|
||||
|
||||
//! Generates a UTC 8601 formatted timestamp
|
||||
static AZStd::string GenerateTimeStamp();
|
||||
private:
|
||||
AZStd::string m_version; //!< Schema version in use
|
||||
AZStd::string m_o3deVersion; //!< O3DE editor version in use
|
||||
AZStd::string m_platform; //!< OS type
|
||||
AZStd::string m_platformVersion; //!< OS subtype
|
||||
AZStd::string m_timestamp; //!< Metric generation time
|
||||
AZStd::vector<AZStd::string> m_activeAWSGems; //!< Active AWS Gems in project
|
||||
};
|
||||
} // namespace AWSCore
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 <AzCore/Component/Component.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
class AWSAttributionManager;
|
||||
|
||||
//! Attribution System Component. Responsible for instantiating and managing AWS Attribution Manager
|
||||
class AWSAttributionSystemComponent:
|
||||
public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AWSAttributionSystemComponent, "{366861EC-8337-4180-A202-4E4DF082A3A8}");
|
||||
|
||||
AWSAttributionSystemComponent();
|
||||
~AWSAttributionSystemComponent() = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);\
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<AWSAttributionManager> m_manager; //!< pointer to the attribution manager which handles operational metrics
|
||||
};
|
||||
} // namespace AWSCore
|
||||
@@ -113,7 +113,13 @@ namespace AWSCore
|
||||
/// needed. See it's use in ServiceRequestJobConfig.
|
||||
const AZStd::string GetServiceUrl() override
|
||||
{
|
||||
if (endpointOverride.has_value())
|
||||
{
|
||||
return endpointOverride.value().c_str();
|
||||
}
|
||||
|
||||
AZStd::string serviceUrl;
|
||||
|
||||
if (!ServiceTraitsType::RESTApiIdKeyName && !ServiceTraitsType::RESTApiStageKeyName)
|
||||
{
|
||||
AWSResourceMappingRequestBus::BroadcastResult(
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <AWSCoreEditorModule.h>
|
||||
#include <AWSCoreEditorSystemComponent.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionSystemComponent.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
@@ -19,6 +20,7 @@ namespace AWSCore
|
||||
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
|
||||
m_descriptors.insert(m_descriptors.end(), {
|
||||
AWSCoreEditorSystemComponent::CreateDescriptor(),
|
||||
AWSAttributionSystemComponent::CreateDescriptor()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,7 +30,8 @@ namespace AWSCore
|
||||
AZ::ComponentTypeList AWSCoreEditorModule::GetRequiredSystemComponents() const
|
||||
{
|
||||
return AZ::ComponentTypeList{
|
||||
azrtti_typeid<AWSCoreEditorSystemComponent>()
|
||||
azrtti_typeid<AWSCoreEditorSystemComponent>(),
|
||||
azrtti_typeid<AWSAttributionSystemComponent>()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 <Editor/Attribution/AWSCoreAttributionMetric.h>
|
||||
#include <Editor/Attribution/AWSAttributionServiceApi.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
namespace ServiceAPI
|
||||
{
|
||||
constexpr char AwsAttributionServiceResultResponseKey[] = "statusCode";
|
||||
|
||||
bool AWSAtrributionSuccessResponse::OnJsonKey(const char* key, AWSCore::JsonReader& reader)
|
||||
{
|
||||
if (strcmp(key, AwsAttributionServiceResultResponseKey) == 0)
|
||||
{
|
||||
return reader.Accept(result);
|
||||
}
|
||||
return reader.Ignore();
|
||||
}
|
||||
|
||||
bool AWSAttributionRequest::Parameters::BuildRequest(AWSCore::RequestBuilder& request)
|
||||
{
|
||||
bool ok = true;
|
||||
ok = ok && request.WriteJsonBodyParameter(*this);
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool AWSAttributionRequest::Parameters::WriteJson(AWSCore::JsonWriter& writer) const
|
||||
{
|
||||
bool ok = true;
|
||||
ok = ok && metric.SerializeToJson(writer);
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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 <Editor/Attribution/AWSCoreAttributionMetric.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionManager.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/PlatformId/PlatformId.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzCore/Jobs/JobFunction.h>
|
||||
#include <AzCore/IO/ByteContainerStream.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Module/ModuleManagerBus.h>
|
||||
#include <ResourceMapping/AWSResourceMappingUtils.h>
|
||||
|
||||
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
static constexpr const char* EngineVersionJsonKey = "O3DEVersion";
|
||||
|
||||
constexpr char EditorAWSPreferencesFileName[] = "editor_aws_preferences.setreg";
|
||||
constexpr char AWSAttributionSettingsPrefixKey[] = "/Amazon/AWS/Preferences";
|
||||
constexpr char AWSAttributionEnabledKey[] = "/Amazon/AWS/Preferences/AWSAttributionEnabled";
|
||||
constexpr char AWSAttributionDelaySecondsKey[] = "/Amazon/AWS/Preferences/AWSAttributionDelaySeconds";
|
||||
constexpr char AWSAttributionLastTimeStampKey[] = "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp";
|
||||
constexpr char AWSAttributionApiId[] = "xbzx78kvbk";
|
||||
constexpr char AWSAttributionChinaApiId[] = "";
|
||||
constexpr char AWSAttributionApiStage[] = "prod";
|
||||
|
||||
AWSAttributionManager::AWSAttributionManager()
|
||||
{
|
||||
m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
|
||||
}
|
||||
|
||||
AWSAttributionManager::~AWSAttributionManager()
|
||||
{
|
||||
m_settingsRegistry.reset();
|
||||
}
|
||||
|
||||
void AWSAttributionManager::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void AWSAttributionManager::MetricCheck()
|
||||
{
|
||||
if (ShouldGenerateMetric())
|
||||
{
|
||||
// 1. Gather metadata and assemble metric
|
||||
AttributionMetric metric;
|
||||
UpdateMetric(metric);
|
||||
// 2. Identify region and chose attribution endpoint
|
||||
|
||||
// 3. Post metric
|
||||
SubmitMetric(metric);
|
||||
}
|
||||
}
|
||||
|
||||
bool AWSAttributionManager::ShouldGenerateMetric() const
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ_Assert(fileIO, "File IO is not initialized.");
|
||||
|
||||
// Resolve path to editor_aws_preferences.setreg
|
||||
AZStd::string editorAWSPreferencesFilePath =
|
||||
AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName);
|
||||
AZStd::array<char, AZ::IO::MaxPathLength> resolvedPathAWSPreference{};
|
||||
if (!fileIO->ResolvePath(editorAWSPreferencesFilePath.c_str(), resolvedPathAWSPreference.data(), resolvedPathAWSPreference.size()))
|
||||
{
|
||||
AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileIO->Exists(resolvedPathAWSPreference.data()))
|
||||
{
|
||||
m_settingsRegistry->MergeSettingsFile(resolvedPathAWSPreference.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
|
||||
}
|
||||
|
||||
bool awsAttributionEnabled = false;
|
||||
if (!m_settingsRegistry->Get(awsAttributionEnabled, AWSAttributionEnabledKey))
|
||||
{
|
||||
// If not found default to sending the metric.
|
||||
awsAttributionEnabled = true;
|
||||
}
|
||||
|
||||
if (!awsAttributionEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If delayInSeconds is not found, set default to a day
|
||||
AZ::u64 delayInSeconds = 0;
|
||||
if (!m_settingsRegistry->Get(delayInSeconds, AWSAttributionDelaySecondsKey))
|
||||
{
|
||||
AZ_Warning("AWSAttributionManager", false, "AWSAttribution delay key not found. Defaulting to delay to day");
|
||||
delayInSeconds = 86400;
|
||||
m_settingsRegistry->Set(AWSAttributionDelaySecondsKey, delayInSeconds);
|
||||
}
|
||||
|
||||
AZ::u64 lastSendTimeStampSeconds = 0;
|
||||
if (!m_settingsRegistry->Get(lastSendTimeStampSeconds, AWSAttributionLastTimeStampKey))
|
||||
{
|
||||
// If last time stamp not found, assume this is the first attempt at sending.
|
||||
return true;
|
||||
}
|
||||
|
||||
AZStd::chrono::seconds lastSendTimeStamp = AZStd::chrono::seconds(lastSendTimeStampSeconds);
|
||||
AZStd::chrono::seconds secondsSinceLastSend =
|
||||
AZStd::chrono::duration_cast<AZStd::chrono::seconds>(AZStd::chrono::system_clock::now().time_since_epoch()) - lastSendTimeStamp;
|
||||
if (secondsSinceLastSend.count() >= delayInSeconds)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AWSAttributionManager::SaveSettingsRegistryFile()
|
||||
{
|
||||
AZ::Job* job = AZ::CreateJobFunction(
|
||||
[this]()
|
||||
{
|
||||
AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance();
|
||||
AZ_Assert(fileIO, "File IO is not initialized.");
|
||||
|
||||
// Resolve path to editor_aws_preferences.setreg
|
||||
AZStd::string editorPreferencesFilePath = AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName);
|
||||
AZStd::array<char, AZ::IO::MaxPathLength> resolvedPath {};
|
||||
fileIO->ResolvePath(editorPreferencesFilePath.c_str(), resolvedPath.data(), resolvedPath.size());
|
||||
|
||||
AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings;
|
||||
dumperSettings.m_prettifyOutput = true;
|
||||
dumperSettings.m_jsonPointerPrefix = AWSAttributionSettingsPrefixKey;
|
||||
|
||||
AZStd::string stringBuffer;
|
||||
AZ::IO::ByteContainerStream stringStream(&stringBuffer);
|
||||
if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream(
|
||||
*m_settingsRegistry, AWSAttributionSettingsPrefixKey, stringStream, dumperSettings))
|
||||
{
|
||||
AZ_Warning(
|
||||
"AWSAttributionManager", false, R"(Unable to save changes to the Editor AWS Preferences registry file at "%s"\n)",
|
||||
resolvedPath.data());
|
||||
return;
|
||||
}
|
||||
|
||||
bool saved {};
|
||||
constexpr auto configurationMode =
|
||||
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode))
|
||||
{
|
||||
saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size();
|
||||
}
|
||||
|
||||
AZ_Warning(
|
||||
"AWSAttributionManager", saved, R"(Unable to save Editor AWS Preferences registry file to path "%s"\n)",
|
||||
editorPreferencesFilePath.c_str());
|
||||
},
|
||||
true);
|
||||
job->Start();
|
||||
|
||||
}
|
||||
|
||||
void AWSAttributionManager::UpdateLastSend()
|
||||
{
|
||||
if (!m_settingsRegistry->Set(AWSAttributionLastTimeStampKey,
|
||||
AZStd::chrono::duration_cast<AZStd::chrono::seconds>(AZStd::chrono::system_clock::now().time_since_epoch()).count()))
|
||||
{
|
||||
AZ_Warning("AWSAttributionManager", true, "Failed to set AWSAttributionLastTimeStamp");
|
||||
return;
|
||||
}
|
||||
SaveSettingsRegistryFile();
|
||||
}
|
||||
|
||||
void AWSAttributionManager::SetApiEndpointAndRegion(AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config)
|
||||
{
|
||||
// Get default config for the process to check the region.
|
||||
// Assumption to determine China region is the default profile is set to China region.
|
||||
auto profile_name = Aws::Auth::GetConfigProfileName();
|
||||
Aws::Client::ClientConfiguration clientConfig(profile_name.c_str());
|
||||
AZStd::string apiId = AWSAttributionApiId;
|
||||
|
||||
if (clientConfig.region == Aws::Region::CN_NORTH_1 || clientConfig.region == Aws::Region::CN_NORTHWEST_1)
|
||||
{
|
||||
config->region = Aws::Region::CN_NORTH_1;
|
||||
apiId = AWSAttributionChinaApiId;
|
||||
}
|
||||
|
||||
config->region = Aws::Region::US_WEST_2;
|
||||
config->endpointOverride =
|
||||
AWSResourceMappingUtils::FormatRESTApiUrl(apiId, config->region.value().c_str(), AWSAttributionApiStage).c_str();
|
||||
}
|
||||
|
||||
AZStd::string AWSAttributionManager::GetEngineVersion() const
|
||||
{
|
||||
AZStd::string engineVersion;
|
||||
auto engineSettingsPath = AZ::IO::FixedMaxPath{ AZ::Utils::GetEnginePath() } / "engine.json";
|
||||
if (AZ::IO::SystemFile::Exists(engineSettingsPath.c_str()))
|
||||
{
|
||||
AZ::SettingsRegistryImpl settingsRegistry;
|
||||
if (settingsRegistry.MergeSettingsFile(
|
||||
engineSettingsPath.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, AZ::SettingsRegistryMergeUtils::EngineSettingsRootKey))
|
||||
{
|
||||
settingsRegistry.Get(engineVersion, AZ::SettingsRegistryInterface::FixedValueString(AZ::SettingsRegistryMergeUtils::EngineSettingsRootKey) + "/" + EngineVersionJsonKey);
|
||||
}
|
||||
}
|
||||
return engineVersion;
|
||||
}
|
||||
|
||||
AZStd::string AWSAttributionManager::GetPlatform() const
|
||||
{
|
||||
return AZ::GetPlatformName(AZ::g_currentPlatform);
|
||||
}
|
||||
|
||||
void AWSAttributionManager::GetActiveAWSGems(AZStd::vector<AZStd::string>& gems)
|
||||
{
|
||||
AZ::ModuleManagerRequestBus::Broadcast(
|
||||
&AZ::ModuleManagerRequestBus::Events::EnumerateModules,
|
||||
[this, &gems](const AZ::ModuleData& moduleData)
|
||||
{
|
||||
AZ::Entity* moduleEntity = moduleData.GetEntity();
|
||||
auto moduleEntityName = moduleEntity->GetName();
|
||||
if (moduleEntityName.contains("AWS"))
|
||||
gems.push_back(moduleEntityName.substr(0, moduleEntityName.find_last_of(".")));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void AWSAttributionManager::UpdateMetric(AttributionMetric& metric)
|
||||
{
|
||||
AZStd::string engineVersion = this->GetEngineVersion();
|
||||
metric.SetO3DEVersion(engineVersion);
|
||||
|
||||
AZStd::string platform = this->GetPlatform();
|
||||
metric.SetPlatform(platform, "");
|
||||
|
||||
AZStd::vector<AZStd::string> gemNames;
|
||||
GetActiveAWSGems(gemNames);
|
||||
for (AZStd::string& gemName : gemNames)
|
||||
{
|
||||
metric.AddActiveGem(gemName);
|
||||
}
|
||||
}
|
||||
|
||||
void AWSAttributionManager::SubmitMetric(AttributionMetric& metric)
|
||||
{
|
||||
AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config = ServiceAPI::AWSAttributionRequestJob::GetDefaultConfig();
|
||||
SetApiEndpointAndRegion(config);
|
||||
|
||||
ServiceAPI::AWSAttributionRequestJob* requestJob = ServiceAPI::AWSAttributionRequestJob::Create(
|
||||
[this](ServiceAPI::AWSAttributionRequestJob* successJob)
|
||||
{
|
||||
AZ_UNUSED(successJob);
|
||||
|
||||
UpdateLastSend();
|
||||
AZ_Printf("AWSAttributionManager", "AWSAttribution metric submit success");
|
||||
|
||||
}, {}, config);
|
||||
|
||||
requestJob->parameters.metric = metric;
|
||||
requestJob->Start();
|
||||
}
|
||||
|
||||
} // namespace AWSCore
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 <Editor/Attribution/AWSCoreAttributionMetric.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionConstant.h>
|
||||
#include <Framework/JsonWriter.h>
|
||||
#include <sstream>
|
||||
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
AttributionMetric::AttributionMetric(const AZStd::string& timestamp)
|
||||
: m_version("1.1")
|
||||
, m_timestamp(timestamp)
|
||||
{
|
||||
}
|
||||
|
||||
AttributionMetric::AttributionMetric()
|
||||
: m_version("1.1")
|
||||
{
|
||||
m_timestamp = AttributionMetric::GenerateTimeStamp();
|
||||
}
|
||||
|
||||
void AttributionMetric::SetO3DEVersion(const AZStd::string& version)
|
||||
{
|
||||
m_o3deVersion = version;
|
||||
}
|
||||
|
||||
void AttributionMetric::SetPlatform(const AZStd::string& platform, const AZStd::string& platformVersion)
|
||||
{
|
||||
m_platform = platform;
|
||||
m_platformVersion = platformVersion;
|
||||
}
|
||||
|
||||
void AttributionMetric::AddActiveGem(const AZStd::string& gemName)
|
||||
{
|
||||
m_activeAWSGems.push_back(gemName);
|
||||
}
|
||||
|
||||
AZStd::string AttributionMetric::SerializeToJson()
|
||||
{
|
||||
std::stringstream stringStream;
|
||||
AWSCore::JsonOutputStream jsonStream{stringStream};
|
||||
AWSCore::JsonWriter writer{jsonStream};
|
||||
|
||||
SerializeToJson(writer);
|
||||
|
||||
return stringStream.str().c_str();
|
||||
}
|
||||
|
||||
bool AttributionMetric::SerializeToJson(AWSCore::JsonWriter& writer) const
|
||||
{
|
||||
bool ok = true;
|
||||
ok = ok && writer.StartObject();
|
||||
|
||||
writer.Write(AwsAttributionAttributeKeyVersion, m_version.c_str());
|
||||
writer.Write(AwsAttributionAttributeKeyO3DEVersion, m_o3deVersion.c_str());
|
||||
writer.Write(AwsAttributionAttributeKeyPlatform, m_platform.c_str());
|
||||
writer.Write(AwsAttributionAttributeKeyPlatformVersion, m_platformVersion.c_str());
|
||||
|
||||
if (m_activeAWSGems.size() > 0)
|
||||
{
|
||||
writer.Key(AwsAttributionAttributeKeyActiveAWSGems);
|
||||
writer.StartArray(); // to store Array of objects
|
||||
for (auto& iter : m_activeAWSGems)
|
||||
{
|
||||
writer.String(iter.c_str());
|
||||
}
|
||||
writer.EndArray();
|
||||
}
|
||||
|
||||
writer.Write(AwsAttributionAttributeKeyTimestamp, m_timestamp.c_str());
|
||||
|
||||
ok = ok && writer.EndObject();
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool AttributionMetric::ReadFromJson(rapidjson::Value& metricsObjVal)
|
||||
{
|
||||
AZ_UNUSED(metricsObjVal);
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string AttributionMetric::GenerateTimeStamp()
|
||||
{
|
||||
// Timestamp format is using the UTC ISO8601 format
|
||||
// TODO: Move to a general util as Metrics has similar requirement
|
||||
time_t now;
|
||||
time(&now);
|
||||
char buffer[50];
|
||||
strftime(buffer, sizeof(buffer), "%FT%TZ", gmtime(&now));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace AWSCore
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 <Editor/Attribution/AWSCoreAttributionManager.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionSystemComponent.h>
|
||||
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/EditContextConstants.inl>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
|
||||
AWSAttributionSystemComponent::AWSAttributionSystemComponent()
|
||||
: m_manager(AZStd::make_unique<AWSAttributionManager>())
|
||||
{
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<AWSAttributionSystemComponent, AZ::Component>()->Version(0);
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
ec->Class<AWSAttributionSystemComponent>("AWSCoreAttributions", "Generates operation metrics for AWSCore gem")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("AWSCoreAttributionService"));
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("AWSCoreAttributionService"));
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC_CE("AWSCoreService"));
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
AZ_UNUSED(dependent);
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::Init()
|
||||
{
|
||||
// load config if required - ie check if attributions should be generated and pass to manager
|
||||
m_manager->Init();
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::Activate()
|
||||
{
|
||||
m_manager->MetricCheck();
|
||||
}
|
||||
|
||||
void AWSAttributionSystemComponent::Deactivate()
|
||||
{
|
||||
m_manager.reset();
|
||||
}
|
||||
|
||||
} // namespace AWSCore
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 <Editor/Attribution/AWSCoreAttributionConstant.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionMetric.h>
|
||||
#include <Editor/Attribution/AWSAttributionServiceApi.h>
|
||||
#include <Framework/JsonObjectHandler.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
using namespace AWSCore;
|
||||
|
||||
namespace AWSCoreUnitTest
|
||||
{
|
||||
class JsonReaderMock
|
||||
: public AWSCore::JsonReader
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD0(Ignore, bool());
|
||||
MOCK_METHOD1(Accept, bool(bool& target));
|
||||
MOCK_METHOD1(Accept, bool(AZStd::string& target));
|
||||
MOCK_METHOD1(Accept, bool(int& target));
|
||||
MOCK_METHOD1(Accept, bool(unsigned& target));
|
||||
MOCK_METHOD1(Accept, bool(int64_t& target));
|
||||
MOCK_METHOD1(Accept, bool(uint64_t& target));
|
||||
MOCK_METHOD1(Accept, bool(double& target));
|
||||
MOCK_METHOD1(Accept, bool(AWSCore::JsonKeyHandler keyHandler));
|
||||
MOCK_METHOD1(Accept, bool(AWSCore::JsonArrayHandler arrayHandler));
|
||||
};
|
||||
|
||||
class AWSAttributionServiceApiTest
|
||||
: public UnitTest::ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
testing::NiceMock<JsonReaderMock> JsonReader;
|
||||
};
|
||||
|
||||
TEST_F(AWSAttributionServiceApiTest, AWSAtrributionSuccessResponse_Serialization)
|
||||
{
|
||||
ServiceAPI::AWSAtrributionSuccessResponse response;
|
||||
response.result = "ok";
|
||||
|
||||
EXPECT_CALL(JsonReader, Accept(response.result)).Times(1);
|
||||
EXPECT_CALL(JsonReader, Ignore()).Times(0);
|
||||
|
||||
response.OnJsonKey("statusCode", JsonReader);
|
||||
}
|
||||
|
||||
TEST_F(AWSAttributionServiceApiTest, AWSAtrributionSuccessResponse_Serialization_Ignore)
|
||||
{
|
||||
ServiceAPI::AWSAtrributionSuccessResponse response;
|
||||
response.result = "ok";
|
||||
|
||||
EXPECT_CALL(JsonReader, Accept(response.result)).Times(0);
|
||||
EXPECT_CALL(JsonReader, Ignore()).Times(1);
|
||||
|
||||
response.OnJsonKey("", JsonReader);
|
||||
}
|
||||
|
||||
TEST_F(AWSAttributionServiceApiTest, BuildRequestBody_PostProducerEventsRequest_SerializedMetricsQueue)
|
||||
{
|
||||
ServiceAPI::AWSAttributionRequest request;
|
||||
request.parameters.metric = AttributionMetric();
|
||||
|
||||
AWSCore::RequestBuilder requestBuilder{};
|
||||
EXPECT_TRUE(request.parameters.BuildRequest(requestBuilder));
|
||||
std::shared_ptr<Aws::StringStream> bodyContent = requestBuilder.GetBodyContent();
|
||||
EXPECT_TRUE(bodyContent != nullptr);
|
||||
|
||||
AZStd::string bodyString;
|
||||
std::istreambuf_iterator<AZStd::string::value_type> eos;
|
||||
bodyString = AZStd::string{ std::istreambuf_iterator<AZStd::string::value_type>(*bodyContent), eos };
|
||||
AZ_Printf("AWSAttributionServiceApiTest", bodyString.c_str());
|
||||
EXPECT_TRUE(bodyString.find(AZStd::string::format("{\"%s\":\"1.1\"", AwsAttributionAttributeKeyVersion)) != AZStd::string::npos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
/*
|
||||
* 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 <Editor/Attribution/AWSCoreAttributionManager.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionMetric.h>
|
||||
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Settings/SettingsRegistry.h>
|
||||
#include <AzCore/Settings/SettingsRegistryImpl.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/Component/ComponentBus.h>
|
||||
#include <AzCore/Jobs/JobManager.h>
|
||||
#include <AzCore/Jobs/JobManagerBus.h>
|
||||
#include <AzCore/Jobs/JobContext.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Module/ModuleManagerBus.h>
|
||||
|
||||
#include <TestFramework/AWSCoreFixture.h>
|
||||
|
||||
|
||||
using namespace AWSCore;
|
||||
|
||||
namespace AWSAttributionUnitTest
|
||||
{
|
||||
class ModuleDataMock:
|
||||
public AZ::ModuleData
|
||||
{
|
||||
public:
|
||||
AZStd::shared_ptr<AZ::Entity> m_entity;
|
||||
ModuleDataMock(AZStd::string name)
|
||||
{
|
||||
m_entity = AZStd::make_shared<AZ::Entity>();
|
||||
m_entity->SetName(name);
|
||||
}
|
||||
virtual ~ModuleDataMock()
|
||||
{
|
||||
m_entity.reset();
|
||||
}
|
||||
|
||||
AZ::DynamicModuleHandle* GetDynamicModuleHandle() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
/// Get the handle to the module class
|
||||
AZ::Module* GetModule() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
/// Get the entity this module uses as a System Entity
|
||||
AZ::Entity* GetEntity() const override
|
||||
{
|
||||
return m_entity.get();
|
||||
}
|
||||
/// Get the debug name of the module
|
||||
const char* GetDebugName() const override
|
||||
{
|
||||
return m_entity->GetName().c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class ModuleManagerRequestBusMock
|
||||
: public AZ::ModuleManagerRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
|
||||
void EnumerateModulesMock(AZ::ModuleManagerRequests::EnumerateModulesCallback perModuleCallback)
|
||||
{
|
||||
auto data = ModuleDataMock("AWSCore.Editor.dll");
|
||||
perModuleCallback(data);
|
||||
data = ModuleDataMock("AWSClientAuth.so");
|
||||
perModuleCallback(data);
|
||||
}
|
||||
|
||||
ModuleManagerRequestBusMock()
|
||||
{
|
||||
AZ::ModuleManagerRequestBus::Handler::BusConnect();
|
||||
ON_CALL(*this, EnumerateModules(testing::_)).WillByDefault(testing::Invoke(this, &ModuleManagerRequestBusMock::EnumerateModulesMock));
|
||||
}
|
||||
|
||||
~ModuleManagerRequestBusMock()
|
||||
{
|
||||
AZ::ModuleManagerRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD1(EnumerateModules, void(AZ::ModuleManagerRequests::EnumerateModulesCallback perModuleCallback));
|
||||
MOCK_METHOD3(LoadDynamicModule, AZ::ModuleManagerRequests::LoadModuleOutcome(const char* modulePath, AZ::ModuleInitializationSteps lastStepToPerform, bool maintainReference));
|
||||
MOCK_METHOD3(LoadDynamicModules, AZ::ModuleManagerRequests::LoadModulesResult(const AZ::ModuleDescriptorList& modules, AZ::ModuleInitializationSteps lastStepToPerform, bool maintainReferences));
|
||||
MOCK_METHOD2(LoadStaticModules, AZ::ModuleManagerRequests::LoadModulesResult(AZ::CreateStaticModulesCallback staticModulesCb, AZ::ModuleInitializationSteps lastStepToPerform));
|
||||
MOCK_METHOD1(IsModuleLoaded, bool(const char* modulePath));
|
||||
};
|
||||
|
||||
class AWSAttributionManagerMock
|
||||
: public AWSAttributionManager
|
||||
{
|
||||
public:
|
||||
using AWSAttributionManager::SubmitMetric;
|
||||
using AWSAttributionManager::UpdateMetric;
|
||||
using AWSAttributionManager::SetApiEndpointAndRegion;
|
||||
|
||||
|
||||
AWSAttributionManagerMock()
|
||||
{
|
||||
ON_CALL(*this, SubmitMetric(testing::_)).WillByDefault(testing::Invoke(this, &AWSAttributionManagerMock::SubmitMetricMock));
|
||||
}
|
||||
|
||||
MOCK_METHOD1(SubmitMetric, void(AttributionMetric& metric));
|
||||
|
||||
void SubmitMetricMock(AttributionMetric& metric)
|
||||
{
|
||||
AZ_UNUSED(metric);
|
||||
UpdateLastSend();
|
||||
}
|
||||
};
|
||||
|
||||
class AttributionManagerTest
|
||||
: public AWSCoreFixture
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~AttributionManagerTest() = default;
|
||||
|
||||
protected:
|
||||
AZStd::shared_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
AZStd::unique_ptr<AZ::JsonRegistrationContext> m_registrationContext;
|
||||
AZStd::shared_ptr<AZ::SettingsRegistryImpl> m_settingsRegistry;
|
||||
AZStd::unique_ptr<AZ::JobContext> m_jobContext;
|
||||
AZStd::unique_ptr<AZ::JobCancelGroup> m_jobCancelGroup;
|
||||
AZStd::unique_ptr<AZ::JobManager> m_jobManager;
|
||||
AZStd::array<char, AZ::IO::MaxPathLength> m_resolvedSettingsPath;
|
||||
ModuleManagerRequestBusMock m_moduleManagerRequestBusMock;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
AWSCoreFixture::SetUp();
|
||||
|
||||
char rootPath[AZ_MAX_PATH_LEN];
|
||||
AZ::Utils::GetExecutableDirectory(rootPath, AZ_MAX_PATH_LEN);
|
||||
m_localFileIO->SetAlias("@user@", AZ_TRAIT_TEST_ROOT_FOLDER);
|
||||
|
||||
m_localFileIO->ResolvePath("@user@/Registry/", m_resolvedSettingsPath.data(), m_resolvedSettingsPath.size());
|
||||
AZ::IO::SystemFile::CreateDir(m_resolvedSettingsPath.data());
|
||||
|
||||
m_localFileIO->ResolvePath("@user@/Registry/editor_aws_preferences.setreg", m_resolvedSettingsPath.data(), m_resolvedSettingsPath.size());
|
||||
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
|
||||
AZ::JsonSystemComponent::Reflect(m_registrationContext.get());
|
||||
|
||||
m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
|
||||
|
||||
m_settingsRegistry->SetContext(m_serializeContext.get());
|
||||
m_settingsRegistry->SetContext(m_registrationContext.get());
|
||||
|
||||
AZ::SettingsRegistry::Register(m_settingsRegistry.get());
|
||||
|
||||
AZ::JobManagerDesc jobManagerDesc;
|
||||
AZ::JobManagerThreadDesc threadDesc;
|
||||
|
||||
m_jobManager.reset(aznew AZ::JobManager(jobManagerDesc));
|
||||
m_jobCancelGroup.reset(aznew AZ::JobCancelGroup());
|
||||
jobManagerDesc.m_workerThreads.push_back(threadDesc);
|
||||
m_jobContext.reset(aznew AZ::JobContext(*m_jobManager, *m_jobCancelGroup));
|
||||
AZ::JobContext::SetGlobalContext(m_jobContext.get());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
AZ::JobContext::SetGlobalContext(nullptr);
|
||||
m_jobContext.reset();
|
||||
m_jobCancelGroup.reset();
|
||||
m_jobManager.reset();
|
||||
|
||||
AZ::SettingsRegistry::Unregister(m_settingsRegistry.get());
|
||||
|
||||
m_settingsRegistry.reset();
|
||||
m_serializeContext.reset();
|
||||
m_registrationContext.reset();
|
||||
|
||||
m_localFileIO->ResolvePath("@user@/Registry/", m_resolvedSettingsPath.data(), m_resolvedSettingsPath.size());
|
||||
AZ::IO::SystemFile::DeleteDir(m_resolvedSettingsPath.data());
|
||||
|
||||
delete AZ::IO::FileIOBase::GetInstance();
|
||||
AZ::IO::FileIOBase::SetInstance(nullptr);
|
||||
|
||||
AWSCoreFixture::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(AttributionManagerTest, MetricsSettings_AttributionDisabled_SkipsSend)
|
||||
{
|
||||
// GIVEN
|
||||
AWSAttributionManagerMock manager;
|
||||
manager.Init();
|
||||
|
||||
CreateFile(m_resolvedSettingsPath.data(), R"({
|
||||
"Amazon": {
|
||||
"AWS": {
|
||||
"Preferences": {
|
||||
"AWSAttributionEnabled": false,
|
||||
"AWSAttributionDelaySeconds": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(0);
|
||||
EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(0);
|
||||
|
||||
// WHEN
|
||||
manager.MetricCheck();
|
||||
|
||||
// THEN
|
||||
m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
|
||||
AZ::u64 timeStamp = 0;
|
||||
m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp");
|
||||
ASSERT_TRUE(timeStamp == 0);
|
||||
|
||||
RemoveFile(m_resolvedSettingsPath.data());
|
||||
}
|
||||
|
||||
TEST_F(AttributionManagerTest, AttributionEnabled_NoPreviousTimeStamp_SendSuccess)
|
||||
{
|
||||
// GIVEN
|
||||
AWSAttributionManagerMock manager;
|
||||
manager.Init();
|
||||
|
||||
CreateFile(m_resolvedSettingsPath.data(), R"({
|
||||
"Amazon": {
|
||||
"AWS": {
|
||||
"Preferences": {
|
||||
"AWSAttributionEnabled": true,
|
||||
"AWSAttributionDelaySeconds": 30,
|
||||
}
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1);
|
||||
EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1);
|
||||
|
||||
// WHEN
|
||||
manager.MetricCheck();
|
||||
|
||||
// THEN
|
||||
m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
|
||||
AZ::u64 timeStamp = 0;
|
||||
m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp");
|
||||
ASSERT_TRUE(timeStamp > 0);
|
||||
|
||||
|
||||
RemoveFile(m_resolvedSettingsPath.data());
|
||||
}
|
||||
|
||||
TEST_F(AttributionManagerTest, AttributionEnabled_ValidPreviousTimeStamp_SendSuccess)
|
||||
{
|
||||
// GIVEN
|
||||
AWSAttributionManagerMock manager;
|
||||
manager.Init();
|
||||
|
||||
CreateFile(m_resolvedSettingsPath.data(), R"({
|
||||
"Amazon": {
|
||||
"AWS": {
|
||||
"Preferences": {
|
||||
"AWSAttributionEnabled": true,
|
||||
"AWSAttributionDelaySeconds": 30,
|
||||
"AWSAttributionLastTimeStamp": 629400
|
||||
}
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1);
|
||||
EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1);
|
||||
|
||||
// WHEN
|
||||
manager.MetricCheck();
|
||||
|
||||
// THEN
|
||||
m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
|
||||
AZ::u64 timeStamp = 0;
|
||||
m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp");
|
||||
ASSERT_TRUE(timeStamp > 0);
|
||||
|
||||
RemoveFile(m_resolvedSettingsPath.data());
|
||||
}
|
||||
|
||||
TEST_F(AttributionManagerTest, AttributionEnabled_DelayNotSatisfied_SendFail)
|
||||
{
|
||||
// GIVEN
|
||||
AWSAttributionManagerMock manager;
|
||||
manager.Init();
|
||||
|
||||
|
||||
CreateFile(m_resolvedSettingsPath.data(), R"({
|
||||
"Amazon": {
|
||||
"AWS": {
|
||||
"Preferences": {
|
||||
"AWSAttributionEnabled": true,
|
||||
"AWSAttributionDelaySeconds": 300,
|
||||
"AWSAttributionLastTimeStamp": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
AZ::u64 delayInSeconds = AZStd::chrono::duration_cast<AZStd::chrono::seconds>(AZStd::chrono::system_clock::now().time_since_epoch()).count();
|
||||
ASSERT_TRUE(m_settingsRegistry->Set("/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp", delayInSeconds));
|
||||
|
||||
EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1);
|
||||
EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1);
|
||||
|
||||
// WHEN
|
||||
manager.MetricCheck();
|
||||
|
||||
// THEN
|
||||
m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
|
||||
AZ::u64 timeStamp = 0;
|
||||
m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp");
|
||||
ASSERT_TRUE(timeStamp == delayInSeconds);
|
||||
|
||||
RemoveFile(m_resolvedSettingsPath.data());
|
||||
}
|
||||
|
||||
TEST_F(AttributionManagerTest, AttributionEnabledNotFound_SendSuccess)
|
||||
{
|
||||
// GIVEN
|
||||
AWSAttributionManagerMock manager;
|
||||
manager.Init();
|
||||
|
||||
CreateFile(m_resolvedSettingsPath.data(), R"({
|
||||
"Amazon": {
|
||||
"AWS": {
|
||||
"Preferences": {
|
||||
}
|
||||
}
|
||||
}
|
||||
})");
|
||||
|
||||
EXPECT_CALL(manager, SubmitMetric(testing::_)).Times(1);
|
||||
EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1);
|
||||
|
||||
// WHEN
|
||||
manager.MetricCheck();
|
||||
|
||||
// THEN
|
||||
m_settingsRegistry->MergeSettingsFile(m_resolvedSettingsPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
|
||||
AZ::u64 timeStamp = 0;
|
||||
m_settingsRegistry->Get(timeStamp, "/Amazon/AWS/Preferences/AWSAttributionLastTimeStamp");
|
||||
ASSERT_TRUE(timeStamp != 0);
|
||||
|
||||
RemoveFile(m_resolvedSettingsPath.data());
|
||||
}
|
||||
|
||||
TEST_F(AttributionManagerTest, SetApiEndpointAndRegion_Success)
|
||||
{
|
||||
// GIVEN
|
||||
AWSAttributionManagerMock manager;
|
||||
AWSCore::ServiceAPI::AWSAttributionRequestJob::Config* config = aznew AWSCore::ServiceAPI::AWSAttributionRequestJob::Config();
|
||||
|
||||
// WHEN
|
||||
manager.SetApiEndpointAndRegion(config);
|
||||
|
||||
// THEN
|
||||
ASSERT_TRUE(config->region == Aws::Region::US_WEST_2);
|
||||
ASSERT_TRUE(config->endpointOverride->find("execute-api.us-west-2.amazonaws.com") != Aws::String::npos);
|
||||
|
||||
delete config;
|
||||
}
|
||||
|
||||
TEST_F(AttributionManagerTest, UpdateMetric_Success)
|
||||
{
|
||||
// GIVEN
|
||||
AWSAttributionManagerMock manager;
|
||||
AttributionMetric metric;
|
||||
|
||||
AZStd::array<char, AZ::IO::MaxPathLength> engineJsonPath;
|
||||
m_localFileIO->ResolvePath("@user@/Registry/engine.json", engineJsonPath.data(), engineJsonPath.size());
|
||||
CreateFile(engineJsonPath.data(), R"({"O3DEVersion": "1.0.0.0"})");
|
||||
|
||||
m_localFileIO->ResolvePath("@user@/Registry/", engineJsonPath.data(), engineJsonPath.size());
|
||||
m_settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder, engineJsonPath.data());
|
||||
|
||||
EXPECT_CALL(m_moduleManagerRequestBusMock, EnumerateModules(testing::_)).Times(1);
|
||||
|
||||
// WHEN
|
||||
manager.UpdateMetric(metric);
|
||||
|
||||
// THEN
|
||||
AZStd::string serializedMetricValue = metric.SerializeToJson();
|
||||
ASSERT_TRUE(serializedMetricValue.find("\"o3de_version\":\"1.0.0.0\"") != AZStd::string::npos);
|
||||
ASSERT_TRUE(serializedMetricValue.find(AZ::GetPlatformName(AZ::g_currentPlatform)) != AZStd::string::npos);
|
||||
ASSERT_TRUE(serializedMetricValue.find("AWSCore.Editor") != AZStd::string::npos);
|
||||
ASSERT_TRUE(serializedMetricValue.find("AWSClientAuth") != AZStd::string::npos);
|
||||
|
||||
RemoveFile(engineJsonPath.data());
|
||||
}
|
||||
|
||||
} // namespace AWSCoreUnitTest
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 <Editor/Attribution/AWSCoreAttributionMetric.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
namespace AWSCore
|
||||
{
|
||||
using AttributionMetricTest = UnitTest::ScopedAllocatorSetupFixture;
|
||||
|
||||
TEST_F(AttributionMetricTest, Contruction_Test)
|
||||
{
|
||||
AZStd::string timestamp = AttributionMetric::GenerateTimeStamp();
|
||||
AttributionMetric metric(timestamp);
|
||||
|
||||
AZStd::string serializedMetric = AZStd::string::format(
|
||||
"{\"version\":\"1.1\",\"o3de_version\":\"\",\"platform\":\"\",\"platform_version\":\"\",\"timestamp\":\"%s\"}", timestamp.c_str());
|
||||
ASSERT_EQ(metric.SerializeToJson(), serializedMetric);
|
||||
}
|
||||
|
||||
TEST_F(AttributionMetricTest, AddActiveGems)
|
||||
{
|
||||
AZStd::string timestamp = AttributionMetric::GenerateTimeStamp();
|
||||
AttributionMetric metric(timestamp);
|
||||
|
||||
AZStd::string gem1 = "AWSGem1";
|
||||
AZStd::string gem2 = "AWSGem2";
|
||||
|
||||
metric.AddActiveGem(gem1);
|
||||
metric.AddActiveGem(gem2);
|
||||
|
||||
AZStd::string serializedMetric = AZStd::string::format(
|
||||
"{\"version\":\"1.1\",\"o3de_version\":\"\",\"platform\":\"\",\"platform_version\":\"\",\"aws_gems\":[\"%s\",\"%s\"],\"timestamp\":\"%s\"}",
|
||||
gem1.c_str(), gem2.c_str(), timestamp.c_str());
|
||||
|
||||
AZStd::string actualValue = metric.SerializeToJson();
|
||||
ASSERT_EQ(actualValue, serializedMetric);
|
||||
}
|
||||
|
||||
} // namespace AWSCore
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
#include <Editor/Attribution/AWSCoreAttributionManager.h>
|
||||
#include <Editor/Attribution/AWSCoreAttributionSystemComponent.h>
|
||||
#include <TestFramework/AWSCoreFixture.h>
|
||||
|
||||
using namespace AWSCore;
|
||||
|
||||
namespace AWSCoreUnitTest
|
||||
{
|
||||
class AWSCoreSystemComponentMock : public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AWSCoreSystemComponentMock, "{5F48030D-EB59-4820-BC65-69EC7CC6C119}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<AWSCoreSystemComponentMock, AZ::Component>()->Version(0);
|
||||
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
ec->Class<AWSCoreSystemComponentMock>("AWSCoreMock", "Adds core support for working with AWS")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("AWSCoreService"));
|
||||
}
|
||||
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
AZ_UNUSED(incompatible);
|
||||
}
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
AZ_UNUSED(required);
|
||||
}
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
AZ_UNUSED(dependent);
|
||||
}
|
||||
|
||||
~AWSCoreSystemComponentMock() = default;
|
||||
|
||||
MOCK_METHOD0(Init, void());
|
||||
MOCK_METHOD0(Activate, void());
|
||||
MOCK_METHOD0(Deactivate, void());
|
||||
};
|
||||
|
||||
class AWSAttributionSystemComponentTest : public AWSCoreFixture
|
||||
{
|
||||
void SetUp() override
|
||||
{
|
||||
AWSCoreFixture::SetUp();
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
m_serializeContext->CreateEditContext();
|
||||
m_behaviorContext = AZStd::make_unique<AZ::BehaviorContext>();
|
||||
|
||||
m_awsCoreComponentDescriptor.reset(AWSCoreSystemComponentMock::CreateDescriptor());
|
||||
m_awsCoreComponentDescriptor->Reflect(m_serializeContext.get());
|
||||
m_awsCoreComponentDescriptor->Reflect(m_behaviorContext.get());
|
||||
|
||||
m_componentDescriptor.reset(AWSAttributionSystemComponent::CreateDescriptor());
|
||||
m_componentDescriptor->Reflect(m_serializeContext.get());
|
||||
m_componentDescriptor->Reflect(m_behaviorContext.get());
|
||||
|
||||
m_entity = aznew AZ::Entity();
|
||||
m_awsCoreSystemComponentMock = aznew testing::NiceMock<AWSCoreSystemComponentMock>();
|
||||
m_entity->AddComponent(m_awsCoreSystemComponentMock);
|
||||
m_attributionSystemsComponent.reset(m_entity->CreateComponent<AWSAttributionSystemComponent>());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_entity->Deactivate();
|
||||
m_entity->RemoveComponent(m_attributionSystemsComponent.get());
|
||||
m_entity->RemoveComponent(m_awsCoreSystemComponentMock);
|
||||
delete m_entity;
|
||||
m_entity = nullptr;
|
||||
|
||||
m_attributionSystemsComponent.reset();
|
||||
delete m_awsCoreSystemComponentMock;
|
||||
m_awsCoreComponentDescriptor.reset();
|
||||
m_componentDescriptor.reset();
|
||||
m_behaviorContext.reset();
|
||||
m_serializeContext.reset();
|
||||
AWSCoreFixture::TearDown();
|
||||
}
|
||||
|
||||
public:
|
||||
AZStd::unique_ptr<AWSAttributionSystemComponent> m_attributionSystemsComponent;
|
||||
testing::NiceMock<AWSCoreSystemComponentMock>* m_awsCoreSystemComponentMock;
|
||||
AZ::Entity* m_entity;
|
||||
|
||||
private:
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
AZStd::unique_ptr<AZ::BehaviorContext> m_behaviorContext;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_componentDescriptor;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_awsCoreComponentDescriptor;
|
||||
};
|
||||
|
||||
TEST_F(AWSAttributionSystemComponentTest, SystemComponentInitActivate_Success)
|
||||
{
|
||||
m_entity->Init();
|
||||
m_entity->Activate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -127,13 +127,40 @@ public:
|
||||
void TearDown() override
|
||||
{
|
||||
AZ::IO::FileIOBase::SetInstance(nullptr);
|
||||
delete m_localFileIO;
|
||||
AZ::IO::FileIOBase::SetInstance(m_otherFileIO);
|
||||
|
||||
if (m_otherFileIO)
|
||||
{
|
||||
delete m_localFileIO;
|
||||
AZ::IO::FileIOBase::SetInstance(m_otherFileIO);
|
||||
}
|
||||
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
}
|
||||
|
||||
bool CreateFile(const AZStd::string& filePath, const AZStd::string& content)
|
||||
{
|
||||
AZ::IO::HandleType fileHandle;
|
||||
if (!m_localFileIO->Open(filePath.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeText, fileHandle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_localFileIO->Write(fileHandle, content.c_str(), content.size());
|
||||
m_localFileIO->Close(fileHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoveFile(const AZStd::string& filePath)
|
||||
{
|
||||
if (m_localFileIO->Exists(filePath.c_str()))
|
||||
{
|
||||
return m_localFileIO->Remove(filePath.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ::IO::FileIOBase* m_localFileIO = nullptr;
|
||||
|
||||
private:
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
|
||||
set(FILES
|
||||
Include/Private/AWSCoreEditorSystemComponent.h
|
||||
Include/Private/Editor/Attribution/AWSCoreAttributionConstant.h
|
||||
Include/Private/Editor/Attribution/AWSCoreAttributionMetric.h
|
||||
Include/Private/Editor/Attribution/AWSCoreAttributionManager.h
|
||||
Include/Private/Editor/Attribution/AWSCoreAttributionSystemComponent.h
|
||||
Include/Private/Editor/Attribution/AWSAttributionServiceApi.h
|
||||
Include/Private/Editor/AWSCoreEditorManager.h
|
||||
Include/Private/Editor/Constants/AWSCoreEditorMenuLinks.h
|
||||
Include/Private/Editor/Constants/AWSCoreEditorMenuNames.h
|
||||
@@ -18,6 +23,10 @@ set(FILES
|
||||
Include/Private/Editor/UI/AWSCoreResourceMappingToolAction.h
|
||||
Source/AWSCoreEditorSystemComponent.cpp
|
||||
Source/Editor/AWSCoreEditorManager.cpp
|
||||
Source/Editor/Attribution/AWSCoreAttributionMetric.cpp
|
||||
Source/Editor/Attribution/AWSCoreAttributionManager.cpp
|
||||
Source/Editor/Attribution/AWSCoreAttributionSystemComponent.cpp
|
||||
Source/Editor/Attribution/AWSAttributionServiceApi.cpp
|
||||
Source/Editor/UI/AWSCoreEditorMenu.cpp
|
||||
Source/Editor/UI/AWSCoreResourceMappingToolAction.cpp
|
||||
)
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
|
||||
set(FILES
|
||||
Tests/AWSCoreEditorSystemComponentTest.cpp
|
||||
Tests/Editor/Attribution/AWSCoreAttributionManagerTest.cpp
|
||||
Tests/Editor/Attribution/AWSCoreAttributionMetricTest.cpp
|
||||
Tests/Editor/Attribution/AWSCoreAttributionSystemComponentTest.cpp
|
||||
Tests/Editor/Attribution/AWSAttributionServiceApiTest.cpp
|
||||
Tests/Editor/UI/AWSCoreEditorMenuTest.cpp
|
||||
Tests/Editor/UI/AWSCoreEditorUIFixture.h
|
||||
Tests/Editor/UI/AWSCoreResourceMappingToolActionTest.cpp
|
||||
|
||||
Reference in New Issue
Block a user