Skip to content

Commit

Permalink
Moved base line logic to seperated classes and created a directory ha…
Browse files Browse the repository at this point in the history
…ndler (#34)
  • Loading branch information
MilleBo authored Feb 21, 2020
1 parent 8f5238e commit 5da746e
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,65 +8,48 @@
using Testura.Mutation.Application.Commands.Project.OpenProject.Handlers;
using Testura.Mutation.Application.Exceptions;
using Testura.Mutation.Application.Models;
using Testura.Mutation.Core.Baseline;
using Testura.Mutation.Core.Config;
using Testura.Mutation.Core.Creator.Filter;
using Testura.Mutation.Core.Git;
using Testura.Mutation.Core.Solution;

namespace Testura.Mutation.Application.Commands.Project.OpenProject
{
public class OpenProjectCommandHandler : IRequestHandler<OpenProjectCommand, MutationConfig>
{
private readonly BaselineCreator _baselineCreator;
private readonly IGitCloner _gitCloner;
private readonly MutationDocumentFilterItemGitDiffCreator _diffCreator;
private readonly ISolutionBuilder _solutionBuilder;
private readonly ISolutionOpener _solutionOpener;
private readonly OpenProjectHandler _handler;

public OpenProjectCommandHandler(
BaselineCreator baselineCreator,
IGitCloner gitCloner,
MutationDocumentFilterItemGitDiffCreator diffCreator,
ISolutionBuilder solutionBuilder,
ISolutionOpener solutionOpener)
OpenProjectExistHandler openProjectExistHandler,
OpenProjectMutatorsHandler openProjectMutatorsHandler,
OpenProjectGitFilterHandler openProjectGitFilterHandler,
OpenProjectWorkspaceHandler openProjectWorkspaceHandler)
{
_baselineCreator = baselineCreator;
_gitCloner = gitCloner;
_diffCreator = diffCreator;
_solutionBuilder = solutionBuilder;
_solutionOpener = solutionOpener;
_handler = openProjectExistHandler;

_handler
.SetNext(openProjectMutatorsHandler)
.SetNext(openProjectGitFilterHandler)
.SetNext(openProjectWorkspaceHandler);
}

public async Task<MutationConfig> Handle(OpenProjectCommand command, CancellationToken cancellationToken)
{
var path = command.Path;
MutationConfig applicationConfig = null;
MutationFileConfig fileConfig = null;

LogTo.Info($"Opening project at {command.Config?.SolutionPath ?? path}");

try
{
var (fileConfig, applicationConfig) = LoadConfigs(path, command.Config);

var handler = new OpenProjectExistHandler(_gitCloner);
(fileConfig, applicationConfig) = LoadConfigs(path, command.Config);

handler
.SetNext(new OpenProjectMutatorsHandler())
.SetNext(new OpenProjectGitFilterHandler(_diffCreator))
.SetNext(new OpenProjectWorkspaceHandler(_baselineCreator, _solutionOpener));

try
{
await handler.HandleAsync(fileConfig, applicationConfig, cancellationToken);
}
catch (OperationCanceledException)
{
LogTo.Info("Open project was cancelled by request");
return applicationConfig;
}
await _handler.HandleAsync(fileConfig, applicationConfig, cancellationToken);

LogTo.Info("Opening project finished.");

return applicationConfig;
}
catch (OperationCanceledException)
{
LogTo.Info("Open project was cancelled by request");
return applicationConfig;
}
catch (Exception ex)
Expand Down
2 changes: 2 additions & 0 deletions src/Testura.Mutation.Console/Bootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Testura.Mutation.Core.Execution.Runners;
using Testura.Mutation.Core.Git;
using Testura.Mutation.Core.Solution;
using Testura.Mutation.Core.Util.FileSystem;
using Testura.Mutation.Infrastructure;
using Testura.Mutation.Infrastructure.Git;
using Testura.Mutation.Infrastructure.Solution;
Expand All @@ -26,6 +27,7 @@ public static IUnityContainer GetContainer()
unityContainer.RegisterType<ITestRunnerClient, TestRunnerConsoleClient>();
unityContainer.RegisterType<ISolutionBuilder, DotNetSolutionBuilder>(new ContainerControlledLifetimeManager());
unityContainer.RegisterType<ISolutionOpener, MsBuildSolutionOpener>();
unityContainer.RegisterType<IDirectoryHandler, DirectoryHandler>();
return unityContainer;
}
}
Expand Down
137 changes: 17 additions & 120 deletions src/Testura.Mutation.Core/Baseline/BaselineCreator.cs
Original file line number Diff line number Diff line change
@@ -1,101 +1,46 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Anotar.Log4Net;
using ConsoleTables;
using Newtonsoft.Json.Linq;
using Testura.Mutation.Core.Baseline.Handlers;
using Testura.Mutation.Core.Config;
using Testura.Mutation.Core.Exceptions;
using Testura.Mutation.Core.Execution;
using Testura.Mutation.Core.Execution.Compilation;
using Testura.Mutation.Core.Execution.Result;
using Testura.Mutation.Core.Execution.Runners;
using Testura.Mutation.Core.Solution;
using Testura.Mutation.Core.Util.FileSystem;

namespace Testura.Mutation.Core.Baseline
{
public class BaselineCreator
{
private readonly IProjectCompiler _projectCompiler;
private readonly TestRunnerDependencyFilesHandler _testRunnerDependencyFilesHandler;
private readonly ISolutionOpener _solutionOpener;
private ITestRunnerClient _testRunnerClient;
private readonly IDirectoryHandler _directoryHandler;
private readonly BaselineCreatorHandler _handler;

public BaselineCreator(
IProjectCompiler projectCompiler,
ITestRunnerClient testRunnerClient,
ISolutionOpener solutionOpener,
TestRunnerDependencyFilesHandler testRunnerDependencyFilesHandler)
IDirectoryHandler directoryHandler,
BaselineCreatorCompileMutationProjectsHandler baselineCreatorCompileMutationProjectsHandler,
BaselineCreatorRunUnitTestsHandler baselineCreatorRunUnitTestsHandler,
BaselineCreatorLogSummaryHandler baselineCreatorLogSummaryHandler)
{
_projectCompiler = projectCompiler;
_testRunnerClient = testRunnerClient;
_solutionOpener = solutionOpener;
_testRunnerDependencyFilesHandler = testRunnerDependencyFilesHandler;
_directoryHandler = directoryHandler;
_handler = baselineCreatorCompileMutationProjectsHandler;

_handler
.SetNext(baselineCreatorRunUnitTestsHandler)
.SetNext(baselineCreatorLogSummaryHandler);
}

private string BaselineDirectoryPath => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "TestRun", "Baseline");

public async Task<IList<BaselineInfo>> CreateBaselineAsync(MutationConfig config, CancellationToken cancellationToken = default(CancellationToken))
{
LogTo.Info("Creating baseline and verifying solution/tests..");

DeleteBaselineDirectory();
_directoryHandler.DeleteDirectory(BaselineDirectoryPath);

try
{
cancellationToken.ThrowIfCancellationRequested();

Directory.CreateDirectory(BaselineDirectoryPath);

foreach (var mutationProject in config.MutationProjects)
{
var project = config.Solution.Projects.FirstOrDefault(p => p.Name == mutationProject.Project.Name);
var result = await _projectCompiler.CompileAsync(BaselineDirectoryPath, project);

if (!result.IsSuccess)
{
foreach (var compilationError in result.Errors)
{
LogTo.Error($"{{ Error = \"{compilationError.Message}\", Location = \"{compilationError.Location}\"");
}

throw new BaselineException(
$"Failed to compile {project.Name} in base line.",
new CompilationException(result.Errors.Select(e => e.Message)));
}
}

var baselineInfos = new List<BaselineInfo>();

foreach (var testProject in config.TestProjects)
{
cancellationToken.ThrowIfCancellationRequested();

var result = await RunTestAsync(testProject, config.DotNetPath, config.MaxTestTimeMin, cancellationToken);

if (!result.IsSuccess)
{
var failedTests = result.TestResults.Where(t => !t.IsSuccess);
LogTo.Error("Unit tests failed with base line");
LogTo.Error($"Name: {result.Name}");

foreach (var failedTest in failedTests)
{
LogTo.Error(JObject.FromObject(new { TestName = failedTest.Name, Message = failedTest.InnerText }).ToString());
}

throw new BaselineException("Failed to run all unit tests with baseline which make mutation testing impossible. See log for more details.");
}

LogTo.Info($"..done ({result.TestResults.Count(t => t.IsSuccess)} tests passed).");
baselineInfos.Add(new BaselineInfo(testProject.Project.Name, result.ExecutionTime));
}

LogBaselineSummary(baselineInfos);
await _handler.HandleAsync(config, BaselineDirectoryPath, baselineInfos, cancellationToken);

LogTo.Info("Baseline completed.");
return baselineInfos;
Expand All @@ -107,55 +52,7 @@ public BaselineCreator(
}
finally
{
DeleteBaselineDirectory();
}
}

private async Task<TestSuiteResult> RunTestAsync(
TestProject testProject,
string dotNetPath,
int maxTestTimeMin,
CancellationToken cancellationToken = default(CancellationToken))
{
LogTo.Info($"Starting to run tests in {testProject.Project.OutputFileName}");
var testDirectoryPath = Path.Combine(BaselineDirectoryPath, Guid.NewGuid().ToString());
var testDllPath = Path.Combine(testDirectoryPath, testProject.Project.OutputFileName);
Directory.CreateDirectory(testDirectoryPath);

// Copy all files from the test directory to our own mutation test directory
_testRunnerDependencyFilesHandler.CopyDependencies(testProject.Project.OutputDirectoryPath, testDirectoryPath);

foreach (var file in Directory.EnumerateFiles(BaselineDirectoryPath))
{
File.Copy(file, Path.Combine(testDirectoryPath, Path.GetFileName(file)), true);
}

return await _testRunnerClient.RunTestsAsync(testProject.TestRunner, testDllPath, dotNetPath, TimeSpan.FromMinutes(maxTestTimeMin), cancellationToken);
}

private void LogBaselineSummary(IList<BaselineInfo> baselineInfos)
{
var table = new ConsoleTable("Project", "Execution time");
foreach (var configBaselineInfo in baselineInfos)
{
table.AddRow(configBaselineInfo.TestProjectName, configBaselineInfo.ExecutionTime);
}

LogTo.Info($"\n{table.ToStringAlternative()}");
}

private void DeleteBaselineDirectory()
{
try
{
if (Directory.Exists(BaselineDirectoryPath))
{
Directory.Delete(BaselineDirectoryPath, true);
}
}
catch (Exception ex)
{
LogTo.Error($"Failed to delete baseline directory: {ex.Message}");
_directoryHandler.DeleteDirectory(BaselineDirectoryPath);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Anotar.Log4Net;
using Testura.Mutation.Core.Config;
using Testura.Mutation.Core.Exceptions;
using Testura.Mutation.Core.Execution.Compilation;
using Testura.Mutation.Core.Util.FileSystem;

namespace Testura.Mutation.Core.Baseline.Handlers
{
public class BaselineCreatorCompileMutationProjectsHandler : BaselineCreatorHandler
{
private readonly IProjectCompiler _projectCompiler;
private readonly IDirectoryHandler _directoryHandler;

public BaselineCreatorCompileMutationProjectsHandler(IProjectCompiler projectCompiler, IDirectoryHandler directoryHandler)
{
_projectCompiler = projectCompiler;
_directoryHandler = directoryHandler;
}

public override async Task HandleAsync(MutationConfig config, string baselineDirectoryPath, IList<BaselineInfo> baselineInfos, CancellationToken cancellationToken = default(CancellationToken))
{
_directoryHandler.CreateDirectory(baselineDirectoryPath);

foreach (var mutationProject in config.MutationProjects)
{
LogTo.Info($"Compiling {mutationProject.Project.Name}..");

var project = config.Solution.Projects.FirstOrDefault(p => p.Name == mutationProject.Project.Name);
var result = await _projectCompiler.CompileAsync(baselineDirectoryPath, project);

if (!result.IsSuccess)
{
foreach (var compilationError in result.Errors)
{
LogTo.Error($"{{ Error = \"{compilationError.Message}\", Location = \"{compilationError.Location}\"");
}

throw new BaselineException(
$"Failed to compile {project.Name} in base line.",
new CompilationException(result.Errors.Select(e => e.Message)));
}
}

await base.HandleAsync(config, baselineDirectoryPath, baselineInfos, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Testura.Mutation.Core.Config;

namespace Testura.Mutation.Core.Baseline.Handlers
{
public abstract class BaselineCreatorHandler
{
public BaselineCreatorHandler Next { get; set; }

public virtual Task HandleAsync(MutationConfig config, string baselineDirectoryPath, IList<BaselineInfo> baselineInfos, CancellationToken cancellationToken = default(CancellationToken))
{
return Next?.HandleAsync(config, baselineDirectoryPath, baselineInfos, cancellationToken) ?? Task.CompletedTask;
}

public BaselineCreatorHandler SetNext(BaselineCreatorHandler handler)
{
Next = handler;
return Next;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Anotar.Log4Net;
using ConsoleTables;
using Testura.Mutation.Core.Config;

namespace Testura.Mutation.Core.Baseline.Handlers
{
public class BaselineCreatorLogSummaryHandler : BaselineCreatorHandler
{
public override Task HandleAsync(MutationConfig config, string baselineDirectoryPath, IList<BaselineInfo> baselineInfos, CancellationToken cancellationToken = default(CancellationToken))
{
var table = new ConsoleTable("Project", "Execution time");
foreach (var configBaselineInfo in baselineInfos)
{
table.AddRow(configBaselineInfo.TestProjectName, configBaselineInfo.ExecutionTime);
}

LogTo.Info($"\n{table.ToStringAlternative()}");

return base.HandleAsync(config, baselineDirectoryPath, baselineInfos, cancellationToken);
}
}
}
Loading

0 comments on commit 5da746e

Please sign in to comment.