1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 //----------------------------------------------------------------------- 4 // </copyright> 5 // <summary>Unit tests for the TargetBuilder with a mock task builder.</summary> 6 //----------------------------------------------------------------------- 7 8 using System; 9 using System.Xml; 10 using System.Text; 11 using System.Collections; 12 using System.Collections.Generic; 13 using System.IO; 14 using System.Linq; 15 using System.Text.RegularExpressions; 16 using System.Threading; 17 using Microsoft.Build.Framework; 18 using Microsoft.Build.BackEnd; 19 using Microsoft.Build.Collections; 20 using Microsoft.Build.Evaluation; 21 using Microsoft.Build.Execution; 22 using Microsoft.Build.Shared; 23 24 using ILoggingService = Microsoft.Build.BackEnd.Logging.ILoggingService; 25 using ProjectLoggingContext = Microsoft.Build.BackEnd.Logging.ProjectLoggingContext; 26 using NodeLoggingContext = Microsoft.Build.BackEnd.Logging.NodeLoggingContext; 27 using LegacyThreadingData = Microsoft.Build.Execution.LegacyThreadingData; 28 using System.Threading.Tasks; 29 using Microsoft.Build.BackEnd.SdkResolution; 30 using Microsoft.Build.Engine.UnitTests.BackEnd; 31 using Xunit; 32 33 namespace Microsoft.Build.UnitTests.BackEnd 34 { 35 /// <summary> 36 /// This is the unit test for the TargetBuilder. This particular test is confined to just using the 37 /// actual TargetBuilder, and uses a mock TaskBuilder on which TargetBuilder depends. 38 /// </summary> 39 public class TargetBuilder_Tests : IRequestBuilderCallback, IDisposable 40 { 41 /// <summary> 42 /// The component host. 43 /// </summary> 44 private MockHost _host; 45 46 /// <summary> 47 /// A mock logger for scenario tests. 48 /// </summary> 49 private MockLogger _mockLogger; 50 51 /// <summary> 52 /// The node request id counter 53 /// </summary> 54 private int _nodeRequestId; 55 56 /// <summary> 57 /// Callback used to receive exceptions from loggers. Unused here. 58 /// </summary> 59 /// <param name="e">The exception</param> LoggingException(Exception e)60 public void LoggingException(Exception e) 61 { 62 } 63 64 /// <summary> 65 /// Sets up to run tests. Creates the host object. 66 /// </summary> TargetBuilder_Tests()67 public TargetBuilder_Tests() 68 { 69 _nodeRequestId = 1; 70 _host = new MockHost(); 71 _mockLogger = new MockLogger(); 72 _host.OnLoggingThreadException += this.LoggingException; 73 } 74 75 /// <summary> 76 /// Executed after all tests are run. 77 /// </summary> Dispose()78 public void Dispose() 79 { 80 File.Delete("testProject.proj"); 81 _mockLogger = null; 82 _host = null; 83 } 84 85 /// <summary> 86 /// Runs the constructor. 87 /// </summary> 88 [Fact] TestConstructor()89 public void TestConstructor() 90 { 91 TargetBuilder builder = new TargetBuilder(); 92 } 93 94 /// <summary> 95 /// Runs a "simple" build with no dependencies and no outputs. 96 /// </summary> 97 [Fact] TestSimpleBuild()98 public void TestSimpleBuild() 99 { 100 ProjectInstance project = CreateTestProject(); 101 102 // The Empty target has no inputs or outputs. 103 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 104 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 105 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Empty" }), cache[1]); 106 107 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 108 Assert.True(result.HasResultsForTarget("Empty")); 109 Assert.Equal(TargetResultCode.Success, result["Empty"].ResultCode); 110 Assert.Equal(0, result["Empty"].Items.Length); 111 } 112 113 /// <summary> 114 /// Runs a build with a target which depends on one other target. 115 /// </summary> 116 [Fact] TestDependencyBuild()117 public void TestDependencyBuild() 118 { 119 ProjectInstance project = CreateTestProject(); 120 121 // The Baz project depends on the Bar target. Both should succeed. 122 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 123 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 124 125 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Baz" }), cache[1]); 126 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 127 128 // The result returned from the builder includes only those for the specified targets. 129 Assert.True(result.HasResultsForTarget("Baz")); 130 Assert.False(result.HasResultsForTarget("Bar")); 131 Assert.Equal(TargetResultCode.Success, result["Baz"].ResultCode); 132 133 // The results cache should have ALL of the results. 134 IResultsCache resultsCache = (IResultsCache)_host.GetComponent(BuildComponentType.ResultsCache); 135 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Bar")); 136 Assert.Equal(TargetResultCode.Success, resultsCache.GetResultForRequest(entry.Request)["Bar"].ResultCode); 137 } 138 139 /// <summary> 140 /// Tests a project with a dependency which will be skipped because its up-to-date. 141 /// </summary> 142 [Fact] TestDependencyBuildWithSkip()143 public void TestDependencyBuildWithSkip() 144 { 145 ProjectInstance project = CreateTestProject(); 146 147 // DepSkip depends on Skip (which skips) but should succeed itself. 148 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 149 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 150 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "DepSkip" }), cache[1]); 151 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 152 Assert.True(result.HasResultsForTarget("DepSkip")); 153 Assert.False(result.HasResultsForTarget("Skip")); 154 Assert.Equal(TargetResultCode.Success, result["DepSkip"].ResultCode); 155 156 IResultsCache resultsCache = (IResultsCache)_host.GetComponent(BuildComponentType.ResultsCache); 157 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("SkipCondition")); 158 Assert.Equal(TargetResultCode.Skipped, resultsCache.GetResultForRequest(entry.Request)["SkipCondition"].ResultCode); 159 } 160 161 /// <summary> 162 /// This test is currently ignored because the error tasks aren't implemented yet (due to needing the task builder.) 163 /// </summary> 164 [Fact] TestDependencyBuildWithError()165 public void TestDependencyBuildWithError() 166 { 167 ProjectInstance project = CreateTestProject(); 168 169 // The DepError target builds Foo (which succeeds), Skip (which skips) and Error (which fails), and Baz2 170 // Baz2 should not run since it came after Error. 171 // Error tries to build Foo again as an error (which is already built) and Bar, which produces outputs. 172 // DepError builds Baz as an error, which produces outputs 173 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 174 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 175 taskBuilder.FailTaskNumber = 3; // Succeed on Foo's one task, and Error's first task, and fail the second. 176 177 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 178 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "DepError" }), cache[1]); 179 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 180 Assert.True(result.HasResultsForTarget("DepError")); 181 Assert.False(result.HasResultsForTarget("Foo")); 182 Assert.False(result.HasResultsForTarget("Skip")); 183 Assert.False(result.HasResultsForTarget("Error")); 184 Assert.False(result.HasResultsForTarget("Baz2")); 185 Assert.False(result.HasResultsForTarget("Bar")); 186 Assert.False(result.HasResultsForTarget("Baz")); 187 188 IResultsCache resultsCache = (IResultsCache)_host.GetComponent(BuildComponentType.ResultsCache); 189 190 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Foo")); 191 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Skip")); 192 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Error")); 193 Assert.False(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Baz2")); 194 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Bar")); 195 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Baz")); 196 Assert.Equal(TargetResultCode.Failure, resultsCache.GetResultForRequest(entry.Request)["DepError"].ResultCode); 197 Assert.Equal(TargetResultCode.Success, resultsCache.GetResultForRequest(entry.Request)["Foo"].ResultCode); 198 Assert.Equal(TargetResultCode.Success, resultsCache.GetResultForRequest(entry.Request)["Skip"].ResultCode); 199 Assert.Equal(TargetResultCode.Failure, resultsCache.GetResultForRequest(entry.Request)["Error"].ResultCode); 200 Assert.Equal(TargetResultCode.Success, resultsCache.GetResultForRequest(entry.Request)["Bar"].ResultCode); 201 Assert.Equal(TargetResultCode.Success, resultsCache.GetResultForRequest(entry.Request)["Baz"].ResultCode); 202 } 203 204 /// <summary> 205 /// Ensure that skipped targets only infer outputs once 206 /// </summary> 207 [Fact] SkippedTargetsShouldOnlyInferOutputsOnce()208 public void SkippedTargetsShouldOnlyInferOutputsOnce() 209 { 210 MockLogger logger = new MockLogger(); 211 212 string path = FileUtilities.GetTemporaryFile(); 213 214 Thread.Sleep(100); 215 216 string content = String.Format 217 ( 218 @" 219 <Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'> 220 221 <Target Name='Build' DependsOnTargets='GFA;GFT;DFTA;GAFT'> 222 <Message Text='Build: [@(Outs)]' /> 223 </Target> 224 225 226 <Target Name='GFA' Inputs='{0}' Outputs='{0}'> 227 <Message Text='GFA' /> 228 <CreateItem Include='GFA'> 229 <Output TaskParameter='Include' ItemName='Outs' /> 230 </CreateItem> 231 </Target> 232 <Target Name='GFT' Inputs='{0}' Outputs='{0}'> 233 <CreateItem Include='GFT'> 234 <Output TaskParameter='Include' ItemName='Outs' /> 235 </CreateItem> 236 <Message Text='GFT' /> 237 </Target> 238 <Target Name='DFTA' Inputs='{0}' Outputs='{0}'> 239 <CreateItem Include='DFTA'> 240 <Output TaskParameter='Include' ItemName='Outs' /> 241 </CreateItem> 242 <Message Text='DFTA' /> 243 </Target> 244 <Target Name='GAFT' Inputs='{0}' Outputs='{0}' DependsOnTargets='DFTA'> 245 <CreateItem Include='GAFT'> 246 <Output TaskParameter='Include' ItemName='Outs' /> 247 </CreateItem> 248 <Message Text='GAFT' /> 249 </Target> 250 </Project> 251 ", 252 path 253 ); 254 255 Project p = new Project(XmlReader.Create(new StringReader(content))); 256 p.Build(new string[] { "Build" }, new ILogger[] { logger }); 257 258 // There should be no duplicates in the list - if there are, then skipped targets are being inferred multiple times 259 logger.AssertLogContains("[GFA;GFT;DFTA;GAFT]"); 260 261 File.Delete(path); 262 } 263 264 /// <summary> 265 /// Test empty before targets 266 /// </summary> 267 [Fact] TestLegacyCallTarget()268 public void TestLegacyCallTarget() 269 { 270 string projectBody = @" 271 <Target Name='Build'> 272 <CallTarget Targets='Foo;Goo'/> 273 </Target> 274 275 <Target Name='Foo' DependsOnTargets='Foo2'> 276 <FooTarget/> 277 </Target> 278 279 <Target Name='Goo'> 280 <GooTarget/> 281 </Target> 282 283 <Target Name='Foo2'> 284 <Foo2Target/> 285 </Target> 286 "; 287 288 ProjectInstance project = CreateTestProject(projectBody); 289 290 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 291 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 292 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 293 294 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 295 AssertTaskExecutionOrder(new string[] { "CallTarget", "Foo2Target", "FooTarget", "GooTarget" }); 296 } 297 298 /// <summary> 299 /// BeforeTargets specifies a missing target. Should not warn or error. 300 /// </summary> 301 [Fact] TestBeforeTargetsMissing()302 public void TestBeforeTargetsMissing() 303 { 304 string content = @" 305 <Project DefaultTargets='t' xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> 306 307 <Target Name='t' BeforeTargets='x'> 308 <Message Text='[t]' /> 309 </Target> 310 </Project> 311 "; 312 313 MockLogger log = Helpers.BuildProjectWithNewOMExpectSuccess(content); 314 315 log.AssertLogContains("[t]"); 316 log.AssertLogDoesntContain("MSB4057"); // missing target 317 log.AssertNoErrors(); 318 log.AssertNoWarnings(); 319 } 320 321 /// <summary> 322 /// BeforeTargets specifies a missing target. Should not warn or error. 323 /// </summary> 324 [Fact] TestBeforeTargetsMissingRunsOthers()325 public void TestBeforeTargetsMissingRunsOthers() 326 { 327 string content = @" 328 <Project DefaultTargets='a;c' xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> 329 330 <Target Name='t' BeforeTargets='a;b;c'> 331 <Message Text='[t]' /> 332 </Target> 333 334 <Target Name='a'> 335 <Message Text='[a]' /> 336 </Target> 337 338 <Target Name='c'> 339 <Message Text='[c]' /> 340 </Target> 341 342 </Project> 343 "; 344 345 MockLogger log = Helpers.BuildProjectWithNewOMExpectSuccess(content); 346 347 log.AssertLogContains("[t]", "[a]", "[c]"); 348 log.AssertLogDoesntContain("MSB4057"); // missing target 349 log.AssertNoErrors(); 350 log.AssertNoWarnings(); 351 } 352 353 /// <summary> 354 /// AfterTargets specifies a missing target. Should not warn or error. 355 /// </summary> 356 [Fact] TestAfterTargetsMissing()357 public void TestAfterTargetsMissing() 358 { 359 string content = @" 360 <Project DefaultTargets='t' xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> 361 362 <Target Name='t' AfterTargets='x'> 363 <Message Text='[t]' /> 364 </Target> 365 </Project> 366 "; 367 368 MockLogger log = Helpers.BuildProjectWithNewOMExpectSuccess(content); 369 370 log.AssertLogContains("[t]"); 371 log.AssertLogDoesntContain("MSB4057"); // missing target 372 log.AssertNoErrors(); 373 log.AssertNoWarnings(); 374 } 375 376 /// <summary> 377 /// AfterTargets specifies a missing target. Should not warn or error. 378 /// </summary> 379 [Fact] TestAfterTargetsMissingRunsOthers()380 public void TestAfterTargetsMissingRunsOthers() 381 { 382 string content = @" 383 <Project DefaultTargets='a;c' xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> 384 385 <Target Name='t' AfterTargets='a;b'> 386 <Message Text='[t]' /> 387 </Target> 388 389 <Target Name='t2' AfterTargets='b;c'> 390 <Message Text='[t2]' /> 391 </Target> 392 393 <Target Name='a'> 394 <Message Text='[a]' /> 395 </Target> 396 397 <Target Name='c'> 398 <Message Text='[c]' /> 399 </Target> 400 401 </Project> 402 "; 403 404 MockLogger log = Helpers.BuildProjectWithNewOMExpectSuccess(content); 405 406 log.AssertLogContains("[a]", "[t]", "[c]", "[t2]"); 407 log.AssertLogDoesntContain("MSB4057"); // missing target 408 log.AssertNoErrors(); 409 log.AssertNoWarnings(); 410 } 411 412 /// <summary> 413 /// Test empty before targets 414 /// </summary> 415 [Fact] TestBeforeTargetsEmpty()416 public void TestBeforeTargetsEmpty() 417 { 418 string projectBody = @" 419 <Target Name='Build'> 420 <BuildTask/> 421 </Target> 422 423 <Target Name='Before' BeforeTargets=''> 424 <BeforeTask/> 425 </Target>"; 426 427 ProjectInstance project = CreateTestProject(projectBody); 428 429 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 430 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 431 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 432 433 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 434 AssertTaskExecutionOrder(new string[] { "BuildTask" }); 435 } 436 437 /// <summary> 438 /// Test single before targets 439 /// </summary> 440 [Fact] TestBeforeTargetsSingle()441 public void TestBeforeTargetsSingle() 442 { 443 string projectBody = @" 444 <Target Name='Build' Outputs='$(Test)'> 445 <BuildTask/> 446 </Target> 447 448 <Target Name='Before' BeforeTargets='Build'> 449 <BeforeTask/> 450 </Target>"; 451 452 ProjectInstance project = CreateTestProject(projectBody); 453 454 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 455 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 456 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 457 458 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 459 AssertTaskExecutionOrder(new string[] { "BeforeTask", "BuildTask" }); 460 } 461 462 /// <summary> 463 /// Test single before targets on an escaped target 464 /// </summary> 465 [Fact] TestBeforeTargetsEscaped()466 public void TestBeforeTargetsEscaped() 467 { 468 string projectBody = @" 469 <Target Name='Build;Me' Outputs='$(Test)'> 470 <BuildTask/> 471 </Target> 472 473 <Target Name='Before' BeforeTargets='Build%3bMe'> 474 <BeforeTask/> 475 </Target>"; 476 477 ProjectInstance project = CreateTestProject(projectBody); 478 479 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 480 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 481 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build;Me" }), cache[1]); 482 483 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 484 AssertTaskExecutionOrder(new string[] { "BeforeTask", "BuildTask" }); 485 } 486 487 /// <summary> 488 /// Test single before targets 489 /// </summary> 490 [Fact] TestBeforeTargetsSingleWithError()491 public void TestBeforeTargetsSingleWithError() 492 { 493 string projectBody = @" 494 <Target Name='Before' BeforeTargets='Build'> 495 <BeforeTask/> 496 </Target> 497 498 <Target Name='Build'> 499 <BuildTask/> 500 </Target> 501 "; 502 503 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 504 taskBuilder.FailTaskNumber = 2; // Succeed on BeforeTask, fail on BuildTask 505 506 ProjectInstance project = CreateTestProject(projectBody); 507 508 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 509 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 510 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 511 512 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 513 AssertTaskExecutionOrder(new string[] { "BeforeTask", "BuildTask" }); 514 } 515 516 /// <summary> 517 /// Test single before targets 518 /// </summary> 519 [Fact] TestBeforeTargetsSingleWithErrorAndParent()520 public void TestBeforeTargetsSingleWithErrorAndParent() 521 { 522 string projectBody = @" 523 <Target Name='Before' BeforeTargets='Build'> 524 <BeforeTask/> 525 </Target> 526 527 <Target Name='Build'> 528 <BuildTask/> 529 <OnError ExecuteTargets='ErrorTarget'/> 530 </Target> 531 532 <Target Name='ErrorTarget'> 533 <Error/> 534 </Target> 535 "; 536 537 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 538 taskBuilder.FailTaskNumber = 2; // Succeed on BeforeTask, fail on BuildTask 539 540 ProjectInstance project = CreateTestProject(projectBody); 541 542 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 543 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 544 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 545 546 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 547 AssertTaskExecutionOrder(new string[] { "BeforeTask", "BuildTask", "Error" }); 548 } 549 550 /// <summary> 551 /// Test multiple before targets 552 /// </summary> 553 [Fact] TestBeforeTargetsWithTwoReferringToOne()554 public void TestBeforeTargetsWithTwoReferringToOne() 555 { 556 string projectBody = @" 557 <Target Name='Build' Outputs='$(Test)'> 558 <BuildTask/> 559 </Target> 560 561 <Target Name='Before' BeforeTargets='Build'> 562 <BeforeTask/> 563 </Target> 564 565 566 <Target Name='Before2' BeforeTargets='Build'> 567 <BeforeTask2/> 568 </Target> 569 "; 570 571 ProjectInstance project = CreateTestProject(projectBody); 572 573 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 574 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 575 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 576 577 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 578 AssertTaskExecutionOrder(new string[] { "BeforeTask", "BeforeTask2", "BuildTask" }); 579 } 580 581 /// <summary> 582 /// Test multiple before targets 583 /// </summary> 584 [Fact] TestBeforeTargetsWithOneReferringToTwo()585 public void TestBeforeTargetsWithOneReferringToTwo() 586 { 587 string projectBody = @" 588 <Target Name='Build' Outputs='$(Test)'> 589 <BuildTask/> 590 </Target> 591 592 <Target Name='Foo' Outputs='$(Test)'> 593 <FooTask/> 594 </Target> 595 596 <Target Name='Before' BeforeTargets='Build;Foo'> 597 <BeforeTask/> 598 </Target> 599 "; 600 601 ProjectInstance project = CreateTestProject(projectBody); 602 603 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 604 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 605 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Foo" }), cache[1]); 606 607 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 608 AssertTaskExecutionOrder(new string[] { "BeforeTask", "FooTask" }); 609 } 610 611 /// <summary> 612 /// Test before target on a skipped target 613 /// </summary> 614 [Fact] TestBeforeTargetsSkip()615 public void TestBeforeTargetsSkip() 616 { 617 string projectBody = @" 618 <Target Name='Build' Condition=""'0'=='1'""> 619 <BuildTask/> 620 </Target> 621 622 <Target Name='Before' BeforeTargets='Build'> 623 <BeforeTask/> 624 </Target>"; 625 626 ProjectInstance project = CreateTestProject(projectBody); 627 628 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 629 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 630 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 631 632 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 633 AssertTaskExecutionOrder(new string[] { "BeforeTask" }); 634 } 635 636 /// <summary> 637 /// Test before target on a skipped target 638 /// </summary> 639 [Fact] TestBeforeTargetsDependencyOrdering()640 public void TestBeforeTargetsDependencyOrdering() 641 { 642 string projectBody = @" 643 <Target Name='Build' DependsOnTargets='BuildDep'> 644 <BuildTask/> 645 </Target> 646 647 <Target Name='Before' DependsOnTargets='BeforeDep' BeforeTargets='Build'> 648 <BeforeTask/> 649 </Target> 650 651 <Target Name='BuildDep'> 652 <BuildDepTask/> 653 </Target> 654 655 <Target Name='BeforeDep'> 656 <BeforeDepTask/> 657 </Target> 658 659 "; 660 661 ProjectInstance project = CreateTestProject(projectBody); 662 663 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 664 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 665 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 666 667 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 668 AssertTaskExecutionOrder(new string[] { "BuildDepTask", "BeforeDepTask", "BeforeTask", "BuildTask" }); 669 } 670 671 /// <summary> 672 /// Test after target on a skipped target 673 /// </summary> 674 [Fact] TestAfterTargetsEmpty()675 public void TestAfterTargetsEmpty() 676 { 677 string projectBody = @" 678 <Target Name='Build'> 679 <BuildTask/> 680 </Target> 681 682 <Target Name='After' AfterTargets=''> 683 <AfterTask/> 684 </Target>"; 685 686 ProjectInstance project = CreateTestProject(projectBody); 687 688 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 689 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 690 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 691 692 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 693 AssertTaskExecutionOrder(new string[] { "BuildTask" }); 694 } 695 696 /// <summary> 697 /// Test after target on a skipped target 698 /// </summary> 699 [Fact] TestAfterTargetsSkip()700 public void TestAfterTargetsSkip() 701 { 702 string projectBody = @" 703 <Target Name='Build' Condition=""'0'=='1'""> 704 <BuildTask/> 705 </Target> 706 707 <Target Name='After' AfterTargets='Build'> 708 <AfterTask/> 709 </Target>"; 710 711 ProjectInstance project = CreateTestProject(projectBody); 712 713 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 714 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 715 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 716 717 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 718 AssertTaskExecutionOrder(new string[] { "AfterTask" }); 719 } 720 721 /// <summary> 722 /// Test single before targets 723 /// </summary> 724 [Fact] TestAfterTargetsSingleWithError()725 public void TestAfterTargetsSingleWithError() 726 { 727 string projectBody = @" 728 <Target Name='Build'> 729 <BuildTask/> 730 </Target> 731 732 <Target Name='After' AfterTargets='Build'> 733 <AfterTask/> 734 </Target>"; 735 736 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 737 taskBuilder.FailTaskNumber = 1; // Fail on BuildTask 738 739 ProjectInstance project = CreateTestProject(projectBody); 740 741 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 742 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 743 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 744 745 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 746 AssertTaskExecutionOrder(new string[] { "BuildTask" }); 747 } 748 749 /// <summary> 750 /// Test single before targets 751 /// </summary> 752 [Fact] TestAfterTargetsSingleWithErrorAndParent()753 public void TestAfterTargetsSingleWithErrorAndParent() 754 { 755 string projectBody = @" 756 <Target Name='After' AfterTargets='Build'> 757 <AfterTask/> 758 </Target> 759 760 <Target Name='Build'> 761 <BuildTask/> 762 <OnError ExecuteTargets='ErrorTarget'/> 763 </Target> 764 765 <Target Name='ErrorTarget'> 766 <Error/> 767 </Target> 768 769 <Target Name='ErrorTarget2'> 770 <Error2/> 771 </Target> 772 773 <Target Name='PostBuild' DependsOnTargets='Build'> 774 <OnError ExecuteTargets='ErrorTarget2'/> 775 </Target> 776 "; 777 778 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 779 taskBuilder.FailTaskNumber = 2; // Succeed on BuildTask, fail on AfterTask 780 781 ProjectInstance project = CreateTestProject(projectBody); 782 783 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 784 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 785 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "PostBuild" }), cache[1]); 786 787 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 788 AssertTaskExecutionOrder(new string[] { "BuildTask", "AfterTask", "Error2" }); 789 } 790 791 /// <summary> 792 /// Test after target on a normal target 793 /// </summary> 794 [Fact] TestAfterTargetsSingle()795 public void TestAfterTargetsSingle() 796 { 797 string projectBody = @" 798 <Target Name='Build'> 799 <BuildTask/> 800 </Target> 801 802 <Target Name='After' AfterTargets='Build'> 803 <AfterTask/> 804 </Target>"; 805 806 ProjectInstance project = CreateTestProject(projectBody); 807 808 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 809 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 810 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 811 812 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 813 AssertTaskExecutionOrder(new string[] { "BuildTask", "AfterTask" }); 814 } 815 816 /// <summary> 817 /// Test after target on a target name which needs escaping 818 /// </summary> 819 [Fact] TestAfterTargetsEscaped()820 public void TestAfterTargetsEscaped() 821 { 822 string projectBody = @" 823 <Target Name='Build;Me'> 824 <BuildTask/> 825 </Target> 826 827 <Target Name='After' AfterTargets='Build%3bMe'> 828 <AfterTask/> 829 </Target>"; 830 831 ProjectInstance project = CreateTestProject(projectBody); 832 833 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 834 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 835 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build;Me" }), cache[1]); 836 837 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 838 AssertTaskExecutionOrder(new string[] { "BuildTask", "AfterTask" }); 839 } 840 841 /// <summary> 842 /// Test after target on a skipped target 843 /// </summary> 844 [Fact] TestAfterTargetsWithTwoReferringToOne()845 public void TestAfterTargetsWithTwoReferringToOne() 846 { 847 string projectBody = @" 848 <Target Name='Build'> 849 <BuildTask/> 850 </Target> 851 852 <Target Name='After' AfterTargets='Build'> 853 <AfterTask/> 854 </Target> 855 856 <Target Name='After2' AfterTargets='Build'> 857 <AfterTask2/> 858 </Target> 859 "; 860 861 ProjectInstance project = CreateTestProject(projectBody); 862 863 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 864 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 865 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 866 867 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 868 AssertTaskExecutionOrder(new string[] { "BuildTask", "AfterTask", "AfterTask2" }); 869 } 870 871 /// <summary> 872 /// Test after target on a skipped target 873 /// </summary> 874 [Fact] TestAfterTargetsWithOneReferringToTwo()875 public void TestAfterTargetsWithOneReferringToTwo() 876 { 877 string projectBody = @" 878 <Target Name='Build'> 879 <BuildTask/> 880 </Target> 881 882 <Target Name='Foo'> 883 <FooTask/> 884 </Target> 885 886 <Target Name='After' AfterTargets='Build;Foo'> 887 <AfterTask/> 888 </Target> 889 "; 890 891 ProjectInstance project = CreateTestProject(projectBody); 892 893 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 894 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 895 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Foo" }), cache[1]); 896 897 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 898 AssertTaskExecutionOrder(new string[] { "FooTask", "AfterTask" }); 899 } 900 901 /// <summary> 902 /// Test after target on a skipped target 903 /// </summary> 904 [Fact] TestAfterTargetsWithDependencyOrdering()905 public void TestAfterTargetsWithDependencyOrdering() 906 { 907 string projectBody = @" 908 <Target Name='Build' DependsOnTargets='BuildDep'> 909 <BuildTask/> 910 </Target> 911 912 <Target Name='After' DependsOnTargets='AfterDep' AfterTargets='Build'> 913 <AfterTask/> 914 </Target> 915 916 <Target Name='BuildDep'> 917 <BuildDepTask/> 918 </Target> 919 920 <Target Name='AfterDep'> 921 <AfterDepTask/> 922 </Target> 923 "; 924 925 ProjectInstance project = CreateTestProject(projectBody); 926 927 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 928 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 929 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 930 931 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 932 AssertTaskExecutionOrder(new string[] { "BuildDepTask", "BuildTask", "AfterDepTask", "AfterTask" }); 933 } 934 935 /// <summary> 936 /// Test a complex ordering with depends, before and after targets 937 /// </summary> 938 [Fact] TestComplexOrdering()939 public void TestComplexOrdering() 940 { 941 string projectBody = @" 942 <Target Name='Build' DependsOnTargets='BuildDep'> 943 <BuildTask/> 944 </Target> 945 946 <Target Name='Before' DependsOnTargets='BeforeDep' BeforeTargets='Build'> 947 <BeforeTask/> 948 </Target> 949 950 <Target Name='After' DependsOnTargets='AfterDep' AfterTargets='Build'> 951 <AfterTask/> 952 </Target> 953 954 <Target Name='BuildDep'> 955 <BuildDepTask/> 956 </Target> 957 958 <Target Name='AfterDep' DependsOnTargets='AfterDepDep'> 959 <AfterDepTask/> 960 </Target> 961 962 <Target Name='BeforeDep' DependsOnTargets='BeforeDepDep'> 963 <BeforeDepTask/> 964 </Target> 965 966 <Target Name='BeforeDepDep'> 967 <BeforeDepDepTask/> 968 </Target> 969 970 <Target Name='AfterDepDep'> 971 <AfterDepDepTask/> 972 </Target> 973 "; 974 975 ProjectInstance project = CreateTestProject(projectBody); 976 977 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 978 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 979 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 980 981 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 982 AssertTaskExecutionOrder(new string[] { "BuildDepTask", "BeforeDepDepTask", "BeforeDepTask", "BeforeTask", "BuildTask", "AfterDepDepTask", "AfterDepTask", "AfterTask" }); 983 } 984 985 /// <summary> 986 /// Test a complex ordering with depends, before and after targets 987 /// </summary> 988 [Fact] TestComplexOrdering2()989 public void TestComplexOrdering2() 990 { 991 string projectBody = @" 992 <Target Name='BuildDep'> 993 <BuildDepTask/> 994 </Target> 995 996 <Target Name='BeforeDepDep'> 997 <BeforeDepDepTask/> 998 </Target> 999 1000 <Target Name='BeforeBeforeDep' BeforeTargets='BeforeDep'> 1001 <BeforeBeforeDepTask/> 1002 </Target> 1003 1004 <Target Name='AfterBeforeBeforeDep' AfterTargets='BeforeBeforeDep'> 1005 <AfterBeforeBeforeDepTask/> 1006 </Target> 1007 1008 <Target Name='BeforeDep' DependsOnTargets='BeforeDepDep'> 1009 <BeforeDepTask/> 1010 </Target> 1011 1012 <Target Name='Before' DependsOnTargets='BeforeDep' BeforeTargets='Build'> 1013 <BeforeTask/> 1014 </Target> 1015 1016 <Target Name='AfterBeforeDepDep'> 1017 <AfterBeforeDepDepTask/> 1018 </Target> 1019 1020 <Target Name='AfterBeforeDep' DependsOnTargets='AfterBeforeDepDep'> 1021 <AfterBeforeDepTask/> 1022 </Target> 1023 1024 <Target Name='AfterBefore' DependsOnTargets='AfterBeforeDep' AfterTargets='Before'> 1025 <AfterBeforeTask/> 1026 </Target> 1027 1028 <Target Name='Build' DependsOnTargets='BuildDep'> 1029 <BuildTask/> 1030 </Target> 1031 1032 "; 1033 1034 ProjectInstance project = CreateTestProject(projectBody); 1035 1036 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 1037 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1038 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 1039 1040 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 1041 AssertTaskExecutionOrder(new string[] { "BuildDepTask", "BeforeDepDepTask", "BeforeBeforeDepTask", "AfterBeforeBeforeDepTask", "BeforeDepTask", "BeforeTask", "AfterBeforeDepDepTask", "AfterBeforeDepTask", "AfterBeforeTask", "BuildTask" }); 1042 } 1043 1044 /// <summary> 1045 /// Test a complex ordering with depends, before and after targets 1046 /// </summary> 1047 [Fact] TestBeforeAndAfterWithErrorTargets()1048 public void TestBeforeAndAfterWithErrorTargets() 1049 { 1050 string projectBody = @" 1051 1052 1053 <Target Name='Build' > 1054 <BuildTask/> 1055 <OnError ExecuteTargets='ErrorTarget'/> 1056 </Target> 1057 1058 <Target Name='ErrorTarget'> 1059 <ErrorTargetTask/> 1060 </Target> 1061 1062 <Target Name='BeforeErrorTarget' BeforeTargets='ErrorTarget'> 1063 <BeforeErrorTargetTask/> 1064 </Target> 1065 1066 <Target Name='AfterErrorTarget' AfterTargets='ErrorTarget'> 1067 <AfterErrorTargetTask/> 1068 </Target> 1069 1070 "; 1071 1072 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 1073 taskBuilder.FailTaskNumber = 1; // Fail on BuildTask 1074 1075 ProjectInstance project = CreateTestProject(projectBody); 1076 1077 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 1078 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1079 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 1080 1081 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 1082 AssertTaskExecutionOrder(new string[] { "BuildTask", "BeforeErrorTargetTask", "ErrorTargetTask", "AfterErrorTargetTask" }); 1083 } 1084 1085 /// <summary> 1086 /// Test after target on a skipped target 1087 /// </summary> 1088 [Fact] TestBeforeAndAfterOverrides()1089 public void TestBeforeAndAfterOverrides() 1090 { 1091 string projectBody = @" 1092 1093 <Target Name='BuildDep'> 1094 <BuildDepTask/> 1095 </Target> 1096 1097 <Target Name='Build' DependsOnTargets='BuildDep'> 1098 <BuildTask/> 1099 </Target> 1100 1101 <Target Name='After' AfterTargets='Build'> 1102 <AfterTask/> 1103 </Target> 1104 1105 <Target Name='After' AfterTargets='BuildDep'> 1106 <AfterTask/> 1107 </Target> 1108 1109 <Target Name='Before' BeforeTargets='Build'> 1110 <BeforeTask/> 1111 </Target> 1112 1113 <Target Name='Before' BeforeTargets='BuildDep'> 1114 <BeforeTask/> 1115 </Target> 1116 1117 "; 1118 1119 ProjectInstance project = CreateTestProject(projectBody); 1120 1121 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 1122 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1123 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 1124 1125 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 1126 AssertTaskExecutionOrder(new string[] { "BeforeTask", "BuildDepTask", "AfterTask", "BuildTask" }); 1127 } 1128 1129 /// <summary> 1130 /// Test that if before and after targets skip, the main target still runs (bug 476908) 1131 /// </summary> 1132 [Fact] TestSkippingBeforeAndAfterTargets()1133 public void TestSkippingBeforeAndAfterTargets() 1134 { 1135 string projectBody = @" 1136 <Target Name='Build'> 1137 <BuildTask/> 1138 </Target> 1139 1140 <Target Name='Before' BeforeTargets='Build' Condition=""'0'=='1'""> 1141 <BeforeTask/> 1142 </Target> 1143 1144 <Target Name='After' AfterTargets='Build' Condition=""'0'=='1'""> 1145 <AfterTask/> 1146 </Target> 1147 "; 1148 1149 ProjectInstance project = CreateTestProject(projectBody); 1150 1151 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 1152 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1153 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 1154 1155 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 1156 AssertTaskExecutionOrder(new string[] { "BuildTask" }); 1157 } 1158 1159 /// <summary> 1160 /// Tests that a circular dependency within a CallTarget call correctly propagates the failure. Bug 502570. 1161 /// </summary> 1162 [Fact] TestCircularDependencyInCallTarget()1163 public void TestCircularDependencyInCallTarget() 1164 { 1165 string projectContents = @" 1166 <Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003""> 1167 <Target Name=""t1""> 1168 <CallTarget Targets=""t3""/> 1169 </Target> 1170 <Target Name=""t2"" DependsOnTargets=""t1""> 1171 </Target> 1172 <Target Name=""t3"" DependsOnTargets=""t2""> 1173 </Target> 1174 </Project> 1175 "; 1176 StringReader reader = new StringReader(projectContents); 1177 #if FEATURE_XMLTEXTREADER 1178 Project project = new Project(new XmlTextReader(reader), null, null); 1179 #else 1180 Project project = new Project(XmlReader.Create(reader), null, null); 1181 #endif 1182 bool success = project.Build(_mockLogger); 1183 Assert.False(success); 1184 } 1185 1186 /// <summary> 1187 /// Tests that cancel with no entries after building does not fail. 1188 /// </summary> 1189 [Fact] TestCancelWithNoEntriesAfterBuild()1190 public void TestCancelWithNoEntriesAfterBuild() 1191 { 1192 string projectBody = @" 1193 <Target Name='Build'> 1194 <BuildTask/> 1195 </Target> 1196 "; 1197 1198 ProjectInstance project = CreateTestProject(projectBody); 1199 1200 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 1201 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1202 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new string[] { "Build" }), cache[1]); 1203 using (CancellationTokenSource source = new CancellationTokenSource()) 1204 { 1205 BuildResult result = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), source.Token).Result; 1206 AssertTaskExecutionOrder(new string[] { "BuildTask" }); 1207 1208 // This simply should not fail. 1209 source.Cancel(); 1210 } 1211 } 1212 1213 [Fact] SkippedTargetWithFailedDependenciesStopsBuild()1214 public void SkippedTargetWithFailedDependenciesStopsBuild() 1215 { 1216 string projectContents = @" 1217 <Target Name=""Build"" DependsOnTargets=""ProduceError1;ProduceError2"" /> 1218 <Target Name=""ProduceError1"" Condition=""false"" /> 1219 <Target Name=""ProduceError2""> 1220 <ErrorTask2 /> 1221 </Target> 1222 <Target Name=""_Error1"" BeforeTargets=""ProduceError1""> 1223 <ErrorTask1 /> 1224 </Target> 1225 "; 1226 1227 var project = CreateTestProject(projectContents, string.Empty, "Build"); 1228 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 1229 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 1230 // Fail the first task 1231 taskBuilder.FailTaskNumber = 1; 1232 1233 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1234 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new[] { "Build" }), cache[1]); 1235 1236 var buildResult = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 1237 1238 IResultsCache resultsCache = (IResultsCache)_host.GetComponent(BuildComponentType.ResultsCache); 1239 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("Build")); 1240 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("ProduceError1")); 1241 Assert.False(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("ProduceError2")); 1242 Assert.True(resultsCache.GetResultForRequest(entry.Request).HasResultsForTarget("_Error1")); 1243 1244 Assert.Equal(TargetResultCode.Failure, resultsCache.GetResultForRequest(entry.Request)["Build"].ResultCode); 1245 Assert.Equal(TargetResultCode.Skipped, resultsCache.GetResultForRequest(entry.Request)["ProduceError1"].ResultCode); 1246 Assert.Equal(TargetResultCode.Failure, resultsCache.GetResultForRequest(entry.Request)["_Error1"].ResultCode); 1247 } 1248 1249 [Fact] SkipNonexistentTargetsDoesNotExecuteOrCacheTargetResult()1250 public void SkipNonexistentTargetsDoesNotExecuteOrCacheTargetResult() 1251 { 1252 string projectContents = @"<Target Name=""Build"" />"; 1253 1254 var project = CreateTestProject(projectContents, string.Empty, "Build"); 1255 TargetBuilder builder = (TargetBuilder)_host.GetComponent(BuildComponentType.TargetBuilder); 1256 MockTaskBuilder taskBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 1257 taskBuilder.FailTaskNumber = 1; 1258 1259 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1260 BuildRequestEntry entry = new BuildRequestEntry(CreateNewBuildRequest(1, new[] { "NotFound" }, BuildRequestDataFlags.SkipNonexistentTargets), cache[1]); 1261 var buildResult = builder.BuildTargets(GetProjectLoggingContext(entry), entry, this, entry.Request.Targets.ToArray(), CreateStandardLookup(project), CancellationToken.None).Result; 1262 1263 IResultsCache resultsCache = (IResultsCache)_host.GetComponent(BuildComponentType.ResultsCache); 1264 1265 // This should throw because the results cache should not contain the results for the target that was not 1266 // executed. This is different than when a target is skipped due to condition not met where the result 1267 // would be in the cache. In this case we can't cache the result because it is only valid for the single 1268 // request. 1269 Assert.Throws<InternalErrorException>(() => resultsCache.GetResultForRequest(entry.Request)); 1270 } 1271 1272 #region IRequestBuilderCallback Members 1273 1274 /// <summary> 1275 /// We have to have this interface, but it won't be used in this test because we aren't doing MSBuild callbacks. 1276 /// </summary> 1277 /// <param name="projectFiles">N/A</param> 1278 /// <param name="properties">N/A</param> 1279 /// <param name="toolsVersions">N/A</param> 1280 /// <param name="targets">N/A</param> 1281 /// <param name="waitForResults">N/A</param> 1282 /// <param name="skipNonexistentTargets">N/A</param> 1283 /// <returns>N/A</returns> IRequestBuilderCallback.BuildProjects(string[] projectFiles, PropertyDictionary<ProjectPropertyInstance>[] properties, string[] toolsVersions, string[] targets, bool waitForResults, bool skipNonexistentTargets)1284 Task<BuildResult[]> IRequestBuilderCallback.BuildProjects(string[] projectFiles, PropertyDictionary<ProjectPropertyInstance>[] properties, string[] toolsVersions, string[] targets, bool waitForResults, bool skipNonexistentTargets) 1285 { 1286 throw new NotImplementedException(); 1287 } 1288 1289 /// <summary> 1290 /// Not implemented 1291 /// </summary> IRequestBuilderCallback.BlockOnTargetInProgress(int blockingRequestId, string blockingTarget, BuildResult partialBuildResult)1292 Task IRequestBuilderCallback.BlockOnTargetInProgress(int blockingRequestId, string blockingTarget, BuildResult partialBuildResult) 1293 { 1294 throw new NotImplementedException(); 1295 } 1296 1297 /// <summary> 1298 /// Empty impl 1299 /// </summary> IRequestBuilderCallback.Yield()1300 void IRequestBuilderCallback.Yield() 1301 { 1302 } 1303 1304 /// <summary> 1305 /// Empty impl 1306 /// </summary> IRequestBuilderCallback.Reacquire()1307 void IRequestBuilderCallback.Reacquire() 1308 { 1309 } 1310 1311 /// <summary> 1312 /// Empty impl 1313 /// </summary> IRequestBuilderCallback.EnterMSBuildCallbackState()1314 void IRequestBuilderCallback.EnterMSBuildCallbackState() 1315 { 1316 } 1317 1318 /// <summary> 1319 /// Empty impl 1320 /// </summary> IRequestBuilderCallback.ExitMSBuildCallbackState()1321 void IRequestBuilderCallback.ExitMSBuildCallbackState() 1322 { 1323 } 1324 1325 #endregion 1326 1327 /// <summary> 1328 /// Verifies the order in which tasks executed. 1329 /// </summary> AssertTaskExecutionOrder(string[] tasks)1330 private void AssertTaskExecutionOrder(string[] tasks) 1331 { 1332 MockTaskBuilder mockBuilder = (MockTaskBuilder)_host.GetComponent(BuildComponentType.TaskBuilder); 1333 1334 Assert.Equal(tasks.Length, mockBuilder.ExecutedTasks.Count); 1335 1336 int currentTask = 0; 1337 foreach (ProjectTaskInstance task in mockBuilder.ExecutedTasks) 1338 { 1339 Assert.True(String.Equals(task.Name, tasks[currentTask])); 1340 currentTask++; 1341 } 1342 } 1343 1344 /// <summary> 1345 /// Creates a new build request 1346 /// </summary> CreateNewBuildRequest(int configurationId, string[] targets, BuildRequestDataFlags flags = BuildRequestDataFlags.None)1347 private BuildRequest CreateNewBuildRequest(int configurationId, string[] targets, BuildRequestDataFlags flags = BuildRequestDataFlags.None) 1348 { 1349 return new BuildRequest(1 /* submissionId */, _nodeRequestId++, configurationId, targets, null, BuildEventContext.Invalid, null, flags); 1350 } 1351 1352 /// <summary> 1353 /// Creates a 'Lookup' used to deal with projects. 1354 /// </summary> 1355 /// <param name="project">The project for which to create the lookup</param> 1356 /// <returns>The lookup</returns> CreateStandardLookup(ProjectInstance project)1357 private Lookup CreateStandardLookup(ProjectInstance project) 1358 { 1359 Lookup lookup = new Lookup(new ItemDictionary<ProjectItemInstance>(project.Items), new PropertyDictionary<ProjectPropertyInstance>(project.Properties), null); 1360 return lookup; 1361 } 1362 1363 /// <summary> 1364 /// Creates a test project. 1365 /// </summary> 1366 /// <returns>The project.</returns> CreateTestProject()1367 private ProjectInstance CreateTestProject() 1368 { 1369 string projectBodyContents = @" 1370 <ItemGroup> 1371 <Compile Include='b.cs' /> 1372 <Compile Include='c.cs' /> 1373 </ItemGroup> 1374 1375 <ItemGroup> 1376 <Reference Include='System' /> 1377 </ItemGroup> 1378 1379 <Target Name='Empty' /> 1380 1381 <Target Name='Skip' Inputs='testProject.proj' Outputs='testProject.proj' /> 1382 1383 <Target Name='SkipCondition' Condition=""'true' == 'false'"" /> 1384 1385 <Target Name='Error' > 1386 <ErrorTask1 ContinueOnError='True'/> 1387 <ErrorTask2 ContinueOnError='False'/> 1388 <ErrorTask3 /> 1389 <OnError ExecuteTargets='Foo'/> 1390 <OnError ExecuteTargets='Bar'/> 1391 </Target> 1392 1393 <Target Name='DepError' DependsOnTargets='Foo;Skip;Error;Baz2'> 1394 <OnError ExecuteTargets='Baz'/> 1395 </Target> 1396 1397 <Target Name='Foo' Inputs='foo.cpp' Outputs='foo.o'> 1398 <FooTask1/> 1399 </Target> 1400 1401 <Target Name='Bar'> 1402 <BarTask1/> 1403 </Target> 1404 1405 <Target Name='Baz' DependsOnTargets='Bar'> 1406 <BazTask1/> 1407 <BazTask2/> 1408 </Target> 1409 1410 <Target Name='Baz2' DependsOnTargets='Bar;Foo'> 1411 <Baz2Task1/> 1412 <Baz2Task2/> 1413 <Baz2Task3/> 1414 </Target> 1415 1416 <Target Name='DepSkip' DependsOnTargets='SkipCondition'> 1417 <DepSkipTask1/> 1418 <DepSkipTask2/> 1419 <DepSkipTask3/> 1420 </Target> 1421 1422 <Target Name='DepSkip2' DependsOnTargets='Skip' Inputs='testProject.proj' Outputs='testProject.proj'> 1423 <DepSkipTask1/> 1424 <DepSkipTask2/> 1425 <DepSkipTask3/> 1426 </Target> 1427 "; 1428 1429 return CreateTestProject(projectBodyContents); 1430 } 1431 1432 /// <summary> 1433 /// Creates a test project. 1434 /// </summary> CreateTestProject(string projectBodyContents)1435 private ProjectInstance CreateTestProject(string projectBodyContents) 1436 { 1437 return CreateTestProject(projectBodyContents, String.Empty, String.Empty); 1438 } 1439 1440 /// <summary> 1441 /// Creates a test project. 1442 /// </summary> CreateTestProject(string projectBodyContents, string initialTargets, string defaultTargets)1443 private ProjectInstance CreateTestProject(string projectBodyContents, string initialTargets, string defaultTargets) 1444 { 1445 string projectFileContents = String.Format("<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='http://schemas.microsoft.com/developer/msbuild/2003' InitialTargets='{0}' DefaultTargets='{1}'>{2}</Project>", initialTargets, defaultTargets, projectBodyContents); 1446 1447 // retries to deal with occasional locking issues where the file can't be written to initially 1448 for (int retries = 0; retries < 5; retries++) 1449 { 1450 try 1451 { 1452 File.Create("testProject.proj").Dispose(); 1453 break; 1454 } 1455 catch (Exception ex) 1456 { 1457 if (retries < 4) 1458 { 1459 Console.WriteLine(ex.ToString()); 1460 } 1461 else 1462 { 1463 // All the retries have failed. We will now fail with the 1464 // actual problem now instead of with some more difficult-to-understand 1465 // issue later. 1466 throw; 1467 } 1468 } 1469 } 1470 1471 IConfigCache cache = (IConfigCache)_host.GetComponent(BuildComponentType.ConfigCache); 1472 BuildRequestConfiguration config = new BuildRequestConfiguration(1, new BuildRequestData("testFile", new Dictionary<string, string>(), "3.5", new string[0], null), "2.0"); 1473 Project project = new Project(XmlReader.Create(new StringReader(projectFileContents))); 1474 1475 config.Project = project.CreateProjectInstance(); 1476 cache.AddConfiguration(config); 1477 1478 return config.Project; 1479 } 1480 1481 /// <summary> 1482 /// Creates a project logging context. 1483 /// </summary> 1484 /// <param name="entry">The entry on which to base the logging context.</param> 1485 /// <returns>The context</returns> GetProjectLoggingContext(BuildRequestEntry entry)1486 private ProjectLoggingContext GetProjectLoggingContext(BuildRequestEntry entry) 1487 { 1488 return new ProjectLoggingContext(new NodeLoggingContext(_host, 1, false), entry, null); 1489 } 1490 1491 /// <summary> 1492 /// The mock component host object. 1493 /// </summary> 1494 private class MockHost : MockLoggingService, IBuildComponentHost, IBuildComponent 1495 { 1496 #region IBuildComponentHost Members 1497 1498 /// <summary> 1499 /// The config cache 1500 /// </summary> 1501 private IConfigCache _configCache; 1502 1503 /// <summary> 1504 /// The logging service 1505 /// </summary> 1506 private ILoggingService _loggingService; 1507 1508 /// <summary> 1509 /// The results cache 1510 /// </summary> 1511 private IResultsCache _resultsCache; 1512 1513 /// <summary> 1514 /// The request builder 1515 /// </summary> 1516 private IRequestBuilder _requestBuilder; 1517 1518 /// <summary> 1519 /// The mock task builder 1520 /// </summary> 1521 private ITaskBuilder _taskBuilder; 1522 1523 /// <summary> 1524 /// The target builder 1525 /// </summary> 1526 private ITargetBuilder _targetBuilder; 1527 1528 /// <summary> 1529 /// The build parameters 1530 /// </summary> 1531 private BuildParameters _buildParameters; 1532 1533 /// <summary> 1534 /// Retrieves the LegacyThreadingData associated with a particular component host 1535 /// </summary> 1536 private LegacyThreadingData _legacyThreadingData; 1537 1538 private ISdkResolverService _sdkResolverService; 1539 1540 /// <summary> 1541 /// Constructor 1542 /// </summary> MockHost()1543 public MockHost() 1544 { 1545 _buildParameters = new BuildParameters(); 1546 _legacyThreadingData = new LegacyThreadingData(); 1547 1548 _configCache = new ConfigCache(); 1549 ((IBuildComponent)_configCache).InitializeComponent(this); 1550 1551 _loggingService = this; 1552 1553 _resultsCache = new ResultsCache(); 1554 ((IBuildComponent)_resultsCache).InitializeComponent(this); 1555 1556 _requestBuilder = new RequestBuilder(); 1557 ((IBuildComponent)_requestBuilder).InitializeComponent(this); 1558 1559 _taskBuilder = new MockTaskBuilder(); 1560 ((IBuildComponent)_taskBuilder).InitializeComponent(this); 1561 1562 _targetBuilder = new TargetBuilder(); 1563 ((IBuildComponent)_targetBuilder).InitializeComponent(this); 1564 1565 _sdkResolverService = new MockSdkResolverService(); 1566 ((IBuildComponent)_sdkResolverService).InitializeComponent(this); 1567 } 1568 1569 /// <summary> 1570 /// Returns the node logging service. We don't distinguish here. 1571 /// </summary> 1572 /// <returns>The logging service.</returns> 1573 public ILoggingService LoggingService 1574 { 1575 get 1576 { 1577 return _loggingService; 1578 } 1579 } 1580 1581 /// <summary> 1582 /// Retrieves the LegacyThreadingData associated with a particular component host 1583 /// </summary> 1584 LegacyThreadingData IBuildComponentHost.LegacyThreadingData 1585 { 1586 get 1587 { 1588 return _legacyThreadingData; 1589 } 1590 } 1591 1592 /// <summary> 1593 /// Retrieves the name of the host. 1594 /// </summary> 1595 public string Name 1596 { 1597 get 1598 { 1599 return "TargetBuilder_Tests.MockHost"; 1600 } 1601 } 1602 1603 /// <summary> 1604 /// Returns the build parameters. 1605 /// </summary> 1606 public BuildParameters BuildParameters 1607 { 1608 get 1609 { 1610 return _buildParameters; 1611 } 1612 } 1613 1614 /// <summary> 1615 /// Constructs and returns a component of the specified type. 1616 /// </summary> 1617 /// <param name="type">The type of component to return</param> 1618 /// <returns>The component</returns> GetComponent(BuildComponentType type)1619 public IBuildComponent GetComponent(BuildComponentType type) 1620 { 1621 switch (type) 1622 { 1623 case BuildComponentType.ConfigCache: 1624 return (IBuildComponent)_configCache; 1625 1626 case BuildComponentType.LoggingService: 1627 return (IBuildComponent)_loggingService; 1628 1629 case BuildComponentType.ResultsCache: 1630 return (IBuildComponent)_resultsCache; 1631 1632 case BuildComponentType.RequestBuilder: 1633 return (IBuildComponent)_requestBuilder; 1634 1635 case BuildComponentType.TaskBuilder: 1636 return (IBuildComponent)_taskBuilder; 1637 1638 case BuildComponentType.TargetBuilder: 1639 return (IBuildComponent)_targetBuilder; 1640 1641 case BuildComponentType.SdkResolverService: 1642 return (IBuildComponent)_sdkResolverService; 1643 1644 default: 1645 throw new ArgumentException("Unexpected type " + type); 1646 } 1647 } 1648 1649 /// <summary> 1650 /// Registers a component factory 1651 /// </summary> RegisterFactory(BuildComponentType type, BuildComponentFactoryDelegate factory)1652 public void RegisterFactory(BuildComponentType type, BuildComponentFactoryDelegate factory) 1653 { 1654 } 1655 1656 #endregion 1657 1658 #region IBuildComponent Members 1659 1660 /// <summary> 1661 /// Sets the component host 1662 /// </summary> 1663 /// <param name="host">The component host</param> InitializeComponent(IBuildComponentHost host)1664 public void InitializeComponent(IBuildComponentHost host) 1665 { 1666 throw new NotImplementedException(); 1667 } 1668 1669 /// <summary> 1670 /// Shuts down the component 1671 /// </summary> ShutdownComponent()1672 public void ShutdownComponent() 1673 { 1674 throw new NotImplementedException(); 1675 } 1676 1677 #endregion 1678 } 1679 } 1680 } 1681