Skip to content
69 changes: 69 additions & 0 deletions src/Build.UnitTests/BackEnd/ResultsCache_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,75 @@ public void TestRetrieveSubsetTargetsFromResult()
Assert.Equal(BuildResultCode.Success, response.Results.OverallResult);
}

[Fact]
public void TestCacheOnDifferentBuildFlagsPerRequest()
{
string targetName = "testTarget1";
int submissionId = 1;
int nodeRequestId = 0;
int configurationId = 1;

BuildRequest requestWithNoBuildDataFlags = new BuildRequest(
submissionId,
nodeRequestId,
configurationId,
new string[1] { targetName } /* escapedTargets */,
null /* hostServices */,
BuildEventContext.Invalid /* parentBuildEventContext */,
null /* parentRequest */,
BuildRequestDataFlags.None);

BuildRequest requestWithProvideProjectStateAfterBuildFlag = new BuildRequest(
submissionId,
nodeRequestId,
configurationId,
new string[1] { targetName } /* escapedTargets */,
null /* hostServices */,
BuildEventContext.Invalid /* parentBuildEventContext */,
null /* parentRequest */,
BuildRequestDataFlags.ProvideProjectStateAfterBuild);

BuildRequest requestWithNoBuildDataFlags2 = new BuildRequest(
submissionId,
nodeRequestId,
configurationId,
new string[1] { targetName } /* escapedTargets */,
null /* hostServices */,
BuildEventContext.Invalid /* parentBuildEventContext */,
null /* parentRequest */,
BuildRequestDataFlags.None);

BuildResult resultForRequestWithNoBuildDataFlags = new(requestWithNoBuildDataFlags);
resultForRequestWithNoBuildDataFlags.AddResultsForTarget(targetName, BuildResultUtilities.GetEmptySucceedingTargetResult());
ResultsCache cache = new();
cache.AddResult(resultForRequestWithNoBuildDataFlags);

ResultsCacheResponse cacheResponseForRequestWithNoBuildDataFlags = cache.SatisfyRequest(
requestWithNoBuildDataFlags,
new List<string>(),
new List<string>(new string[] { targetName }),
skippedResultsDoNotCauseCacheMiss: false);

ResultsCacheResponse cacheResponseWithProvideProjectStateAfterBuild = cache.SatisfyRequest(
requestWithProvideProjectStateAfterBuildFlag,
new List<string>(),
new List<string>(new string[] { targetName }),
skippedResultsDoNotCauseCacheMiss: false);

ResultsCacheResponse cacheResponseForRequestWithNoBuildDataFlags2 = cache.SatisfyRequest(
requestWithNoBuildDataFlags2,
new List<string>(),
new List<string>(new string[] { targetName }),
skippedResultsDoNotCauseCacheMiss: false);

Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForRequestWithNoBuildDataFlags.Type);

// Because ProvideProjectStateAfterBuildFlag was provided as a part of BuildRequest
Assert.Equal(ResultsCacheResponseType.NotSatisfied, cacheResponseWithProvideProjectStateAfterBuild.Type);

Assert.Equal(ResultsCacheResponseType.Satisfied, cacheResponseForRequestWithNoBuildDataFlags2.Type);
}

[Fact]
public void TestClearResultsCache()
{
Expand Down
12 changes: 11 additions & 1 deletion src/Build/BackEnd/Components/Caching/ResultsCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,9 @@ public ResultsCacheResponse SatisfyRequest(BuildRequest request, List<string> co
{
// Check for targets explicitly specified.
bool explicitTargetsSatisfied = CheckResults(allResults, request.Targets, response.ExplicitTargetsToBuild, skippedResultsDoNotCauseCacheMiss);
bool buildDataFlagsSatisfied = CheckBuildDataFlagsResults(request.BuildRequestDataFlags, allResults.BuildRequestDataFlags);

if (explicitTargetsSatisfied)
if (explicitTargetsSatisfied && buildDataFlagsSatisfied)
{
// All of the explicit targets, if any, have been satisfied
response.Type = ResultsCacheResponseType.Satisfied;
Expand Down Expand Up @@ -332,6 +333,15 @@ private static bool CheckResults(BuildResult result, List<string> targets, HashS
return returnValue;
}

/// <summary>
/// Checks results for the specified build flags.
/// </summary>
/// <param name="buildRequestDataFlags">The current request build flags.</param>
/// <param name="buildResultDataFlags">The existing build result data flags.</param>
/// <returns>False if there is any difference in the data flags that can cause missed build data, true otherwise.</returns>
private static bool CheckBuildDataFlagsResults(BuildRequestDataFlags buildRequestDataFlags, BuildRequestDataFlags buildResultDataFlags) =>
buildRequestDataFlags != BuildRequestDataFlags.ProvideProjectStateAfterBuild || buildResultDataFlags == buildRequestDataFlags;

public IEnumerator<BuildResult> GetEnumerator()
{
return _resultsByConfiguration.Values.GetEnumerator();
Expand Down
7 changes: 7 additions & 0 deletions src/Build/BackEnd/Shared/BuildResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ internal BuildResult(BuildRequest request, BuildResult existingResults, string[]
_nodeRequestId = request.NodeRequestId;
_circularDependency = false;
_baseOverallResult = true;
BuildRequestDataFlags = request.BuildRequestDataFlags;

if (existingResults == null)
{
Expand Down Expand Up @@ -380,6 +381,12 @@ public ProjectInstance ProjectStateAfterBuild
set => _projectStateAfterBuild = value;
}

/// <summary>
/// Gets or sets the flags that provide additional control over the build request.
/// See <see cref="Execution.BuildRequestDataFlags"/> for examples of the available flags.
/// </summary>
public BuildRequestDataFlags BuildRequestDataFlags { get; }

/// <summary>
/// Returns the node packet type.
/// </summary>
Expand Down