Runtime refactor

This commit is contained in:
jonawals
2021-05-27 11:37:34 +01:00
parent c93a2f06ff
commit f9425992f8
16 changed files with 513 additions and 114 deletions
@@ -34,7 +34,7 @@ namespace TestImpact
else
{
// This is a new entry on the dependency map so create an entry with this parent target and no covering targets
m_sourceDependencyMap.emplace(source, DependencyData{ {target}, {} });
m_sourceDependencyMap.emplace(source.String(), DependencyData{ {target}, {} });
}
}
@@ -56,6 +56,7 @@ namespace TestImpact
for (const auto& target : m_testTargets.GetTargets())
{
mapBuildTargetSources(&target);
m_testTargetSourceCoverageCount[&target] = 0;
}
}
@@ -142,10 +143,21 @@ namespace TestImpact
DependencyException, AZStd::string::format("Couldn't replace source coverage for %s, source file is an autogen input file",
sourceCoverage.GetPath().c_str()).c_str());
auto [it, inserted] = m_sourceDependencyMap.insert(sourceCoverage.GetPath().String());
auto& [key, sourceDependency] = *it;
auto [sourceDependencyIt, inserted] = m_sourceDependencyMap.insert(sourceCoverage.GetPath().String());
auto& [key, sourceDependency] = *sourceDependencyIt;
// Clear any existing coverage for the delta
// Knock down the source coverage count for the test targets and clear any existing coverage for the delta
for (const auto& testTarget : sourceDependency.m_coveringTestTargets)
{
if (auto coveringTestTargetIt = m_testTargetSourceCoverageCount.find(testTarget);
coveringTestTargetIt != m_testTargetSourceCoverageCount.end())
{
if (coveringTestTargetIt->second > 0)
{
coveringTestTargetIt->second--;
}
}
}
sourceDependency.m_coveringTestTargets.clear();
// Update the dependency with any new coverage data
@@ -157,10 +169,13 @@ namespace TestImpact
// Source to covering test target mapping
sourceDependency.m_coveringTestTargets.insert(testTarget);
// Test target covering sources count
m_testTargetSourceCoverageCount[testTarget]++;
// Build target to covering test target mapping
for (const auto& parentTarget : sourceDependency.m_parentTargets)
{
m_buildTargetCoverage[parentTarget.GetBuildTarget()].insert(testTarget);
{
m_buildTargetCoverage[parentTarget.GetBuildTarget()].insert(testTarget);
}
}
else
@@ -173,7 +188,7 @@ namespace TestImpact
// If the new coverage data results in a parentless and coverageless entry, consider it a dead entry and remove accordingly
if (sourceDependency.m_coveringTestTargets.empty() && sourceDependency.m_parentTargets.empty())
{
m_sourceDependencyMap.erase(it);
m_sourceDependencyMap.erase(sourceDependencyIt);
}
}
}
@@ -198,6 +213,14 @@ namespace TestImpact
}
}
void DynamicDependencyMap::ClearAllSourceCoverage()
{
for (const auto& [path, coverage] : m_sourceDependencyMap)
{
ReplaceSourceCoverage(SourceCoveringTestsList(AZStd::vector<SourceCoveringTests>{ SourceCoveringTests(RepoPath(path)) }));
}
}
const ProductionTargetList& DynamicDependencyMap::GetProductionTargetList() const
{
return m_productionTargets;
@@ -405,4 +428,33 @@ namespace TestImpact
return ChangeDependencyList(AZStd::move(createDependencies), AZStd::move(updateDependencies), AZStd::move(deleteDependencies));
}
AZStd::vector<const TestTarget*> DynamicDependencyMap::GetCoveringTests() const
{
AZStd::vector<const TestTarget*> covering;
for (const auto& [testTarget, coveringSources] : m_testTargetSourceCoverageCount)
{
if (coveringSources > 0)
{
covering.push_back(testTarget);
}
}
return covering;
}
AZStd::vector<const TestTarget*> DynamicDependencyMap::GetNotCoveringTests() const
{
AZStd::vector<const TestTarget*> notCovering;
for(const auto& [testTarget, coveringSources] : m_testTargetSourceCoverageCount)
{
if(coveringSources == 0)
{
notCovering.push_back(testTarget);
}
}
return notCovering;
}
} // namespace TestImpact
@@ -85,18 +85,27 @@ namespace TestImpact
//! @param sourceCoverageDelta The source coverage delta to replace in the dependency map.
void ReplaceSourceCoverage(const SourceCoveringTestsList& sourceCoverageDelta);
//! Clears all of the existing source coverage in the dependency map.
void ClearAllSourceCoverage();
//! Exports the coverage of all sources in the dependency map.
SourceCoveringTestsList ExportSourceCoverage() const;
//! Gets the list of orphaned source files in the dependency map that have coverage data but belong to no parent build targets.
AZStd::vector<AZStd::string> GetOrphanSourceFiles() const;
//! Applies the specified change list to the dynamic dependency map and resolves the change list to a change dependency list
//! Applies the specified change list to the dependency map and resolves the change list to a change dependency list
//! containing the updated source dependencies for each source file in the change list.
//! @param changeList The change list to apply and resolve.
//! @returns The change list as resolved to the appropriate source dependencies.
[[nodiscard]] ChangeDependencyList ApplyAndResoveChangeList(const ChangeList& changeList);
//! Returns the test targets that cover one or more sources in the repository.
AZStd::vector<const TestTarget*> GetCoveringTests() const;
//! Returns the test targets that do not cover any sources in the repository.
AZStd::vector<const TestTarget*> GetNotCoveringTests() const;
private:
//! Clears the source coverage of the specified sources.
//! @note The covering targets for the parent test target(s) will not be pruned if those covering targets are removed.
@@ -116,5 +125,8 @@ namespace TestImpact
//! Mapping of autogen input sources to their generated output sources.
AZStd::unordered_map<AZStd::string, AZStd::vector<AZStd::string>> m_autogenInputToOutputMap;
//! Number of sources that each test target in the repository covers.
AZStd::unordered_map<const TestTarget*, size_t> m_testTargetSourceCoverageCount;
};
} // namespace TestImpact
@@ -65,7 +65,7 @@ namespace TestImpact
{
AZStd::sort(m_coverage.begin(), m_coverage.end(), [](const SourceCoveringTests& lhs, const SourceCoveringTests& rhs)
{
return lhs.GetPath() < rhs.GetPath();
return lhs.GetPath().String() < rhs.GetPath().String();
});
}
@@ -0,0 +1,93 @@
/*
* 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 <Dependency/TestImpactDependencyException.h>
#include <Dependency/TestImpactSourceCoveringTestsSerializer.h>
#include <AzCore/JSON/document.h>
#include <AzCore/JSON/prettywriter.h>
#include <AzCore/JSON/rapidjson.h>
#include <AzCore/JSON/stringbuffer.h>
namespace TestImpact
{
// Tag used to indicate that a given line is the name o a covering test target
constexpr char TargetTag = '-';
AZStd::string SerializeSourceCoveringTestsList(const SourceCoveringTestsList& sourceCoveringTestsList)
{
AZStd::string output;
output.reserve(1U << 24); // Reserve approx. 16Mib as the outputs can be quite large
for (const auto& source : sourceCoveringTestsList.GetCoverage())
{
// Source file
output += source.GetPath().String();
output += "\n";
// Covering test targets
for (const auto& testTarget : source.GetCoveringTestTargets())
{
output += AZStd::string::format("%c%s\n", TargetTag, testTarget.c_str());
}
}
// Add the newline so the deserializer can properly terminate on the last read line
output += "\n";
return output;
}
SourceCoveringTestsList DeserializeSourceCoveringTestsList(const AZStd::string& sourceCoveringTestsListString)
{
AZStd::vector<SourceCoveringTests> sourceCoveringTests;
AZStd::string source;
AZStd::vector<AZStd::string> coveringTests;
sourceCoveringTests.reserve(1U << 16); // Reserve for approx. 65k source files
const AZStd::string delim = "\n";
auto start = 0U;
auto end = sourceCoveringTestsListString.find(delim);
while (end != AZStd::string::npos)
{
const auto line = sourceCoveringTestsListString.substr(start, end - start);
if (line.starts_with(TargetTag))
{
// This is a test target covering the most recent source discovered
coveringTests.push_back(line.substr(1, line.length() - 1));
}
else
{
// This is a new source file so assign the accumulated test targets to the current source file before proceeding
if (!coveringTests.empty())
{
sourceCoveringTests.push_back(SourceCoveringTests(source, AZStd::move(coveringTests)));
coveringTests.clear();
}
source = line;
}
start = end + delim.length();
end = sourceCoveringTestsListString.find(delim, start);
}
// Ensure we properly assign the accumulated test targets to the most recent source discovered
if (!coveringTests.empty())
{
sourceCoveringTests.push_back(SourceCoveringTests(source, AZStd::move(coveringTests)));
coveringTests.clear();
}
return SourceCoveringTestsList(AZStd::move(sourceCoveringTests));
}
} // namespace TestImpact
@@ -0,0 +1,26 @@
/*
* 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 <Dependency/TestImpactSourceCoveringTestsList.h>
#include <AzCore/std/string/string.h>
namespace TestImpact
{
//! Serializes the specified source covering tests list to plain text format.
AZStd::string SerializeSourceCoveringTestsList(const SourceCoveringTestsList& sourceCoveringTestsList);
//! Deserializes a source covering tests list from the specified source covering tests data in plain text format.
SourceCoveringTestsList DeserializeSourceCoveringTestsList(const AZStd::string& sourceCoveringTestsListString);
} // namespace TestImpact
@@ -25,7 +25,7 @@ namespace TestImpact
}
AZStd::vector<const TestTarget*> TestSelectorAndPrioritizer::SelectTestTargets(
const ChangeDependencyList& changeDependencyList, TestSelectionStrategy testSelectionStrategy)
const ChangeDependencyList& changeDependencyList, Policy::TestPrioritization testSelectionStrategy)
{
const auto selectedTestTargetAndDependerMap = SelectTestTargets(changeDependencyList);
const auto prioritizedSelectedTests = PrioritizeSelectedTestTargets(selectedTestTargetAndDependerMap, testSelectionStrategy);
@@ -210,7 +210,7 @@ namespace TestImpact
AZStd::vector<const TestTarget*> TestSelectorAndPrioritizer::PrioritizeSelectedTestTargets(
const SelectedTestTargetAndDependerMap& selectedTestTargetAndDependerMap,
[[maybe_unused]]TestSelectionStrategy testSelectionStrategy)
[[maybe_unused]] Policy::TestPrioritization testSelectionStrategy)
{
AZStd::vector<const TestTarget*> selectedTestTargets;
@@ -12,6 +12,8 @@
#pragma once
#include <TestImpactFramework/TestImpactTestSequence.h>
#include <Artifact/Static/TestImpactDependencyGraphData.h>
#include <Dependency/TestImpactChangeDependencyList.h>
@@ -25,13 +27,6 @@ namespace TestImpact
class BuildTarget;
class TestTarget;
//! Strategy for selecting tests given a set of source changes.
enum class TestSelectionStrategy : bool
{
SelectOnly, //!< Select tests only, do not attempt prioritization of those selected tests.
SelectAndPriotitize //!< Select tests and prioritize according to dependency graph locality of coverer and coveree.
};
//! Map of build targets and their dependency graph data.
//! For test targets, the dependency graph data is that of the build targets which the test target depends on.
//! For production targets, the dependency graph is that of the build targets that depend on it (dependers).
@@ -52,7 +47,7 @@ namespace TestImpact
//! Select the covering test targets for the given set of source changes and optionally prioritizes said test selection.
//! @param changeDependencyList The resolved list of source dependencies for the CRUD source changes.
//! @param testSelectionStrategy The test selection and prioritization strategy to apply to the given CRUD source changes.
AZStd::vector<const TestTarget*> SelectTestTargets(const ChangeDependencyList& changeDependencyList, TestSelectionStrategy testSelectionStrategy);
AZStd::vector<const TestTarget*> SelectTestTargets(const ChangeDependencyList& changeDependencyList, Policy::TestPrioritization testSelectionStrategy);
private:
//! Map of selected test targets and the production targets they cover for the given set of source changes.
@@ -69,7 +64,7 @@ namespace TestImpact
//! @param testSelectionStrategy The test selection strategy to prioritize the selected tests.
//! @returns The selected tests either in either arbitrary order or in prioritized with highest priority first.
AZStd::vector<const TestTarget*> PrioritizeSelectedTestTargets(
const SelectedTestTargetAndDependerMap& selectedTestTargetAndDependerMap, TestSelectionStrategy testSelectionStrategy);
const SelectedTestTargetAndDependerMap& selectedTestTargetAndDependerMap, Policy::TestPrioritization testSelectionStrategy);
const DynamicDependencyMap* m_dynamicDependencyMap;
DependencyGraphDataMap m_dependencyGraphDataMap;