Skip to content

Commit

Permalink
Add cache for PDF files, bump version to v6.1.0 (#65)
Browse files Browse the repository at this point in the history
* Add cache for PDF files

* PDFs are created when outdated, or taken from cache
* ReportSheetCache added as scoped service
* _Layout extended to render a section with meta tags if needed
* Match.Results has "noFollow" meta tag for robots
* Match.Fixtures has "noFollow" meta tag for robots
* Add unit tests for PDF caching

* Bump version to v6.1.0
  • Loading branch information
axunonb authored Mar 23, 2023
1 parent 71217f4 commit 45092b5
Show file tree
Hide file tree
Showing 21 changed files with 462 additions and 158 deletions.
4 changes: 2 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<Copyright>Copyright 2011-$(CurrentYear) axuno gGmbH</Copyright>
<RepositoryUrl>https://github.com/axuno/Volleyball-League</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<Version>6.0.0</Version>
<FileVersion>6.0.0</FileVersion>
<Version>6.1.0</Version>
<FileVersion>6.1.0</FileVersion>
<AssemblyVersion>6.0.0.0</AssemblyVersion> <!--only update AssemblyVersion with major releases -->
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
Expand Down
1 change: 1 addition & 0 deletions League.Demo/Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=0" />
@await RenderSectionAsync("meta", required: false)
<title>@ViewData.Title()</title>
@if (ViewData.Description() != null)
{
Expand Down
102 changes: 102 additions & 0 deletions League.Tests/Caching/ReportSheetCacheTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// Copyright Volleyball League Project maintainers and contributors.
// Licensed under the MIT license.
//

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using League.Caching;
using League.Tests.TestComponents;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;
using TournamentManager.DAL.TypedViewClasses;
using TournamentManager.MultiTenancy;

namespace League.Tests.Caching;

[TestFixture]
public class ReportSheetCacheTests
{
private readonly ReportSheetCache _cache;
private readonly ITenantContext _tenantContext;
private readonly IWebHostEnvironment _webHostEnvironment;

public ReportSheetCacheTests()
{
_webHostEnvironment = new HostingEnvironment {
WebRootPath = Path.GetTempPath(), ContentRootPath
// Because we use the Chromium installation in the demo web app
= DirectoryLocator.GetTargetProjectPath(typeof(League.WebApp.WebAppStartup))
};

_tenantContext = new TenantContext
{
Identifier = "testorg"
};

var chromiumPath = new List<KeyValuePair<string, string?>>
{ new("Chromium:ExecutablePath", "Chromium-Win\\chrome.exe") };

IServiceProvider services = UnitTestHelpers.GetReportSheetCacheServiceProvider(_tenantContext, _webHostEnvironment, chromiumPath);
_cache = services.GetRequiredService<ReportSheetCache>();
}

[TestCase("en")]
[TestCase("de")]
public async Task CreateNewPdfInOutputPath(string c)
{
DeleteOutputFolder();
var culture = CultureInfo.GetCultureInfo(c);
using var switcher = new CultureSwitcher(culture, culture);

var data = new MatchReportSheetRow
{ Id = 1234, ModifiedOn = new DateTime(2023, 03, 22, 12, 0, 0).ToUniversalTime() };

var stream = await _cache.GetOrCreatePdf(data, "<html><body>Some text</body></html>", CancellationToken.None);
var fileName = Path.GetFileName(((FileStream) stream).Name);
await stream.DisposeAsync();

Assert.That(fileName,
Is.EqualTo(string.Format(ReportSheetCache.ReportSheetFilenameTemplate, _tenantContext.Identifier, data.Id,
culture.TwoLetterISOLanguageName)));
}

[TestCase("en")]
[TestCase("de")]
public async Task ShouldReturnExistingPdfFromCache(string c)
{
DeleteOutputFolder();
var culture = CultureInfo.GetCultureInfo(c);
using var switcher = new CultureSwitcher(culture, culture);

var data = new MatchReportSheetRow
{ Id = 1234, ModifiedOn = new DateTime(2023, 03, 22, 12, 0, 0).ToUniversalTime() };

// (1) This should create the file in the cache
var stream1 = await _cache.GetOrCreatePdf(data, "<html><body>Some text</body></html>", CancellationToken.None);
var fileInfo1 = new FileInfo(Path.GetFileName(((FileStream) stream1).Name));
await stream1.DisposeAsync();

// (1) This should return the file from the cache
var stream2 = await _cache.GetOrCreatePdf(data, "<html><body>Some text</body></html>", CancellationToken.None);
var fileInfo2 = new FileInfo(Path.GetFileName(((FileStream) stream1).Name));
await stream2.DisposeAsync();

// Assert the file was not created again
Assert.That(fileInfo1.CreationTimeUtc.Ticks, Is.EqualTo(fileInfo2.CreationTimeUtc.Ticks));
}

private void DeleteOutputFolder()
{
var outputFolder = Path.Combine(_webHostEnvironment.WebRootPath, ReportSheetCache.ReportSheetCacheFolder);

// Delete folder in TempPath
if (!Directory.Exists(outputFolder)) return;
Directory.Delete(outputFolder, true);
}
}
3 changes: 1 addition & 2 deletions League.Tests/Identity/RoleStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,13 @@
using System.Threading.Tasks;
using System.Threading;
using League.Identity;
using League.Test.TestComponents;
using NUnit.Framework;
using SD.LLBLGen.Pro.ORMSupportClasses;
using TournamentManager.DAL.EntityClasses;
using TournamentManager.DAL.DatabaseSpecific;
using TournamentManager.MultiTenancy;

namespace League.Test.Identity;
namespace League.Tests.Identity;

/// <summary>
/// Integration tests
Expand Down
2 changes: 1 addition & 1 deletion League.Tests/Identity/UserAuthenticationTokenStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using SD.LLBLGen.Pro.ORMSupportClasses;
using TournamentManager.MultiTenancy;

namespace League.Test.Identity;
namespace League.Tests.Identity;

/// <summary>
/// Integration tests
Expand Down
4 changes: 1 addition & 3 deletions League.Tests/Identity/UserClaimStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
using System.Threading.Tasks;
using System.Threading;
using League.Identity;
using League.Test.TestComponents;
using NUnit.Framework;
using SD.LLBLGen.Pro.ORMSupportClasses;
using TournamentManager.Data;
using TournamentManager.DAL.EntityClasses;
using TournamentManager.DAL.DatabaseSpecific;
using TournamentManager.MultiTenancy;

namespace League.Test.Identity;
namespace League.Tests.Identity;

/// <summary>
/// Integration tests
Expand Down
4 changes: 1 addition & 3 deletions League.Tests/Identity/UserLoginStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
using System.Threading.Tasks;
using System.Threading;
using League.Identity;
using League.Test.TestComponents;
using NUnit.Framework;
using TournamentManager.DAL.DatabaseSpecific;
using TournamentManager.Data;
using TournamentManager.DAL.EntityClasses;
using SD.LLBLGen.Pro.ORMSupportClasses;
using TournamentManager.MultiTenancy;

namespace League.Test.Identity;
namespace League.Tests.Identity;

/// <summary>
/// Integration tests
Expand Down
7 changes: 1 addition & 6 deletions League.Tests/Identity/UserRoleStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,14 @@
using System.Threading.Tasks;
using System.Threading;
using League.Identity;
using League.Test.TestComponents;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using NUnit.Framework;
using SD.LLBLGen.Pro.ORMSupportClasses;
using TournamentManager.DAL.DatabaseSpecific;
using TournamentManager.Data;
using TournamentManager.DAL.EntityClasses;
using TournamentManager.DAL.HelperClasses;
using TournamentManager.MultiTenancy;

namespace League.Test.Identity;
namespace League.Tests.Identity;

/// <summary>
/// Integration tests
Expand Down
2 changes: 1 addition & 1 deletion League.Tests/Identity/UserStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
using TournamentManager.MultiTenancy;
using SD.LLBLGen.Pro.ORMSupportClasses;

namespace League.Test.Identity;
namespace League.Tests.Identity;

/// <summary>
/// Integration tests
Expand Down
2 changes: 1 addition & 1 deletion League.Tests/IntegrationTests/BasicIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.AspNetCore.TestHost;
using NUnit.Framework;

namespace League.Test;
namespace League.Tests;

[TestFixture]
public class BasicIntegrationTests
Expand Down
24 changes: 17 additions & 7 deletions League.Tests/TestComponents/CultureSwitcher.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

namespace League.Test.TestComponents;
namespace League.Tests.TestComponents;

public class CultureSwitcher : IDisposable
{
private readonly CultureInfo _originalCulture;
private readonly CultureInfo _originalUiCulture;
private readonly CultureInfo? _originalDefaultThreadCulture;
private readonly CultureInfo? _originalDefaultThreadUiCulture;

public CultureSwitcher(CultureInfo culture, CultureInfo uiCulture)
{
_originalCulture = CultureInfo.CurrentCulture;
_originalUiCulture = CultureInfo.CurrentUICulture;
SetCulture(culture, uiCulture);
_originalDefaultThreadCulture = CultureInfo.DefaultThreadCurrentCulture;
_originalDefaultThreadUiCulture = CultureInfo.DefaultThreadCurrentUICulture;
SetCurrentCulture(culture, uiCulture);
SetThreadDefaultCulture(culture, uiCulture);
}

private static void SetCulture(CultureInfo culture, CultureInfo uiCulture)
private static void SetCurrentCulture(CultureInfo culture, CultureInfo uiCulture)
{
CultureInfo.CurrentCulture = culture;
CultureInfo.CurrentUICulture = uiCulture;
}

private static void SetThreadDefaultCulture(CultureInfo? culture, CultureInfo? uiCulture)
{
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = uiCulture;
}

public void Dispose()
{
GC.SuppressFinalize(this);
SetCulture(_originalCulture, _originalUiCulture);
SetCurrentCulture(_originalCulture, _originalUiCulture);
SetThreadDefaultCulture(_originalDefaultThreadCulture, _originalDefaultThreadUiCulture);
}
}
}
2 changes: 1 addition & 1 deletion League.Tests/TestComponents/DirectoryLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.IO;
using System.Reflection;
#nullable enable
namespace League.Test.TestComponents;
namespace League.Tests.TestComponents;

public class DirectoryLocator
{
Expand Down
23 changes: 23 additions & 0 deletions League.Tests/TestComponents/HostingEnvironment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Copyright Volleyball League Project maintainers and contributors.
// Licensed under the MIT license.
//

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;

namespace League.Tests.TestComponents;
public class HostingEnvironment : IWebHostEnvironment
{
public string EnvironmentName { get; set; } = Microsoft.Extensions.Hosting.Environments.Development;

public string ApplicationName { get; set; } = null!;

public string WebRootPath { get; set; } = null!;

public IFileProvider WebRootFileProvider { get; set; } = null!;

public string ContentRootPath { get; set; } = null!;

public IFileProvider ContentRootFileProvider { get; set; } = null!;
}
34 changes: 31 additions & 3 deletions League.Tests/TestComponents/UnitTestHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System.Globalization;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Axuno.VirtualFileSystem;
using League.Caching;
using League.Identity;
using League.Test.TestComponents;
using League.Tests.TestComponents;
using League.TextTemplatingModule;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
Expand All @@ -18,7 +21,7 @@
using TournamentManager.MultiTenancy;
using ILogger = Microsoft.Extensions.Logging.ILogger;

namespace League.Test;
namespace League.Tests;

public class UnitTestHelpers
{
Expand Down Expand Up @@ -138,6 +141,31 @@ public static ServiceProvider GetTextTemplatingServiceProvider(ITenantContext te
.BuildServiceProvider();
}

public static ServiceProvider GetReportSheetCacheServiceProvider(ITenantContext tenantContext, IWebHostEnvironment webHostEnvironment, IEnumerable<KeyValuePair<string,string?>> chromiumPath)
{
return new ServiceCollection()
.AddLogging(builder =>
{
builder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
builder.AddNLog(new NLogProviderOptions
{
CaptureMessageTemplates = true,
CaptureMessageProperties = true
});
})
.AddTransient<IConfiguration>(sp =>
{
var c = new ConfigurationManager();
c.AddInMemoryCollection(chromiumPath);
return c;
})
.AddTransient<ITenantContext>(sp => tenantContext)
.AddTransient<IWebHostEnvironment>(sp => webHostEnvironment)
.AddTransient<ReportSheetCache>()
.AddLocalization()
.BuildServiceProvider();
}


public static TestServer GetLeagueTestServer()
{
Expand Down
4 changes: 2 additions & 2 deletions League.Tests/TextTemplating/EmailTemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
using League.Models.ContactViewModels;
using League.Templates.Email;
using League.Templates.Email.Localization;
using League.Test.TestComponents;
using League.Tests.TestComponents;
using League.TextTemplatingModule;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using NUnit.Framework;
using TournamentManager.DAL.TypedViewClasses;
using TournamentManager.MultiTenancy;

namespace League.Test.TextTemplating;
namespace League.Tests.TextTemplating;

/// <summary>
/// Tests for all email templates.
Expand Down
Loading

0 comments on commit 45092b5

Please sign in to comment.