ソースを参照

Add python tiaf mode.

Signed-off-by: John <[email protected]>
John 2 年 前
コミット
04a51cf501

+ 3 - 9
AutomatedTesting/Gem/PythonCoverage/Code/Source/PythonCoverageEditorSystemComponent.cpp

@@ -102,14 +102,7 @@ namespace PythonCoverage
             return m_coverageState;
         }
 
-        const auto& tempConfig = configurationFile["common"]["workspace"]["temp"];
-
-        // Temp directory root path is absolute
-        const AZ::IO::Path tempWorkspaceRootDir = tempConfig["root"].GetString();
-
-        // Artifact directory is relative to temp directory root
-        const AZ::IO::Path artifactRelativeDir = tempConfig["relative_paths"]["artifact_dir"].GetString();
-        m_coverageDir = tempWorkspaceRootDir / artifactRelativeDir;
+        m_coverageDir = configurationFile["python"]["workspace"]["temp"]["coverage_artifact_dir"].GetString();
 
         // Everything is good to go, await the first python test case
         m_coverageState = CoverageState::Idle;
@@ -163,7 +156,8 @@ namespace PythonCoverage
                 {
                     for (const auto* moduleComponentDescriptor : moduleData.GetModule()->GetComponentDescriptors())
                     {
-                        m_moduleComponents[moduleComponentDescriptor->GetUuid()] = moduleData.GetDebugName();
+                        m_moduleComponents[moduleComponentDescriptor->GetUuid()] =
+                            m_moduleComponents[moduleComponentDescriptor->GetUuid()] = moduleData.GetDebugName();
                     }
                 }
     

+ 16 - 0
Code/Tools/TestImpactFramework/Runtime/Common/Code/Include/Static/TestImpactRuntime.h

@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <TestImpactRuntimeUtils.h>
+
+namespace TestImpact
+{
+
+} // namespace TestImpact

+ 177 - 35
Code/Tools/TestImpactFramework/Runtime/Common/Code/Include/Static/TestImpactRuntimeUtils.h

@@ -110,7 +110,8 @@ namespace TestImpact
             const auto sparTiaData = SerializeSourceCoveringTestsList(sparTia);
             WriteFileContents<RuntimeException>(sparTiaData, sparTiaFile);
             return true;
-        } catch (const RuntimeException& e)
+        }
+        catch (const RuntimeException& e)
         {
             if (integrationFailurePolicy == Policy::IntegrityFailure::Abort)
             {
@@ -253,40 +254,6 @@ namespace TestImpact
         return AZStd::make_unique<TestTargetExclusionList<TestTarget>>(AZStd::move(testTargetExcludeList));
     }
 
-    //! Selects the test targets from the specified list of test targets that are not in the specified test target exclusion list.
-    //! @param testTargetExcludeList The test target exclusion list to lookup.
-    //! @param testTargets The list of test targets to select from.
-    //! @returns The subset of test targets in the specified list that are not on the target exclude list.
-    template<typename TestTarget>
-    AZStd::pair<AZStd::vector<const TestTarget*>, AZStd::vector<const TestTarget*>>
-    SelectTestTargetsByExcludeList(
-        const TestTargetExclusionList<TestTarget>& testTargetExcludeList, const AZStd::vector<const TestTarget*>& testTargets)
-    {
-        AZStd::vector<const TestTarget*> includedTestTargets;
-        AZStd::vector<const TestTarget*> excludedTestTargets;
-
-        if (testTargetExcludeList.IsEmpty())
-        {
-            return { testTargets, {} };
-        }
-
-        for (const auto& testTarget : testTargets)
-        {
-            if (const auto* excludedTests = testTargetExcludeList.GetExcludedTestsForTarget(testTarget);
-                excludedTests != nullptr && excludedTests->empty())
-            {
-                // If the test filter is empty, the entire suite is excluded
-                excludedTestTargets.push_back(testTarget);
-            }
-            else
-            {
-                includedTestTargets.push_back(testTarget);
-            }
-        }
-
-        return { includedTestTargets, excludedTestTargets };
-    }
-
     //! Extracts the name information from the specified test targets.
     template<typename TestTarget>
     AZStd::vector<AZStd::string> ExtractTestTargetNames(const AZStd::vector<const TestTarget*>& testTargets)
@@ -414,4 +381,179 @@ namespace TestImpact
             AZStd::move(timedOutTests),
             AZStd::move(unexecutedTests));
     }
+
+    //! Selects the test targets from the specified list of test targets that are not in the specified test target exclusion list.
+    //! @param testTargetExcludeList The test target exclusion list to lookup.
+    //! @param testTargets The list of test targets to select from.
+    //! @returns The subset of test targets in the specified list that are not on the target exclude list.
+    template<typename TestTarget>
+    AZStd::pair<AZStd::vector<const TestTarget*>, AZStd::vector<const TestTarget*>> SelectTestTargetsByExcludeList(
+        const TestTargetExclusionList<TestTarget>& testTargetExcludeList, const AZStd::vector<const TestTarget*>& testTargets)
+    {
+        AZStd::vector<const TestTarget*> includedTestTargets;
+        AZStd::vector<const TestTarget*> excludedTestTargets;
+
+        if (testTargetExcludeList.IsEmpty())
+        {
+            return { testTargets, {} };
+        }
+
+        for (const auto& testTarget : testTargets)
+        {
+            if (const auto* excludedTests = testTargetExcludeList.GetExcludedTestsForTarget(testTarget);
+                excludedTests != nullptr && excludedTests->empty())
+            {
+                // If the test filter is empty, the entire suite is excluded
+                excludedTestTargets.push_back(testTarget);
+            }
+            else
+            {
+                includedTestTargets.push_back(testTarget);
+            }
+        }
+
+        return { includedTestTargets, excludedTestTargets };
+    }
+
+    //! Utility for concatenating two vectors.
+    template<typename T>
+    static AZStd::vector<T> ConcatenateVectors(const AZStd::vector<T>& v1, const AZStd::vector<T>& v2)
+    {
+        AZStd::vector<T> result;
+        result.reserve(v1.size() + v2.size());
+        result.insert(result.end(), v1.begin(), v1.end());
+        result.insert(result.end(), v2.begin(), v2.end());
+        return result;
+    }
+
+    //! Utility structure for holding the pertinent data for test run reports.
+    template<typename TestJob>
+    struct TestRunData
+    {
+        TestSequenceResult m_result = TestSequenceResult::Success;
+        AZStd::vector<TestJob> m_jobs;
+        AZStd::chrono::high_resolution_clock::time_point m_relativeStartTime;
+        AZStd::chrono::milliseconds m_duration = AZStd::chrono::milliseconds{ 0 };
+    };
+
+    //! Wrapper for the impact analysis test sequence to handle both the updating and non-updating policies through a common pathway.
+    //! @tparam TestRunnerFunctor The functor for running the specified tests.
+    //! @tparam TestJob The test engine job type returned by the functor.
+    //! @param maxConcurrency The maximum concurrency being used for this sequence.
+    //! @param policyState The policy state being used for the sequence.
+    //! @param suiteType The suite type used for this sequence.
+    //! @param timer The timer to use for the test run timings.
+    //! @param testRunner The test runner functor to use for each of the test runs.
+    //! @param includedSelectedTestTargets The subset of test targets that were selected to run and not also fully excluded from running.
+    //! @param excludedSelectedTestTargets The subset of test targets that were selected to run but were fully excluded running.
+    //! @param discardedTestTargets The subset of test targets that were discarded from the test selection and will not be run.
+    //! @param globalTimeout The maximum duration the entire test sequence may run for (infinite if empty).
+    //! @param testSequenceStartCallback The client function to be called after the test targets have been selected but prior to running the
+    //! tests.
+    //! @param testSequenceCompleteCallback The client function to be called after the test sequence has completed.
+    //! @param testRunCompleteCallback The client function to be called after an individual test run has completed.
+    //! @param updateCoverage The function to call to update the dynamic dependency map with test coverage (if any).
+    template<typename TestTarget, typename TestRunnerFunctor, typename TestJob>
+    Client::ImpactAnalysisSequenceReport ImpactAnalysisTestSequenceWrapper(
+        size_t maxConcurrency,
+        const ImpactAnalysisSequencePolicyState& policyState,
+        SuiteType suiteType,
+        const Timer& sequenceTimer,
+        const TestRunnerFunctor& testRunner,
+        const AZStd::vector<const TestTarget*>& includedSelectedTestTargets,
+        const AZStd::vector<const TestTarget*>& excludedSelectedTestTargets,
+        const AZStd::vector<const TestTarget*>& discardedTestTargets,
+        const AZStd::vector<const TestTarget*>& draftedTestTargets,
+        const AZStd::optional<AZStd::chrono::milliseconds>& testTargetTimeout,
+        const AZStd::optional<AZStd::chrono::milliseconds>& globalTimeout,
+        AZStd::optional<ImpactAnalysisTestSequenceStartCallback> testSequenceStartCallback,
+        AZStd::optional<TestSequenceCompleteCallback<Client::ImpactAnalysisSequenceReport>> testSequenceEndCallback,
+        AZStd::optional<TestRunCompleteCallback> testCompleteCallback,
+        AZStd::optional<AZStd::function<void(const AZStd::vector<TestJob>& jobs)>> updateCoverage)
+    {
+        TestRunData<TestJob> selectedTestRunData, draftedTestRunData;
+        AZStd::optional<AZStd::chrono::milliseconds> sequenceTimeout = globalTimeout;
+
+        // Extract the client facing representation of selected, discarded and drafted test targets
+        const Client::TestRunSelection selectedTests(
+            ExtractTestTargetNames(includedSelectedTestTargets), ExtractTestTargetNames(excludedSelectedTestTargets));
+        const auto discardedTests = ExtractTestTargetNames(discardedTestTargets);
+        const auto draftedTests = ExtractTestTargetNames(draftedTestTargets);
+
+        // Inform the client that the sequence is about to start
+        if (testSequenceStartCallback.has_value())
+        {
+            (*testSequenceStartCallback)(suiteType, selectedTests, discardedTests, draftedTests);
+        }
+
+        // We share the test run complete handler between the selected and drafted test runs as to present them together as one
+        // continuous test sequence to the client rather than two discrete test runs
+        const size_t totalNumTestRuns = includedSelectedTestTargets.size() + draftedTestTargets.size();
+        TestRunCompleteCallbackHandler<TestTarget> testRunCompleteHandler(totalNumTestRuns, testCompleteCallback);
+
+        const auto gatherTestRunData = [&sequenceTimer, &testRunner, &testRunCompleteHandler, &globalTimeout](
+                                           const AZStd::vector<const TestTarget*>& testsTargets, TestRunData<TestJob>& testRunData)
+        {
+            const Timer testRunTimer;
+            testRunData.m_relativeStartTime = testRunTimer.GetStartTimePointRelative(sequenceTimer);
+            auto [result, jobs] = testRunner(testsTargets, testRunCompleteHandler, globalTimeout);
+            testRunData.m_result = result;
+            testRunData.m_jobs = AZStd::move(jobs);
+            testRunData.m_duration = testRunTimer.GetElapsedMs();
+        };
+
+        if (!includedSelectedTestTargets.empty())
+        {
+            // Run the selected test targets and collect the test run results
+            gatherTestRunData(includedSelectedTestTargets, selectedTestRunData);
+
+            // Carry the remaining global sequence time over to the drafted test run
+            if (globalTimeout.has_value())
+            {
+                const auto elapsed = selectedTestRunData.m_duration;
+                sequenceTimeout = elapsed < globalTimeout.value() ? globalTimeout.value() - elapsed : AZStd::chrono::milliseconds(0);
+            }
+        }
+
+        if (!draftedTestTargets.empty())
+        {
+            // Run the drafted test targets and collect the test run results
+            gatherTestRunData(draftedTestTargets, draftedTestRunData);
+        }
+
+        // Generate the sequence report for the client
+        const auto sequenceReport = Client::ImpactAnalysisSequenceReport(
+            maxConcurrency,
+            testTargetTimeout,
+            globalTimeout,
+            policyState,
+            suiteType,
+            selectedTests,
+            discardedTests,
+            draftedTests,
+            GenerateTestRunReport(
+                selectedTestRunData.m_result,
+                selectedTestRunData.m_relativeStartTime,
+                selectedTestRunData.m_duration,
+                selectedTestRunData.m_jobs),
+            GenerateTestRunReport(
+                draftedTestRunData.m_result,
+                draftedTestRunData.m_relativeStartTime,
+                draftedTestRunData.m_duration,
+                draftedTestRunData.m_jobs));
+
+        // Inform the client that the sequence has ended
+        if (testSequenceEndCallback.has_value())
+        {
+            (*testSequenceEndCallback)(sequenceReport);
+        }
+
+        // Update the dynamic dependency map with the latest coverage data (if any)
+        if (updateCoverage.has_value())
+        {
+            (*updateCoverage)(ConcatenateVectors(selectedTestRunData.m_jobs, draftedTestRunData.m_jobs));
+        }
+
+        return sequenceReport;
+    }
 } // namespace TestImpact

+ 2 - 1
Code/Tools/TestImpactFramework/Runtime/Common/Code/Source/Artifact/Factory/TestImpactTestEnumerationSuiteFactory.cpp

@@ -22,7 +22,8 @@ namespace TestImpact
         AZStd::vector<TestEnumerationSuite> TestEnumerationSuitesFactory(const AZStd::string& testEnumerationData)
         {
             // Keys for pertinent XML node and attribute names
-            constexpr const char* Keys[] = {
+            constexpr const char* Keys[] =
+            {
                 "testsuites",
                 "testsuite",
                 "name",

+ 2 - 1
Code/Tools/TestImpactFramework/Runtime/Common/Code/testimpactframework_runtime_common_files.cmake

@@ -66,9 +66,10 @@ set(FILES
     Include/Static/TestEngine/Common/Enumeration/TestImpactTestEngineEnumeration.h
     Include/Static/TestEngine/Common/Run/TestImpactTestEngineRegularRun.h
     Include/Static/TestEngine/Common/Run/TestImpactTestEngineInstrumentedRun.h
-    Include/Static/TestImpactTestTargetExclusionList.h
+    Include/Static/TestImpactRuntime.h
     Include/Static/TestImpactRuntimeUtils.cpp
     Include/Static/TestImpactRuntimeUtils.h
+    Include/Static/TestImpactTestTargetExclusionList.h
     Source/Artifact/Factory/TestImpactTestEnumerationSuiteFactory.cpp
     Source/Artifact/Factory/TestImpactTestRunSuiteFactory.cpp
     Source/Artifact/Factory/TestImpactModuleCoverageFactory.cpp

+ 1 - 143
Code/Tools/TestImpactFramework/Runtime/Native/Code/Source/TestImpactNativeRuntime.cpp

@@ -9,7 +9,7 @@
 #include <TestImpactFramework/TestImpactUtils.h>
 #include <TestImpactFramework/Native/TestImpactNativeRuntime.h>
 
-#include <TestImpactRuntimeUtils.h>
+#include <TestImpactRuntime.h>
 #include <Artifact/Factory/TestImpactNativeTestTargetMetaMapFactory.h>
 #include <BuildTarget/Common/TestImpactBuildTarget.h>
 #include <Dependency/TestImpactDependencyException.h>
@@ -25,148 +25,6 @@
 
 namespace TestImpact
 {
-    //! Utility for concatenating two vectors.
-    template<typename T>
-    static AZStd::vector<T> ConcatenateVectors(const AZStd::vector<T>& v1, const AZStd::vector<T>& v2)
-    {
-        AZStd::vector<T> result;
-        result.reserve(v1.size() + v2.size());
-        result.insert(result.end(), v1.begin(), v1.end());
-        result.insert(result.end(), v2.begin(), v2.end());
-        return result;
-    }
-
-    //! Utility structure for holding the pertinent data for test run reports.
-    template<typename TestJob>
-    struct TestRunData
-    {
-        TestSequenceResult m_result = TestSequenceResult::Success;
-        AZStd::vector<TestJob> m_jobs;
-        AZStd::chrono::high_resolution_clock::time_point m_relativeStartTime;
-        AZStd::chrono::milliseconds m_duration = AZStd::chrono::milliseconds{ 0 };
-    };
-
-    //! Wrapper for the impact analysis test sequence to handle both the updating and non-updating policies through a common pathway.
-    //! @tparam TestRunnerFunctor The functor for running the specified tests.
-    //! @tparam TestJob The test engine job type returned by the functor.
-    //! @param maxConcurrency The maximum concurrency being used for this sequence.
-    //! @param policyState The policy state being used for the sequence.
-    //! @param suiteType The suite type used for this sequence.
-    //! @param timer The timer to use for the test run timings.
-    //! @param testRunner The test runner functor to use for each of the test runs.
-    //! @param includedSelectedTestTargets The subset of test targets that were selected to run and not also fully excluded from running.
-    //! @param excludedSelectedTestTargets The subset of test targets that were selected to run but were fully excluded running.
-    //! @param discardedTestTargets The subset of test targets that were discarded from the test selection and will not be run.
-    //! @param globalTimeout The maximum duration the entire test sequence may run for (infinite if empty).
-    //! @param testSequenceStartCallback The client function to be called after the test targets have been selected but prior to running the
-    //! tests.
-    //! @param testSequenceCompleteCallback The client function to be called after the test sequence has completed.
-    //! @param testRunCompleteCallback The client function to be called after an individual test run has completed.
-    //! @param updateCoverage The function to call to update the dynamic dependency map with test coverage (if any).
-    template<typename TestRunnerFunctor, typename TestJob>
-    Client::ImpactAnalysisSequenceReport ImpactAnalysisTestSequenceWrapper(
-        size_t maxConcurrency,
-        const ImpactAnalysisSequencePolicyState& policyState,
-        SuiteType suiteType,
-        const Timer& sequenceTimer,
-        const TestRunnerFunctor& testRunner,
-        const AZStd::vector<const NativeTestTarget*>& includedSelectedTestTargets,
-        const AZStd::vector<const NativeTestTarget*>& excludedSelectedTestTargets,
-        const AZStd::vector<const NativeTestTarget*>& discardedTestTargets,
-        const AZStd::vector<const NativeTestTarget*>& draftedTestTargets,
-        const AZStd::optional<AZStd::chrono::milliseconds>& testTargetTimeout,
-        const AZStd::optional<AZStd::chrono::milliseconds>& globalTimeout,
-        AZStd::optional<ImpactAnalysisTestSequenceStartCallback> testSequenceStartCallback,
-        AZStd::optional<TestSequenceCompleteCallback<Client::ImpactAnalysisSequenceReport>> testSequenceEndCallback,
-        AZStd::optional<TestRunCompleteCallback> testCompleteCallback,
-        AZStd::optional<AZStd::function<void(const AZStd::vector<TestJob>& jobs)>> updateCoverage)
-    {
-        TestRunData<TestJob> selectedTestRunData, draftedTestRunData;
-        AZStd::optional<AZStd::chrono::milliseconds> sequenceTimeout = globalTimeout;
-
-        // Extract the client facing representation of selected, discarded and drafted test targets
-        const Client::TestRunSelection selectedTests(
-            ExtractTestTargetNames(includedSelectedTestTargets), ExtractTestTargetNames(excludedSelectedTestTargets));
-        const auto discardedTests = ExtractTestTargetNames(discardedTestTargets);
-        const auto draftedTests = ExtractTestTargetNames(draftedTestTargets);
-
-        // Inform the client that the sequence is about to start
-        if (testSequenceStartCallback.has_value())
-        {
-            (*testSequenceStartCallback)(suiteType, selectedTests, discardedTests, draftedTests);
-        }
-
-        // We share the test run complete handler between the selected and drafted test runs as to present them together as one
-        // continuous test sequence to the client rather than two discrete test runs
-        const size_t totalNumTestRuns = includedSelectedTestTargets.size() + draftedTestTargets.size();
-        TestRunCompleteCallbackHandler<NativeTestTarget> testRunCompleteHandler(totalNumTestRuns, testCompleteCallback);
-
-        const auto gatherTestRunData = [&sequenceTimer, &testRunner, &testRunCompleteHandler, &globalTimeout]
-        (const AZStd::vector<const NativeTestTarget*>& testsTargets, TestRunData<TestJob>& testRunData)
-        {
-            const Timer testRunTimer;
-            testRunData.m_relativeStartTime = testRunTimer.GetStartTimePointRelative(sequenceTimer);
-            auto [result, jobs] = testRunner(testsTargets, testRunCompleteHandler, globalTimeout);
-            testRunData.m_result = result;
-            testRunData.m_jobs = AZStd::move(jobs);
-            testRunData.m_duration = testRunTimer.GetElapsedMs();
-        };
-
-        if (!includedSelectedTestTargets.empty())
-        {
-            // Run the selected test targets and collect the test run results
-            gatherTestRunData(includedSelectedTestTargets, selectedTestRunData);
-
-            // Carry the remaining global sequence time over to the drafted test run
-            if (globalTimeout.has_value())
-            {
-                const auto elapsed = selectedTestRunData.m_duration;
-                sequenceTimeout = elapsed < globalTimeout.value() ? globalTimeout.value() - elapsed : AZStd::chrono::milliseconds(0);
-            }
-        }
-
-        if (!draftedTestTargets.empty())
-        {
-            // Run the drafted test targets and collect the test run results
-            gatherTestRunData(draftedTestTargets, draftedTestRunData);
-        }
-
-        // Generate the sequence report for the client
-        const auto sequenceReport = Client::ImpactAnalysisSequenceReport(
-            maxConcurrency,
-            testTargetTimeout,
-            globalTimeout,
-            policyState,
-            suiteType,
-            selectedTests,
-            discardedTests,
-            draftedTests,
-            GenerateTestRunReport(
-                selectedTestRunData.m_result, 
-                selectedTestRunData.m_relativeStartTime, 
-                selectedTestRunData.m_duration,
-                selectedTestRunData.m_jobs),
-            GenerateTestRunReport(
-                draftedTestRunData.m_result, 
-                draftedTestRunData.m_relativeStartTime, 
-                draftedTestRunData.m_duration,
-                draftedTestRunData.m_jobs));
-
-        // Inform the client that the sequence has ended
-        if (testSequenceEndCallback.has_value())
-        {
-            (*testSequenceEndCallback)(sequenceReport);
-        }
-
-        // Update the dynamic dependency map with the latest coverage data (if any)
-        if (updateCoverage.has_value())
-        {
-            (*updateCoverage)(ConcatenateVectors(selectedTestRunData.m_jobs, draftedTestRunData.m_jobs));
-        }
-
-        return sequenceReport;
-    }
-
     NativeTestTargetMetaMap ReadNativeTestTargetMetaMapFile(SuiteType suiteFilter, const RepoPath& testTargetMetaConfigFile)
     {
         const auto masterTestListData = ReadFileContents<RuntimeException>(testTargetMetaConfigFile);

+ 4 - 2
Code/Tools/TestImpactFramework/Runtime/Native/Code/Source/TestRunner/Native/Job/TestImpactNativeTestJobInfoGenerator.h

@@ -58,7 +58,8 @@ namespace TestImpact
     };
 
     //! Generates job information for the different test job runner types.
-    class NativeRegularTestRunJobInfoGenerator : public TestJobInfoGenerator<NativeRegularTestRunner, NativeTestTarget>
+    class NativeRegularTestRunJobInfoGenerator
+        : public TestJobInfoGenerator<NativeRegularTestRunner, NativeTestTarget>
     {
     public:
         //! Configures the test job info generator with the necessary path information for launching test targets.
@@ -83,7 +84,8 @@ namespace TestImpact
     };
 
     //! Generates job information for the different test job runner types.
-    class NativeInstrumentedTestRunJobInfoGenerator : public TestJobInfoGenerator<NativeInstrumentedTestRunner, NativeTestTarget>
+    class NativeInstrumentedTestRunJobInfoGenerator
+        : public TestJobInfoGenerator<NativeInstrumentedTestRunner, NativeTestTarget>
     {
     public:
         //! Configures the test job info generator with the necessary path information for launching test targets.

+ 16 - 0
Code/Tools/TestImpactFramework/Runtime/Python/Code/Include/TestImpactFramework/Python/TestImpactPythonRuntime.h

@@ -122,6 +122,14 @@ namespace TestImpact
         using ProductionTarget = PythonProductionTarget;
         using TestTarget = PythonTestTarget;
 
+        //! Selects the test targets covering a given change list and updates the enumeration cache of the test targets with sources
+        //! modified in that change list.
+        //! @param changeList The change list for which the covering tests and enumeration cache updates will be generated for.
+        //! @param testPrioritizationPolicy The test prioritization strategy to use for the selected test targets.
+        //! @returns The pair of selected test targets and discarded test targets.
+        AZStd::pair<AZStd::vector<const TestTarget*>, AZStd::vector<const TestTarget*>> SelectCoveringTestTargets(
+            const ChangeList& changeList, Policy::TestPrioritization testPrioritizationPolicy);
+
         //! Prepares the dynamic dependency map for a seed update by clearing all existing data and deleting the file that will be
         //! serialized.
         void ClearDynamicDependencyMapAndRemoveExistingFile();
@@ -132,6 +140,14 @@ namespace TestImpact
         //! Generates a regular/seed sequence policy state for the current runtime policy runtime configuration.
         SequencePolicyState GenerateSequencePolicyState() const;
 
+        //! Generates a safe impact analysis sequence policy state for the current runtime policy runtime configuration.
+        SafeImpactAnalysisSequencePolicyState GenerateSafeImpactAnalysisSequencePolicyState(
+            Policy::TestPrioritization testPrioritizationPolicy) const;
+
+        //! Generates an impact analysis sequence policy state for the current runtime policy runtime configuration.
+        ImpactAnalysisSequencePolicyState GenerateImpactAnalysisSequencePolicyState(
+            Policy::TestPrioritization testPrioritizationPolicy, Policy::DynamicDependencyMap dynamicDependencyMapPolicy) const;
+
         PythonRuntimeConfig m_config;
         RepoPath m_sparTiaFile;
         SuiteType m_suiteFilter;

+ 138 - 33
Code/Tools/TestImpactFramework/Runtime/Python/Code/Source/TestImpactPythonRuntime.cpp

@@ -9,7 +9,7 @@
 #include <TestImpactFramework/TestImpactUtils.h>
 #include <TestImpactFramework/Python/TestImpactPythonRuntime.h>
 
-#include <TestImpactRuntimeUtils.h>
+#include <TestImpactRuntime.h>
 #include <Artifact/Static/TestImpactPythonTestTargetMeta.h>
 #include <Artifact/Factory/TestImpactPythonTestTargetMetaMapFactory.h>
 #include <Dependency/TestImpactPythonTestSelectorAndPrioritizer.h>
@@ -19,6 +19,7 @@
 #include <Target/Python/TestImpactPythonTargetListCompiler.h>
 #include <Target/Python/TestImpactPythonTestTarget.h>
 #include <TestEngine/Python/TestImpactPythonTestEngine.h>
+#include <TestRunner/Common/Run/TestImpactTestCoverage.h>
 
 #include <AzCore/std/string/regex.h>
 
@@ -146,6 +147,33 @@ namespace TestImpact
 
     PythonRuntime::~PythonRuntime() = default;
 
+    AZStd::pair<AZStd::vector<const PythonTestTarget*>, AZStd::vector<const PythonTestTarget*>> PythonRuntime::SelectCoveringTestTargets(
+        const ChangeList& changeList, Policy::TestPrioritization testPrioritizationPolicy)
+    {
+        AZStd::vector<const TestTarget*> discardedTestTargets;
+
+        // Select and prioritize the test targets pertinent to this change list
+        const auto changeDependencyList = m_dynamicDependencyMap->ApplyAndResoveChangeList(changeList, m_integrationFailurePolicy);
+        const auto selectedTestTargets = m_testSelectorAndPrioritizer->SelectTestTargets(changeDependencyList, testPrioritizationPolicy);
+
+        // Populate a set with the selected test targets so that we can infer the discarded test target not selected for this change list
+        const AZStd::unordered_set<const TestTarget*> selectedTestTargetSet(selectedTestTargets.begin(), selectedTestTargets.end());
+
+        // Update the enumeration caches of mutated targets regardless of the current sharding policy
+        // EnumerateMutatedTestTargets(changeDependencyList);
+
+        // The test targets in the main list not in the selected test target set are the test targets not selected for this change list
+        for (const auto& testTarget : m_dynamicDependencyMap->GetBuildTargetList()->GetTestTargetList().GetTargets())
+        {
+            if (!selectedTestTargetSet.contains(&testTarget))
+            {
+                discardedTestTargets.push_back(&testTarget);
+            }
+        }
+
+        return { selectedTestTargets, discardedTestTargets };
+    }
+
     void PythonRuntime::ClearDynamicDependencyMapAndRemoveExistingFile()
     {
         m_dynamicDependencyMap->ClearAllSourceCoverage();
@@ -171,6 +199,17 @@ namespace TestImpact
         return { GeneratePolicyStateBase() };
     }
 
+    SafeImpactAnalysisSequencePolicyState PythonRuntime::GenerateSafeImpactAnalysisSequencePolicyState(
+        Policy::TestPrioritization testPrioritizationPolicy) const
+    {
+        return { GeneratePolicyStateBase(), testPrioritizationPolicy };
+    }
+
+    ImpactAnalysisSequencePolicyState PythonRuntime::GenerateImpactAnalysisSequencePolicyState(
+        Policy::TestPrioritization testPrioritizationPolicy, Policy::DynamicDependencyMap dynamicDependencyMapPolicy) const
+    {
+        return { GeneratePolicyStateBase(), testPrioritizationPolicy, dynamicDependencyMapPolicy };
+    }
     Client::RegularSequenceReport PythonRuntime::RegularTestSequence(
         [[maybe_unused]] AZStd::optional<AZStd::chrono::milliseconds> testTargetTimeout,
         [[maybe_unused]] AZStd::optional<AZStd::chrono::milliseconds> globalTimeout,
@@ -206,33 +245,99 @@ namespace TestImpact
         [[maybe_unused]] AZStd::optional<TestSequenceCompleteCallback<Client::ImpactAnalysisSequenceReport>> testSequenceEndCallback,
         [[maybe_unused]] AZStd::optional<TestRunCompleteCallback> testCompleteCallback)
     {
-        return Client::ImpactAnalysisSequenceReport(
-            1,
-            AZStd::nullopt,
-            AZStd::nullopt,
-            ImpactAnalysisSequencePolicyState{},
-            m_suiteFilter,
-            Client::TestRunSelection(),
-            {},
-            {},
-            Client::TestRunReport(
-                TestSequenceResult::Success,
-                AZStd::chrono::high_resolution_clock::time_point(),
-                AZStd::chrono::milliseconds{ 0 },
-                {},
-                {},
-                {},
-                {},
-                {}),
-            Client::TestRunReport(
-                TestSequenceResult::Success,
-                AZStd::chrono::high_resolution_clock::time_point(),
-                AZStd::chrono::milliseconds{ 0 },
-                {},
-                {},
-                {},
-                {},
-                {}));
+        const Timer sequenceTimer;
+
+        AZStd::vector<const TestTarget*> draftedTestTargets;
+        if (!HasImpactAnalysisData())
+        {
+            const auto notCovered = m_dynamicDependencyMap->GetNotCoveringTests();
+            for (const auto& testTarget : notCovered)
+            {
+                if (!m_testTargetExcludeList->IsTestTargetFullyExcluded(testTarget))
+                {
+                    draftedTestTargets.push_back(testTarget);
+                }
+            }
+        }
+
+        // The test targets that were selected for the change list by the dynamic dependency map and the test targets that were not
+        const auto [selectedTestTargets, discardedTestTargets] = SelectCoveringTestTargets(changeList, testPrioritizationPolicy);
+        
+        // The subset of selected test targets that are not on the configuration's exclude list and those that are
+        const auto [includedSelectedTestTargets, excludedSelectedTestTargets] =
+            SelectTestTargetsByExcludeList(*m_testTargetExcludeList, selectedTestTargets);
+        
+        // Functor for running instrumented test targets
+        const auto instrumentedTestRun = [this, &testTargetTimeout](
+                                             const AZStd::vector<const TestTarget*>& testsTargets,
+                                             TestRunCompleteCallbackHandler<TestTarget>& testRunCompleteHandler,
+                                             AZStd::optional<AZStd::chrono::milliseconds> globalTimeout)
+        {
+            return DiscoverDependencyCoverage(
+                m_dynamicDependencyMap.get(),
+                m_testEngine->InstrumentedRun(
+                testsTargets,
+                m_executionFailurePolicy,
+                m_integrationFailurePolicy,
+                m_testFailurePolicy,
+                m_targetOutputCapture,
+                testTargetTimeout,
+                globalTimeout,
+                AZStd::ref(testRunCompleteHandler)));
+        };
+        
+        if (dynamicDependencyMapPolicy == Policy::DynamicDependencyMap::Update)
+        {
+            AZStd::optional<AZStd::function<void(const AZStd::vector<TestEngineInstrumentedRun<TestTarget, TestCoverage>>& jobs)>>
+                updateCoverage = [this](const AZStd::vector<TestEngineInstrumentedRun<TestTarget, TestCoverage>>& jobs)
+            {
+                m_hasImpactAnalysisData = UpdateAndSerializeDynamicDependencyMap(
+                                              *m_dynamicDependencyMap.get(),
+                                              jobs,
+                                              m_failedTestCoveragePolicy,
+                                              m_integrationFailurePolicy,
+                                              m_config.m_commonConfig.m_repo.m_root,
+                                              m_sparTiaFile)
+                                              .value_or(m_hasImpactAnalysisData);
+            };
+        
+            return ImpactAnalysisTestSequenceWrapper(
+                1,
+                GenerateImpactAnalysisSequencePolicyState(testPrioritizationPolicy, dynamicDependencyMapPolicy),
+                m_suiteFilter,
+                sequenceTimer,
+                instrumentedTestRun,
+                includedSelectedTestTargets,
+                excludedSelectedTestTargets,
+                discardedTestTargets,
+                draftedTestTargets,
+                testTargetTimeout,
+                globalTimeout,
+                testSequenceStartCallback,
+                testSequenceEndCallback,
+                testCompleteCallback,
+                updateCoverage);
+        }
+        else
+        {
+            return ImpactAnalysisTestSequenceWrapper(
+                1,
+                GenerateImpactAnalysisSequencePolicyState(testPrioritizationPolicy, dynamicDependencyMapPolicy),
+                m_suiteFilter,
+                sequenceTimer,
+                instrumentedTestRun,
+                includedSelectedTestTargets,
+                excludedSelectedTestTargets,
+                discardedTestTargets,
+                draftedTestTargets,
+                testTargetTimeout,
+                globalTimeout,
+                testSequenceStartCallback,
+                testSequenceEndCallback,
+                testCompleteCallback,
+                AZStd::optional<AZStd::function<void(const AZStd::vector<TestEngineInstrumentedRun<TestTarget, TestCoverage>>& jobs)>>{
+                    AZStd::nullopt });
+        }
     }
 
     Client::SafeImpactAnalysisSequenceReport PythonRuntime::SafeImpactAnalysisTestSequence(
@@ -283,11 +388,11 @@ namespace TestImpact
     }
 
     Client::SeedSequenceReport PythonRuntime::SeededTestSequence(
-        [[maybe_unused]] AZStd::optional<AZStd::chrono::milliseconds> testTargetTimeout,
-        [[maybe_unused]] AZStd::optional<AZStd::chrono::milliseconds> globalTimeout,
-        [[maybe_unused]] AZStd::optional<TestSequenceStartCallback> testSequenceStartCallback,
-        [[maybe_unused]] AZStd::optional<TestSequenceCompleteCallback<Client::SeedSequenceReport>> testSequenceEndCallback,
-        [[maybe_unused]] AZStd::optional<TestRunCompleteCallback> testCompleteCallback)
+        AZStd::optional<AZStd::chrono::milliseconds> testTargetTimeout,
+        AZStd::optional<AZStd::chrono::milliseconds> globalTimeout,
+        AZStd::optional<TestSequenceStartCallback> testSequenceStartCallback,
+        AZStd::optional<TestSequenceCompleteCallback<Client::SeedSequenceReport>> testSequenceEndCallback,
+        AZStd::optional<TestRunCompleteCallback> testCompleteCallback)
     {
         const Timer sequenceTimer;
         AZStd::vector<const TestTarget*> includedTestTargets;