Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't expand full drive globs with false condition #5669

Merged
merged 5 commits into from Aug 25, 2020

Conversation

ladipro
Copy link
Member

@ladipro ladipro commented Aug 21, 2020

We often see hangs where MSBuild is enumerating the entire drive because conditions similar to this one are ignored at design time, most notably when loading projects in Visual Studio.

<Content Include="$(SomeDir)\**\*.*" Condition="'$(SomeDir)' != ''">

This PR addresses the problem by honoring the condition in cases where the evaluated glob file spec represents a full drive/filesystem walk, i.e. starts with \**\ or /**/.

Fixes #4091 after adding the condition.

Copy link
Member

@Forgind Forgind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks!

src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
@ladipro
Copy link
Member Author

ladipro commented Aug 23, 2020

I have added an escape hatch. Setting MSBuildAlwaysEvaluateDangerousGlobs to 1 disables this change.

src/Build.OM.UnitTests/Definition/ProjectItem_Tests.cs Outdated Show resolved Hide resolved
[InlineData(@"<i Condition='false' Include='/**/*.cs'/>")]
public void FullFileSystemScanGlobWithFalseCondition(string itemDefinition)
{
IList<ProjectItem> items = ObjectModelHelpers.GetItemsFromFragment(itemDefinition, allItems: false, ignoreCondition: true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we break this at some point in the future, it will seem like a hang rather than a failing test. Do you think it would be reasonable to add a timeout?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not in favor of adding explicit timeouts to tests. My reasons are as follows:

  1. [Philosophical] While some tests might seem more susceptible to hangs than others, it's as easy to break something by causing it to hang as it is to break it by causing it to return a wrong result. The test infra should have a reasonable default for the maximum duration, applied to all tests. Guessing how much time something should take is guaranteed to backfire - tests run on stronger/weaker hardware, in parallel, and so on. A lot of non-determinism in play for us to be able to claim that "this test should take a maximum of 10 seconds, otherwise it is a hang".

  2. [Technical] The hang we're expecting in this test case would have the program spend an excessive amount of time in the Project constructor. A long-running synchronous method is an API problem, let alone a long-running constructor. I guess that's an unfortunate legacy we have to live with. If I were to add a timeout, I'd run something like a Thread.Sleep() in parallel, and if the sleep finishes before the test case does, I would:

a) Abort the hanging thread, risking that it leaves the disk or process in a corrupted or inconsistent state.
b) Let the thread run to completion but move on to executing other tests, marking this one failed.

In either case I wouldn't be able to trust the tests that execute after this because something may be amiss or interfering with normal test execution. For better or for worse, in general a hanging test case kills the entire test run.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do log all long test executions, though we don't currently have a hard timeout.

Co-authored-by: Forgind <Forgind@users.noreply.github.com>
@ladipro
Copy link
Member Author

ladipro commented Aug 24, 2020

Test failure on Linux, not caused by the change:

Microsoft.Build.Engine.UnitTests: [Long Running Test] 'Microsoft.Build.UnitTests.BackEnd.BuildManager_Tests.CancelledBuild', Elapsed: 00:55:03

Looks related to #5229 and #5290.

@ladipro
Copy link
Member Author

ladipro commented Aug 24, 2020

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@Forgind
Copy link
Member

Forgind commented Aug 24, 2020

Weird. Do you know if WaitOne works differently on Linux? From what I can tell, that test should never take noticeably more than 10 seconds.

@ladipro
Copy link
Member Author

ladipro commented Aug 24, 2020

It could be hanging somewhere else. Here's a link to the failed build if you want to take a look:
https://dev.azure.com/dnceng/public/_build/results?buildId=784572&view=logs&jobId=6772b272-ab79-59eb-8cca-405ab5c4d2b5

src/Build/Evaluation/ItemSpec.cs Outdated Show resolved Hide resolved
[InlineData(@"<i Condition='false' Include='/**/*.cs'/>")]
public void FullFileSystemScanGlobWithFalseCondition(string itemDefinition)
{
IList<ProjectItem> items = ObjectModelHelpers.GetItemsFromFragment(itemDefinition, allItems: false, ignoreCondition: true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do log all long test executions, though we don't currently have a hard timeout.

@ladipro ladipro merged commit 384d02a into dotnet:master Aug 25, 2020
@ladipro ladipro deleted the 4091-dont-expand-drive-root branch August 25, 2020 19:04
Forgind added a commit that referenced this pull request Sep 25, 2020
Makes three PRs (#5669, #5625, and #5653) use Change Waves (#5710) to opt out as a unit. Also added a test to ensure that change waves worked properly for one of the three PRs and corrected a minor issue with tests for changes under a change wave that assume it is enabled when there exist tests that disable the relevant change wave without resetting it to empty at the end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wildcard rooted at a NuGet-package-defined property expands drive root
4 participants