Skip to content

Commit

Permalink
Ensure benchmark results are exported to sensible directory.
Browse files Browse the repository at this point in the history
  • Loading branch information
atmoos committed May 16, 2024
1 parent f684a70 commit fa62f0d
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 12 deletions.
2 changes: 1 addition & 1 deletion source/GlassView.Benchmark/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"Indented": true
},
"Directory": {
"Path": "./GlassView.Core.Test/Resources/"
"Path": "BenchmarkDotNet.Artifacts/GlassView/"
}
}
}
Expand Down
48 changes: 48 additions & 0 deletions source/GlassView.Export.Test/ExtensionsTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using static Atmoos.GlassView.Export.Extensions;

namespace Atmoos.GlassView.Export.Test;

public class ExtensionsTest
{

[Fact]
public void FindLeafFindsExistingLeafDirInSomeToplevelDirectory()
{
const String directoryName = "someExistingLeafDir";
DirectoryInfo expected = MoveUp(CurrentDirectory(), levels: 3).CreateSubdirectory(directoryName);
try {
DirectoryInfo actual = FindLeaf(directoryName);

Assert.Equal(expected.FullName, actual.FullName);
Assert.True(expected.Exists, "The expected directory should exist after the test.");
}
finally {
expected.Delete(true);
}
}

[Fact]
public void FindLeafReturnsCreatedLeafDirInCurrentDirectoryWhenItCannotBeFound()
{
const String directoryName = "someLeafDirThatDoesNotExist";
var expected = new DirectoryInfo(Path.Combine(CurrentDirectory().FullName, directoryName));
Assert.False(expected.Exists, "The expected directory should not exist before the test.");

try {

DirectoryInfo actual = FindLeaf(directoryName);

Assert.Equal(expected.FullName, actual.FullName);
Assert.True(actual.Exists, "The expected directory should exist after the test.");
}
finally {
expected.Delete(true);
}
}

private static DirectoryInfo MoveUp(DirectoryInfo directory, Int32 levels)
{
for (; directory.Parent != null && levels-- > 0; directory = directory.Parent) { }
return directory;
}
}
10 changes: 5 additions & 5 deletions source/GlassView.Export/DirectoryExport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ public DirectoryExport(DirectoryInfo path, JsonFormatting formatting, ILogger lo
: this(path, logger)
{
this.options = new JsonSerializerOptions().EnableGlassView();
Set(formatting?.Indented, value => this.options.WriteIndented = value);
Set(formatting?.AllowTrailingCommas, value => this.options.AllowTrailingCommas = value);
SetValue(formatting.Indented, value => this.options.WriteIndented = value);
SetValue(formatting.AllowTrailingCommas, value => this.options.AllowTrailingCommas = value);
}

public async Task Export(Summary inputSummary, CancellationToken token)
{
var summary = Map(inputSummary);
FileInfo file = CombineToFile(path, summary);
FileInfo file = path.AddFile(FileNameFor(summary));
logger.WriteLine($"Exporting summary '{summary.Name}' to:");
logger.WriteLine($" -> {file.FullName}");
using var stream = file.Open(FileMode.Create, FileAccess.Write, FileShare.None);
await JsonSerializer.SerializeAsync(stream, summary, this.options, token).ConfigureAwait(ConfigureAwaitOptions.None);
}
public override String ToString() => $"{nameof(Export)}: {path.FullName}";
private static FileInfo CombineToFile(DirectoryInfo path, BenchmarkSummary summary)
=> new(Path.Combine(path.FullName, $"{summary.Name}.json"));

private static String FileNameFor(BenchmarkSummary summary) => $"{summary.Name}-{summary.Timestamp.ToLocalTime():s}.json";
}
36 changes: 35 additions & 1 deletion source/GlassView.Export/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ namespace Atmoos.GlassView.Export;

public static class Extensions
{
private static readonly EnumerationOptions findLeafOptions = new() {
RecurseSubdirectories = false,
IgnoreInaccessible = true,
MatchType = MatchType.Simple,
MatchCasing = MatchCasing.CaseSensitive,
AttributesToSkip = FileAttributes.Hidden | FileAttributes.System
};

public static async Task Export(this IExport exporter, IEnumerable<Summary> inputSummaries, CancellationToken token = default)
{
// For fun, some interleaved exporting :-)
Expand All @@ -31,10 +39,36 @@ private static JsonSerializerOptions Options(JsonSerializerOptions options)

internal static T Item<T>(this IConfiguration config) => config.GetSection(typeof(T).Name).Get<T>();

internal static void Set(Boolean? value, Action<Boolean> setter)
internal static void SetValue<T>(T? value, Action<T> setter)
where T : struct
{
if (value != null) {
setter(value.Value);
}
}

internal static void Set<T>(T? value, Action<T> setter)
where T : class
{
if (value != null) {
setter(value);
}
}

internal static DirectoryInfo FindLeaf(String directoryName)
{
DirectoryInfo? result;
DirectoryInfo cwd, directory;
directory = cwd = new DirectoryInfo(Directory.GetCurrentDirectory());
while ((result = directory.EnumerateDirectories(directoryName, findLeafOptions).SingleOrDefault()) == null) {
if (directory.Parent == null) {
return cwd.CreateSubdirectory(directoryName);
}
directory = directory.Parent;
}
return result;
}

internal static DirectoryInfo CurrentDirectory() => new(Directory.GetCurrentDirectory());
internal static FileInfo AddFile(this DirectoryInfo directory, String fileName) => new(Path.Combine(directory.FullName, fileName));
}
12 changes: 7 additions & 5 deletions source/GlassView.Export/GlassView.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using Microsoft.Extensions.Configuration;
using BenchmarkDotNet.Loggers;

using static System.IO.Directory;

namespace Atmoos.GlassView.Export;

public static class GlassView
{
private const String glassViewSection = nameof(GlassView);

public static IExport Default() => Default(ConsoleLogger.Default);
public static IExport Default(ILogger logger)
// ToDo: use benchmark artifact directory.
=> new DirectoryExport(new DirectoryInfo(Directory.GetCurrentDirectory()), logger);
=> new DirectoryExport(GlassViewArtifactsDirectory(), logger);

public static IExport Configure(IConfiguration config)
=> Configure(config, ConsoleLogger.Default);
Expand All @@ -24,9 +24,11 @@ public static IExport Configure(IConfiguration config, ILogger logger)
}
var export = section.Item<Configuration.Export>();
return export switch {
{ Directory.Path: var directory, JsonFormatting: null } => new DirectoryExport(new DirectoryInfo(directory), logger),
{ Directory.Path: var directory, JsonFormatting: var formatting } => new DirectoryExport(new DirectoryInfo(directory), formatting, logger),
{ Directory.Path: var directory, JsonFormatting: null } => new DirectoryExport(CreateDirectory(directory), logger),
{ Directory.Path: var directory, JsonFormatting: var formatting } => new DirectoryExport(CreateDirectory(directory), formatting, logger),
_ => throw new ArgumentOutOfRangeException(nameof(config), $"The '{glassViewSection}' section does not contain a valid '{nameof(Export)}' configuration section.")
};
}

private static DirectoryInfo GlassViewArtifactsDirectory() => Extensions.FindLeaf("BenchmarkDotNet.Artifacts").CreateSubdirectory(nameof(GlassView));
}

0 comments on commit fa62f0d

Please sign in to comment.