Permalink
Browse files

Added a new action to Project for retrieving its status (very simple …

…at the moment, needs some more work.)

Refactored ProcessExecutor to simplify working within an IoC container (split off interface, moved some constructor arguments to be injected properties, registered in CoreModule, etc.)
Did a simple proof of concept implementation of the BuildMSBuild task using ProcessExecutor.
  • Loading branch information...
1 parent 0ae63bc commit 1c406f78e417183a766187dc4e92fbdf70468a13 @csut017 csut017 committed Mar 4, 2011
@@ -44,6 +44,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Messages\OperationReport.cs" />
+ <Compile Include="Messages\ProjectStatus.cs" />
<Compile Include="Messages\ServerItemList.cs" />
<Compile Include="Messages\ServerItem.cs" />
<Compile Include="Messages\SingleValue.cs" />
@@ -0,0 +1,17 @@
+namespace CruiseControl.Common.Messages
+{
+ using System;
+
+ public class ProjectStatus
+ {
+ #region Public properties
+ #region Status
+ public string Status { get; set; }
+ #endregion
+
+ #region LastBuildDate
+ public DateTime LastBuildDate { get; set; }
+ #endregion
+ #endregion
+ }
+}
@@ -60,6 +60,9 @@
<Compile Include="PersistedProjectStateTests.cs" />
<Compile Include="Structure\ScmProjectTests.cs" />
<Compile Include="Stubs\ChannelStub.cs" />
+ <Compile Include="Stubs\ProcessExecutorStub.cs" />
+ <Compile Include="TaskExecutionContextHelpers.cs" />
+ <Compile Include="Tasks\BuildMSBuildTests.cs" />
<Compile Include="Tasks\ForceBuildTests.cs" />
<Compile Include="Triggers\RollUpTests.cs" />
<Compile Include="Utilities\ActionInvokerTests.cs" />
@@ -816,6 +816,14 @@ public void StopMessageStopsProject()
Thread.Sleep(500);
Assert.IsTrue(stopped);
}
+
+ [Test]
+ public void GetStatusReturnsCurrentStatus()
+ {
+ var project = new Project();
+ var status = project.GetStatus(new Messages.Blank());
+ Assert.AreEqual("Stopped", status.Status);
+ }
#endregion
#region Private methods
@@ -0,0 +1,72 @@
+namespace CruiseControl.Core.Tests.Stubs
+{
+ using System;
+ using System.IO;
+ using CruiseControl.Core.Interfaces;
+ using CruiseControl.Core.Utilities;
+ using Moq;
+ using NUnit.Framework;
+
+ public class ProcessExecutorStub
+ : IProcessExecutor
+ {
+ public ProcessExecutorStub(
+ string fileName,
+ string args,
+ string workingDir,
+ ProjectItem item,
+ TaskExecutionContext context)
+ {
+ this.FileName = fileName;
+ this.Arguments = args;
+ this.WorkingDirectory = workingDir;
+ this.Item = item;
+ this.Context = context;
+ }
+
+ public string FileName { get; set; }
+ public string Arguments { get; set; }
+ public string WorkingDirectory { get; set; }
+ public ProjectItem Item { get; set; }
+ public TaskExecutionContext Context { get; set; }
+ public bool Failed { get; set; }
+ public bool TimedOut { get; set; }
+ public int ExitCode { get; set; }
+
+ public ProcessResult Execute(ProcessInfo processInfo, string projectName, string itemId, string outputFile)
+ {
+ throw new NotImplementedException();
+ }
+
+ public ProcessResult Execute(ProcessInfo processInfo, ProjectItem item, TaskExecutionContext context)
+ {
+ var outputFile = context.GeneratePathInWorkingDirectory(item.NameOrType + ".log");
+ if ((this.Item == null) || (this.Context == null))
+ {
+ return this.Execute(processInfo,
+ item.Project.Name,
+ item.NameOrType,
+ outputFile);
+ }
+
+ Assert.AreEqual(this.FileName, processInfo.FileName);
+ var actual = processInfo.Arguments == null ? null : processInfo.Arguments.ToString();
+ Assert.AreEqual(this.Arguments, actual);
+ Assert.AreEqual(this.WorkingDirectory, processInfo.WorkingDirectory);
+ Assert.AreSame(this.Item, item);
+ Assert.AreEqual(this.Context, context);
+
+ var fileSystemMock = new Mock<IFileSystem>();
+ fileSystemMock.Setup(fs => fs.OpenFileForRead(outputFile)).Returns(new MemoryStream());
+ var result = new ProcessResult(
+ fileSystemMock.Object,
+ outputFile,
+ this.ExitCode,
+ this.TimedOut,
+ this.Failed);
+ return result;
+ }
+
+ public event EventHandler<ProcessOutputEventArgs> ProcessOutput;
+ }
+}
@@ -0,0 +1,17 @@
+namespace CruiseControl.Core.Tests
+{
+ public static class TaskExecutionContextHelpers
+ {
+ #region Helper methods
+ public static TaskExecutionContext Initialise(Project project)
+ {
+ var instance = new TaskExecutionContext(
+ new TaskExecutionParameters
+ {
+ Project = project
+ });
+ return instance;
+ }
+ #endregion
+ }
+}
@@ -240,6 +240,25 @@ public void StartOutputStreamStartsANewStream()
fileSystemMock.Verify();
Assert.AreSame(expected, actual);
}
+
+ [Test]
+ public void GeneratePathInWorkingDirectoryGeneratesDefaultPath()
+ {
+ var projectName = "Test";
+ var filename = "aTestFile.txt";
+ var expected = Path.Combine(
+ Environment.CurrentDirectory,
+ projectName,
+ "working",
+ filename);
+ var context = new TaskExecutionContext(
+ new TaskExecutionParameters
+ {
+ Project = new Project(projectName)
+ });
+ var actual = context.GeneratePathInWorkingDirectory(filename);
+ Assert.AreEqual(expected, actual);
+ }
#endregion
}
}
@@ -0,0 +1,59 @@
+namespace CruiseControl.Core.Tests.Tasks
+{
+ using System;
+ using System.Linq;
+ using CruiseControl.Core.Tasks;
+ using CruiseControl.Core.Tests.Stubs;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class BuildMSBuildTests
+ {
+ #region Tests
+ [Test]
+ public void RunWithDefaultParametersCallExecutor()
+ {
+ var projectFile = "project";
+ var task = new BuildMSBuild
+ {
+ Project = new Project("Test"),
+ ProjectFile = projectFile
+ };
+ var context = TaskExecutionContextHelpers.Initialise(task.Project);
+ task.ProcessExecutor = new ProcessExecutorStub(
+ "msbuild",
+ projectFile,
+ Environment.CurrentDirectory,
+ task,
+ context);
+
+ var result = task.Run(context);
+ result.Count(); // This is needed to actually run the task
+ Assert.AreEqual(IntegrationStatus.Success, context.CurrentStatus);
+ }
+
+ [Test]
+ public void RunHandlesExecutorFailing()
+ {
+ var projectFile = "project";
+ var task = new BuildMSBuild
+ {
+ Project = new Project("Test"),
+ ProjectFile = projectFile
+ };
+ var context = TaskExecutionContextHelpers.Initialise(task.Project);
+ var executor = new ProcessExecutorStub(
+ "msbuild",
+ projectFile,
+ Environment.CurrentDirectory,
+ task,
+ context) { Failed = true };
+ task.ProcessExecutor = executor;
+
+ var result = task.Run(context);
+ result.Count(); // This is needed to actually run the task
+ Assert.AreEqual(IntegrationStatus.Failure, context.CurrentStatus);
+ }
+ #endregion
+ }
+}
@@ -7,6 +7,7 @@
using System.Threading;
using CruiseControl.Core.Exceptions;
using CruiseControl.Core.Interfaces;
+ using CruiseControl.Core.Tasks;
using CruiseControl.Core.Utilities;
using Moq;
using NUnit.Framework;
@@ -96,7 +97,7 @@ public void KillProcessesForProjectKillsAProcess()
{
var fileSystemMock = InitialiseFileSystemMockForExecute();
var info = new ProcessInfo("sleeper");
- var executor = new ProcessExecutor(fileSystemMock.Object);
+ var executor = new ProcessExecutor { FileSystem = fileSystemMock.Object };
var projectName = "aProject";
var thread = new Thread(
() => executor.Execute(info, projectName, "aTask", "C:\\somewhere.txt"));
@@ -115,7 +116,7 @@ public void ExecuteRunsProcess()
{
var fileSystemMock = InitialiseFileSystemMockForExecute();
var info = new ProcessInfo("sleeper", "1");
- var executor = new ProcessExecutor(fileSystemMock.Object);
+ var executor = new ProcessExecutor { FileSystem = fileSystemMock.Object };
var projectName = "aProject";
var waitHandle = new ManualResetEvent(false);
ProcessResult result = null;
@@ -141,7 +142,7 @@ public void ExecuteTimesOut()
{
var fileSystemMock = InitialiseFileSystemMockForExecute();
var info = new ProcessInfo("sleeper") { TimeOut = TimeSpan.FromSeconds(1) };
- var executor = new ProcessExecutor(fileSystemMock.Object);
+ var executor = new ProcessExecutor { FileSystem = fileSystemMock.Object };
var projectName = "aProject";
var waitHandle = new ManualResetEvent(false);
ProcessResult result = null;
@@ -168,7 +169,7 @@ public void ExecutePassesOnOutput()
var fileSystemMock = InitialiseFileSystemMockForExecute();
var info = new ProcessInfo("sleeper", "1");
var output = new List<ProcessOutputEventArgs>();
- var executor = new ProcessExecutor(fileSystemMock.Object);
+ var executor = new ProcessExecutor { FileSystem = fileSystemMock.Object };
executor.ProcessOutput += (o, e) => output.Add(e);
var projectName = "aProject";
var waitHandle = new ManualResetEvent(false);
@@ -188,39 +189,41 @@ public void ExecutePassesOnOutput()
thread.Start();
waitHandle.WaitOne(TimeSpan.FromSeconds(30));
CollectionAssert.IsNotEmpty(output);
+ Assert.IsTrue(result.Succeeded);
}
[Test]
public void ExecuteChangesPriority()
{
var fileSystemMock = InitialiseFileSystemMockForExecute();
var info = new ProcessInfo("sleeper", "1", null, ProcessPriorityClass.BelowNormal);
- var executor = new ProcessExecutor(fileSystemMock.Object);
+ var executor = new ProcessExecutor { FileSystem = fileSystemMock.Object };
var projectName = "aProject";
var waitHandle = new ManualResetEvent(false);
ProcessResult result = null;
var thread = new Thread(
() =>
+ {
+ try
{
- try
- {
- result = executor.Execute(info, projectName, "aTask", "C:\\somewhere.txt");
- }
- finally
- {
- waitHandle.Set();
- }
- });
+ result = executor.Execute(info, projectName, "aTask", "C:\\somewhere.txt");
+ }
+ finally
+ {
+ waitHandle.Set();
+ }
+ });
thread.Start();
waitHandle.WaitOne(TimeSpan.FromSeconds(30));
+ Assert.IsTrue(result.Succeeded);
}
[Test]
public void ExecuteWritesToStdIn()
{
var fileSystemMock = InitialiseFileSystemMockForExecute();
- var info = new ProcessInfo("sleeper", "1") {StandardInputContent = "SomeData"};
- var executor = new ProcessExecutor(fileSystemMock.Object);
+ var info = new ProcessInfo("sleeper", "1") { StandardInputContent = "SomeData" };
+ var executor = new ProcessExecutor { FileSystem = fileSystemMock.Object };
var projectName = "aProject";
var waitHandle = new ManualResetEvent(false);
ProcessResult result = null;
@@ -238,13 +241,42 @@ public void ExecuteWritesToStdIn()
});
thread.Start();
waitHandle.WaitOne(TimeSpan.FromSeconds(30));
+ Assert.IsTrue(result.Succeeded);
}
[Test]
public void KillProcessesForProjectHandlesAMissingProject()
{
ProcessExecutor.KillProcessesForProject(null, "DoesNothingExist");
}
+
+ [Test]
+ public void ExecuteWithProjectItemGeneratesTheRightArguments()
+ {
+ var info = new ProcessInfo("Test");
+ var item = new Comment
+ {
+ Project = new Project("Test")
+ };
+ var context = new TaskExecutionContext(
+ new TaskExecutionParameters
+ {
+ Project = item.Project
+ });
+ var logFile = context.GeneratePathInWorkingDirectory("Comment.log");
+ var executor = new ProcessExecutorOverride
+ {
+ OnExecute = (pi, p, i, o) =>
+ {
+ Assert.AreSame(info, pi);
+ Assert.AreEqual("Test", p);
+ Assert.AreEqual("Comment", i);
+ Assert.AreEqual(logFile, o);
+ return null;
+ }
+ };
+ executor.Execute(info, item, context);
+ }
#endregion
#region Helper methods
@@ -257,5 +289,19 @@ private static Mock<IFileSystem> InitialiseFileSystemMockForExecute()
return fileSystemMock;
}
#endregion
+
+ #region Private classes
+ private class ProcessExecutorOverride
+ : ProcessExecutor
+ {
+ public Func<ProcessInfo, string, string, string, ProcessResult> OnExecute { get; set; }
+ public override ProcessResult Execute(ProcessInfo processInfo, string projectName, string itemId, string outputFile)
+ {
+ return this.OnExecute != null ?
+ this.OnExecute(processInfo, projectName, itemId, outputFile) :
+ base.Execute(processInfo, projectName, itemId, outputFile);
+ }
+ }
+ #endregion
}
}
@@ -152,6 +152,7 @@
<Compile Include="Triggers\Schedule.cs" />
<Compile Include="Triggers\Url.cs" />
<Compile Include="Utilities\FileSystem.cs" />
+ <Compile Include="Interfaces\IProcessExecutor.cs" />
<Compile Include="Utilities\LoggingValidationLog.cs" />
<Compile Include="Utilities\PrivateString.cs" />
<Compile Include="Utilities\PrivateStringTypeConverter.cs" />
Oops, something went wrong.

0 comments on commit 1c406f7

Please sign in to comment.