Skip to content

Commit

Permalink
Add test for StartupProcessor, Make StartedAsync faster by paralleliz…
Browse files Browse the repository at this point in the history
…ing, and small cleanup/refactor
  • Loading branch information
pacna committed Jan 18, 2024
1 parent b060393 commit 0d5933b
Show file tree
Hide file tree
Showing 15 changed files with 100 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Edge.MyMusic/src/Edge.MyMusic.Tests/MusicServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public async Task CanUpdateFavoriteSongAsync()
}


internal void AssertEqual(MusicDocument expected, SongResponse actual)
private static void AssertEqual(MusicDocument expected, SongResponse actual)
{
Assert.Equal(expected.Id, actual.Id);
Assert.Equal(expected.Album, actual.Album);
Expand Down
61 changes: 61 additions & 0 deletions Edge.MyMusic/src/Edge.MyMusic.Tests/StartupProcessorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Edge.MyMusic.Processors;
using Edge.MyMusic.Providers;
using Edge.MyMusic.Repositories;
using Edge.MyMusic.Settings;
using Microsoft.Extensions.Logging;

namespace Edge.MyMusic.Tests;

public class StartupProcessorTests
{
private readonly Mock<ILogger<StartupProcessor>> _logger;
private readonly Mock<IMusicRepository> _repo;
private readonly Mock<IAudioProvider> _audioProvider;
private readonly Mock<IArgsSetting> _setting;

private readonly StartupProcessor _processor;

public StartupProcessorTests()
{
_logger = new Mock<ILogger<StartupProcessor>>();
_repo = new Mock<IMusicRepository>();
_audioProvider = new Mock<IAudioProvider>();
_setting = new Mock<IArgsSetting>();

_processor = new StartupProcessor(_logger.Object, _repo.Object, _audioProvider.Object, _setting.Object);
}

[Fact]
public async Task CanStartAsync()
{
// ACT
await _processor.StartAsync(default);

// ASSERT
_logger.Verify(
log => log.Log(
It.Is<LogLevel>(l => l == LogLevel.Information),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString() == $"{nameof(StartupProcessor)} is starting..."),
It.IsAny<Exception>(),
It.Is<Func<It.IsAnyType, Exception?, string>>((v, t) => true)),
Times.Once);
}

[Fact]
public async Task CanStopAsync()
{
// ACT
await _processor.StopAsync(default);

// ASSERT
_logger.Verify(
log => log.Log(
It.Is<LogLevel>(l => l == LogLevel.Information),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString() == $"{nameof(StartupProcessor)} is stopping..."),
It.IsAny<Exception>(),
It.Is<Func<It.IsAnyType, Exception?, string>>((v, t) => true)),
Times.Once);
}
}
10 changes: 6 additions & 4 deletions Edge.MyMusic/src/Edge.MyMusic/ApplicationBuilderExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ internal static IApplicationBuilder UseCors(this IApplicationBuilder application

internal static IApplicationBuilder UseServerHandler(this IApplicationBuilder application)
{
JsonSerializerOptions options = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

return application.UseExceptionHandler(app =>
{
app.Run(async context =>
Expand All @@ -77,10 +82,7 @@ await context.Response.WriteAsync(JsonSerializer.Serialize
Type = exceptionHandlerPathFeature.Error.GetType().Name,
exceptionHandlerPathFeature.Error.Message
},
new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
}
options
));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public IEnumerable<ValidationResult> Validate(ValidationContext validationContex
});
}

internal IEnumerable<ValidationResult> Validate(IReadOnlyDictionary<string, string> properties)
private IEnumerable<ValidationResult> Validate(IReadOnlyDictionary<string, string> properties)
{
if (!Uri.IsWellFormedUriString(this.Path, UriKind.Absolute))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public IEnumerable<ValidationResult> Validate(ValidationContext validationContex
});
}

internal IEnumerable<ValidationResult> Validate(IReadOnlyDictionary<string, string?> properties)
private IEnumerable<ValidationResult> Validate(IReadOnlyDictionary<string, string?> properties)
{

if (!string.IsNullOrEmpty(this.Path) && !Uri.IsWellFormedUriString(this.Path, UriKind.Absolute))
Expand Down
2 changes: 1 addition & 1 deletion Edge.MyMusic/src/Edge.MyMusic/Processors/BaseProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Edge.MyMusic.Processors;

internal abstract class BaseProcessor: IHostedLifecycleService
public abstract class BaseProcessor: IHostedLifecycleService
{
public virtual Task StartingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public virtual Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
Expand Down
30 changes: 19 additions & 11 deletions Edge.MyMusic/src/Edge.MyMusic/Processors/StartupProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

namespace Edge.MyMusic.Processors;

internal class StartupProcessor(
public class StartupProcessor(
ILogger<StartupProcessor> logger,
IMusicRepository musicRepository,
IAudioProvider audioProvider,
IArgsSetting argsSetting) : BaseProcessor
{
private readonly ILogger _logger = logger;
private readonly ILogger<StartupProcessor> _logger = logger;
private readonly IMusicRepository _musicRepository = musicRepository;
private readonly IAudioProvider _audioProvider = audioProvider;
private readonly IArgsSetting _argsSetting = argsSetting;
Expand All @@ -32,19 +32,22 @@ public override Task StartedAsync(CancellationToken cancellationToken)
return Task.CompletedTask;
}

return Task.Run(async() =>
try
{
IEnumerable<string> files = Directory.EnumerateFiles(_argsSetting.AudiosPath);

foreach(string filePath in files)
return Parallel.ForEachAsync(
Directory.EnumerateFiles(_argsSetting.AudiosPath),
new ParallelOptions { MaxDegreeOfParallelism = 3,
CancellationToken = cancellationToken }, async (file, ct) =>
{
string path = $"{_argsSetting.BaseUrl}/audios/{Path.GetFileName(filePath)}";
ct.ThrowIfCancellationRequested();

string path = $"{_argsSetting.BaseUrl}/audios/{Path.GetFileName(file)}";
AudioResponse? audio = await _audioProvider.GetMetadataAsync(path);

if (audio == null)
{
_logger.LogWarning($"Unable to find audio file {path}", new[] { path});
continue;
_logger.LogWarning($"Unable to find audio file", new[] { path });
return;
}

await _musicRepository.AddMusicAsync(new MusicDocument
Expand All @@ -56,8 +59,13 @@ await _musicRepository.AddMusicAsync(new MusicDocument
Path = path,
Title = audio.Title ?? _default
});
};
});
});
}
catch(OperationCanceledException ex)
{
_logger.LogWarning("Operation was cancelled", new[] { ex.Message });
return Task.CompletedTask;
}
}

public override Task StopAsync(CancellationToken cancellationToken)
Expand Down
2 changes: 1 addition & 1 deletion Edge.MyMusic/src/Edge.MyMusic/Services/MapperExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static MusicDocument ToDocument(this SongPostRequest from, int? duration)
Album = from.Album,
Artist = from.Artist,
IsFavorite = from.IsFavorite,
Length = duration ?? 0,
Length = duration.GetValueOrDefault(-1),
Path = from.Path,
Title = from.Title
};
Expand Down
9 changes: 1 addition & 8 deletions Edge.MyMusic/src/Edge.MyMusic/Services/MusicService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,7 @@ public async Task<CollectionModel<SongResponse>> SearchSongsAsync(SongSearchRequ

public async Task<SongResponse> AddSongAsync(SongPostRequest request)
{
try
{
return (await _musicRepository.AddMusicAsync(request.ToDocument((await _audioProvider.GetMetadataAsync(request.Path))?.Duration))).ToResponse();
}
catch
{
throw new Exception("Unable to add song");
}
return (await _musicRepository.AddMusicAsync(request.ToDocument((await _audioProvider.GetMetadataAsync(request.Path))?.Duration))).ToResponse();
}

public async Task<SongResponse?> GetSongAsync(string id)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Edge.MyMusic.Settings;

internal class ApplicationSetting : ICORSPolicySetting, IArgsSetting, IMongoDBSetting
internal class ApplicationSetting : IApplicationSetting
{
public string? PolicyName { get; init; }
public string[]? AllowedOrigins { get; init; }
Expand Down
3 changes: 3 additions & 0 deletions Edge.MyMusic/src/Edge.MyMusic/Settings/IApplicationSetting.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Edge.MyMusic.Settings;

public interface IApplicationSetting : ICORSPolicySetting, IArgsSetting, IMongoDBSetting;
2 changes: 1 addition & 1 deletion Edge.MyMusic/src/Edge.MyMusic/Settings/IArgsSetting.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Edge.MyMusic.Settings;

internal interface IArgsSetting
public interface IArgsSetting
{
string? AudiosPath { get; init; }
string? BaseUrl { get; init; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Edge.MyMusic.Settings;

internal interface ICORSPolicySetting
public interface ICORSPolicySetting
{
string? PolicyName { get; init; }
string[]? AllowedOrigins { get; init; }
Expand Down
2 changes: 1 addition & 1 deletion Edge.MyMusic/src/Edge.MyMusic/Settings/IMongoDBSetting.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Edge.MyMusic.Settings;

internal interface IMongoDBSetting
public interface IMongoDBSetting
{
string? ConnectionString { get; init; }
string? DatabaseName { get; init; }
Expand Down
2 changes: 1 addition & 1 deletion Web.MyMusic/src/shared/components/nav-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const StyledListItemButton = styled(ListItemButton)({
backgroundColor: Color.NeonPink,
color: "white",
"& .MuiSvgIcon-root": {
color: Color.White, // Change the color of the icon on hover
color: Color.White,
},
},
});
Expand Down

0 comments on commit 0d5933b

Please sign in to comment.