diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/Platform/Windows/TestEngine/JobRunner/TestImpactWin32_TestTargetExtension.cpp b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Platform/Windows/TestEngine/JobRunner/TestImpactWin32_TestTargetExtension.cpp new file mode 100644 index 0000000000..12c78f91cf --- /dev/null +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Platform/Windows/TestEngine/JobRunner/TestImpactWin32_TestTargetExtension.cpp @@ -0,0 +1,44 @@ +/* + * 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 +#include +#include + +namespace TestImpact +{ + AZStd::string GetTestTargetExtension(const TestTarget* testTarget) + { + static constexpr char* const standAloneExtension = ".exe"; + static constexpr char* const testRunnerExtension = ".dll"; + + switch (const auto launchMethod = testTarget->GetLaunchMethod(); launchMethod) + { + case LaunchMethod::StandAlone: + { + return standAloneExtension; + } + case LaunchMethod::TestRunner: + { + return testRunnerExtension; + } + default: + { + throw TestEngineException( + AZStd::string::format( + "Unexpected launch method for target %s: %u", + testTarget->GetName().c_str(), + aznumeric_cast(launchMethod))); + } + } + } +} diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/Platform/Windows/platform_windows_files.cmake b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Platform/Windows/platform_windows_files.cmake index 32f996cdf8..5f5e8fc3d1 100644 --- a/Code/Tools/TestImpactFramework/Runtime/Code/Source/Platform/Windows/platform_windows_files.cmake +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/Platform/Windows/platform_windows_files.cmake @@ -16,4 +16,5 @@ set(FILES Process/TestImpactWin32_Handle.h Process/TestImpactWin32_Pipe.cpp Process/TestImpactWin32_Pipe.h + TestEngine/JobRunner/TestImpactWin32_TestTargetExtension.cpp ) diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestJobInfoGenerator.cpp b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestJobInfoGenerator.cpp new file mode 100644 index 0000000000..7e8e65e940 --- /dev/null +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestJobInfoGenerator.cpp @@ -0,0 +1,194 @@ +/* + * 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 +#include +#include + +namespace TestImpact +{ + TestJobInfoGenerator::TestJobInfoGenerator( + const RepoPath& sourceDir, + const RepoPath& targetBinaryDir, + const RepoPath& cacheDir, + const RepoPath& artifactDir, + const RepoPath& testRunnerBinary, + const RepoPath& instrumentBinary) + : m_sourceDir(sourceDir) + , m_targetBinaryDir(targetBinaryDir) + , m_cacheDir(cacheDir) + , m_artifactDir(artifactDir) + , m_testRunnerBinary(testRunnerBinary) + , m_instrumentBinary(instrumentBinary) + { + } + + AZStd::string TestJobInfoGenerator::GenerateLaunchArgument(const TestTarget* testTarget) const + { + if (testTarget->GetLaunchMethod() == LaunchMethod::StandAlone) + { + return AZStd::string::format( + "%s%s %s", + (m_targetBinaryDir / testTarget->GetOutputName()).c_str(), + GetTestTargetExtension(testTarget).c_str(), + testTarget->GetCustomArgs().c_str()).c_str(); + } + else + { + return AZStd::string::format( + "\"%s\" \"%s%s\" %s", + m_testRunnerBinary.c_str(), + (m_targetBinaryDir / testTarget->GetOutputName()).c_str(), + GetTestTargetExtension(testTarget).c_str(), + testTarget->GetCustomArgs().c_str()).c_str(); + } + } + + RepoPath TestJobInfoGenerator::GenerateTargetEnumerationCacheFilePath(const TestTarget* testTarget) const + { + return AZStd::string::format("%s.cache", (m_artifactDir / testTarget->GetName()).c_str()); + } + + RepoPath TestJobInfoGenerator::GenerateTargetEnumerationArtifactFilePath(const TestTarget* testTarget) const + { + return AZStd::string::format("%s.Enumeration.xml", (m_artifactDir / testTarget->GetName()).c_str()); + } + + RepoPath TestJobInfoGenerator::GenerateTargetRunArtifactFilePath(const TestTarget* testTarget) const + { + return AZStd::string::format("%s.Run.xml", (m_artifactDir / testTarget->GetName()).c_str()); + } + + RepoPath TestJobInfoGenerator::GenerateTargetCoverageArtifactFilePath(const TestTarget* testTarget) const + { + return AZStd::string::format("%s.Coverage.xml", (m_artifactDir / testTarget->GetName()).c_str()); + } + + TestEnumerator::JobInfo TestJobInfoGenerator::GenerateTestEnumerationJobInfo( + const TestTarget* testTarget, + TestEnumerator::JobInfo::Id jobId, + TestEnumerator::JobInfo::CachePolicy cachePolicy) const + { + using Command = TestEnumerator::Command; + using JobInfo = TestEnumerator::JobInfo; + using JobData = TestEnumerator::JobData; + using Cache = TestEnumerator::JobData::Cache; + + const auto enumerationArtifact = GenerateTargetEnumerationArtifactFilePath(testTarget); + const Command args = + { + AZStd::string::format( + "%s --gtest_list_tests --gtest_output=xml:\"%s\"", + GenerateLaunchArgument(testTarget).c_str(), + enumerationArtifact.c_str()) + }; + + return JobInfo(jobId, args, JobData(enumerationArtifact, Cache{ cachePolicy, GenerateTargetEnumerationCacheFilePath(testTarget) })); + } + + TestRunner::JobInfo TestJobInfoGenerator::GenerateRegularTestRunJobInfo( + const TestTarget* testTarget, + TestRunner::JobInfo::Id jobId) const + { + using Command = TestRunner::Command; + using JobInfo = TestRunner::JobInfo; + using JobData = TestRunner::JobData; + + const auto runArtifact = GenerateTargetRunArtifactFilePath(testTarget); + const Command args = + { + AZStd::string::format( + "%s --gtest_output=xml:\"%s\"", + GenerateLaunchArgument(testTarget).c_str(), + runArtifact.c_str()) + }; + + return JobInfo(jobId, args, JobData(runArtifact)); + } + + InstrumentedTestRunner::JobInfo TestJobInfoGenerator::GenerateInstrumentedTestRunJobInfo( + const TestTarget* testTarget, + InstrumentedTestRunner::JobInfo::Id jobId, + CoverageLevel coverageLevel) const + { + using Command = InstrumentedTestRunner::Command; + using JobInfo = InstrumentedTestRunner::JobInfo; + using JobData = InstrumentedTestRunner::JobData; + + const auto coverageArtifact = GenerateTargetCoverageArtifactFilePath(testTarget); + const auto runArtifact = GenerateTargetRunArtifactFilePath(testTarget); + const Command args = + { + AZStd::string::format( + "\"%s\" " // 1. Instrumented test runner + "--coverage_level %s " // 2. Coverage level + "--export_type cobertura:\"%s\" " // 3. Test coverage artifact path + "--modules \"%s\" " // 4. Modules path + "--excluded_modules \"%s\" " // 5. Exclude modules + "--sources \"%s\" -- " // 6. Sources path + "%s " // 7. Launch command + "--gtest_output=xml:\"%s\"", // 8. Result artifact + + m_instrumentBinary.c_str(), // 1. Instrumented test runner + (coverageLevel == CoverageLevel::Line ? "line" : "source"), // 2. Coverage level + coverageArtifact.c_str(), // 3. Test coverage artifact path + m_targetBinaryDir.c_str(), // 4. Modules path + m_testRunnerBinary.c_str(), // 5. Exclude modules + m_sourceDir.c_str(), // 6. Sources path + GenerateLaunchArgument(testTarget).c_str(), // 7. Launch command + runArtifact.c_str()) // 8. Result artifact + }; + + return JobInfo(jobId, args, JobData(runArtifact, coverageArtifact)); + } + + AZStd::vector TestJobInfoGenerator::GenerateTestEnumerationJobInfos( + const AZStd::vector& testTargets, + TestEnumerator::JobInfo::CachePolicy cachePolicy) const + { + AZStd::vector jobInfos; + jobInfos.reserve(testTargets.size()); + for (size_t jobId = 0; jobId < testTargets.size(); jobId++) + { + jobInfos.push_back(GenerateTestEnumerationJobInfo(testTargets[jobId], { jobId }, cachePolicy)); + } + + return jobInfos; + } + + AZStd::vector TestJobInfoGenerator::GenerateRegularTestRunJobInfos( + const AZStd::vector& testTargets) const + { + AZStd::vector jobInfos; + jobInfos.reserve(testTargets.size()); + for (size_t jobId = 0; jobId < testTargets.size(); jobId++) + { + jobInfos.push_back(GenerateRegularTestRunJobInfo(testTargets[jobId], { jobId })); + } + + return jobInfos; + } + + AZStd::vector TestJobInfoGenerator::GenerateInstrumentedTestRunJobInfos( + const AZStd::vector& testTargets, + CoverageLevel coverageLevel) const + { + AZStd::vector jobInfos; + jobInfos.reserve(testTargets.size()); + for (size_t jobId = 0; jobId < testTargets.size(); jobId++) + { + jobInfos.push_back(GenerateInstrumentedTestRunJobInfo(testTargets[jobId], { jobId }, coverageLevel)); + } + + return jobInfos; + } +} diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestJobInfoGenerator.h b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestJobInfoGenerator.h new file mode 100644 index 0000000000..1bd06f6372 --- /dev/null +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestJobInfoGenerator.h @@ -0,0 +1,108 @@ +/* + * 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 +#include +#include +#include + +#include + +namespace TestImpact +{ + class TestTarget; + + //! Generates job information for the different test job runner types. + class TestJobInfoGenerator + { + public: + //! Configures the test job info generator with the necessary path information for launching test targets. + //! @param sourceDir Root path where source files are found (including subfolders). + //! @param targetBinaryDir Path to where the test target binaries are found. + //! @param cacheDir Path to the persistent folder where test target enumerations are cached. + //! @param artifactDir Path to the transient directory where test artifacts are produced. + //! @param testRunnerBinary Path to the binary responsible for launching test targets that have the TestRunner launch method. + //! @param instrumentBinary Path to the binary responsible for launching test targets with test coverage instrumentation. + TestJobInfoGenerator( + const RepoPath& sourceDir, + const RepoPath& targetBinaryDir, + const RepoPath& cacheDir, + const RepoPath& artifactDir, + const RepoPath& testRunnerBinary, + const RepoPath& instrumentBinary); + + //! Generates the information for a test enumeration job. + //! @param testTarget The test target to generate the job information for. + //! @param jobId The id to assign for this job. + //! @param cachePolicy The cache policy to use for this job. + TestEnumerator::JobInfo GenerateTestEnumerationJobInfo( + const TestTarget* testTarget, + TestEnumerator::JobInfo::Id jobId, + TestEnumerator::JobInfo::CachePolicy cachePolicy) const; + + //! Generates the information for a test run job. + //! @param testTarget The test target to generate the job information for. + //! @param jobId The id to assign for this job. + TestRunner::JobInfo GenerateRegularTestRunJobInfo( + const TestTarget* testTarget, + TestRunner::JobInfo::Id jobId) const; + + //! Generates the information for an instrumented test run job. + //! @param testTarget The test target to generate the job information for. + //! @param jobId The id to assign for this job. + //! @param coverageLevel The coverage level to use for this job. + InstrumentedTestRunner::JobInfo GenerateInstrumentedTestRunJobInfo( + const TestTarget* testTarget, + InstrumentedTestRunner::JobInfo::Id jobId, + CoverageLevel coverageLevel) const; + + //! Generates the information for the batch of test enumeration jobs. + AZStd::vector GenerateTestEnumerationJobInfos( + const AZStd::vector& testTargets, + TestEnumerator::JobInfo::CachePolicy cachePolicy) const; + + //! Generates the information for the batch of test run jobs. + AZStd::vector GenerateRegularTestRunJobInfos( + const AZStd::vector& testTargets) const; + + //! Generates the information for the batch of instrumented test run jobs. + AZStd::vector GenerateInstrumentedTestRunJobInfos( + const AZStd::vector& testTargets, + CoverageLevel coverageLevel) const; + private: + //! Generates the command string to launch the specified test target. + AZStd::string GenerateLaunchArgument(const TestTarget* testTarget) const; + + //! Generates the path to the enumeration cache file for the specified test target. + RepoPath GenerateTargetEnumerationCacheFilePath(const TestTarget* testTarget) const; + + //! Generates the path to the enumeration artifact file for the specified test target. + RepoPath GenerateTargetEnumerationArtifactFilePath(const TestTarget* testTarget) const; + + //! Generates the path to the test run artifact file for the specified test target. + RepoPath GenerateTargetRunArtifactFilePath(const TestTarget* testTarget) const; + + //! Generates the path to the test coverage artifact file for the specified test target. + RepoPath GenerateTargetCoverageArtifactFilePath(const TestTarget* testTarget) const; + + RepoPath m_sourceDir; + RepoPath m_targetBinaryDir; + RepoPath m_cacheDir; + RepoPath m_artifactDir; + RepoPath m_testRunnerBinary; + RepoPath m_instrumentBinary; + }; +} diff --git a/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestTargetExtension.h b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestTargetExtension.h new file mode 100644 index 0000000000..9251164052 --- /dev/null +++ b/Code/Tools/TestImpactFramework/Runtime/Code/Source/TestEngine/JobRunner/TestImpactTestTargetExtension.h @@ -0,0 +1,23 @@ +/* + * 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 + +namespace TestImpact +{ + class TestTarget; + + //! Returns the binary file extension for the specified test target. + AZStd::string GetTestTargetExtension(const TestTarget* testTarget); +}