Merge remote-tracking branch 'origin/v13/dev' into v14/dev

# Conflicts:
#	.artifactignore
#	build/azure-pipelines.yml
#	tests/Umbraco.Tests.AcceptanceTest/misc/umbraco-linux.docker
This commit is contained in:
Jacob Overgaard
2024-02-02 13:48:28 +01:00
13 changed files with 442 additions and 247 deletions

View File

@@ -0,0 +1,42 @@
using Microsoft.Data.Sqlite;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Extensions;
namespace UmbracoProject;
/// <summary>
/// Ensures a SQLite in-memory database is persisted for the whole application duration.
/// </summary>
public sealed class SQLiteMemoryComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
var connectionString = builder.Config.GetUmbracoConnectionString(out var providerName);
if (!string.IsNullOrEmpty(connectionString) &&
Constants.ProviderNames.SQLLite.InvariantEquals(providerName) &&
connectionString.InvariantContains("Mode=Memory"))
{
// Open new SQLite connection to ensure in-memory database is persisted for the whole application duration
var connection = new SqliteConnection(connectionString);
connection.Open();
// And ensure connection is kept open (by keeping a reference) and gets gracefully closed/disposed when application stops
builder.Services.AddHostedService(_ => new SQLiteMemoryHostedService(connection));
}
}
private sealed class SQLiteMemoryHostedService : IHostedService, IAsyncDisposable
{
private readonly SqliteConnection _connection;
public SQLiteMemoryHostedService(SqliteConnection connection) => _connection = connection;
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public async Task StopAsync(CancellationToken cancellationToken) => await _connection.CloseAsync();
public async ValueTask DisposeAsync() => await _connection.DisposeAsync();
}
}

View File

@@ -0,0 +1,44 @@
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Extensions;
namespace UmbracoProject;
/// <summary>
/// Disable waiting on log IO to finish when commiting a transaction (we can tolerate some data loss) on SQL Server.
/// </summary>
public sealed class SqlServerDelayedDurabilityComposer : IComposer
{
public void Compose(IUmbracoBuilder builder)
{
var connectionString = builder.Config.GetUmbracoConnectionString(out var providerName);
if (!string.IsNullOrEmpty(connectionString) &&
Constants.ProviderNames.SQLServer.InvariantEquals(providerName))
{
builder.AddNotificationAsyncHandler<UnattendedInstallNotification, SqlServerDelayedDurabilityInstallNotification>();
}
}
private sealed class SqlServerDelayedDurabilityInstallNotification : INotificationAsyncHandler<UnattendedInstallNotification>
{
private readonly IOptions<ConnectionStrings> _connectionStrings;
public SqlServerDelayedDurabilityInstallNotification(IOptions<ConnectionStrings> connectionStrings) => _connectionStrings = connectionStrings;
public async Task HandleAsync(UnattendedInstallNotification notification, CancellationToken cancellationToken)
{
using var connection = new SqlConnection(_connectionStrings.Value.ConnectionString);
await connection.OpenAsync(cancellationToken);
// Disable waiting on log IO to finish when commiting a transaction (we can tolerate some data loss)
var command = new SqlCommand("ALTER DATABASE CURRENT SET DELAYED_DURABILITY = FORCED;", connection);
await command.ExecuteNonQueryAsync(cancellationToken);
}
}
}

View File

@@ -0,0 +1,13 @@
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Infrastructure;
namespace UmbracoProject;
/// <summary>
/// Suspends/disables scheduled publishing, because that takes an eager write lock every minute, resulting in flaky test runs on SQLite.
/// </summary>
public sealed class SuspendScheduledPublishingComposer : IComposer
{
public void Compose(IUmbracoBuilder builder) => Suspendable.ScheduledPublishing.Suspend();
}

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<!-- All C# files in the root of this project will be copied to the E2E/Acceptance Test application during build -->
<OutputType>Library</OutputType>
<RootNamespace>UmbracoProject</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Umbraco.Cms\Umbraco.Cms.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<!--
Keep this empty Directory.Build.props file to prevent inheriting from parent directories,
because the Windows E2E test that outputs a new Umbraco project into this directory otherwise won't build.
-->
</Project>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="local" value="./nupkg" />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View File

@@ -1,51 +0,0 @@
############################################
## Build
############################################
FROM mcr.microsoft.com/dotnet/nightly/sdk:8.0.100-rc.2-jammy AS build
COPY nuget.config .
COPY nuget.config .
WORKDIR /nupkg
COPY nupkg .
WORKDIR /build
RUN dotnet new --install /nupkg/Umbraco.Templates.*.nupkg
RUN dotnet new umbraco --name AcceptanceTestProject --no-restore --output .
RUN dotnet restore --configfile /nuget.config
RUN dotnet build --configuration Release --no-restore
RUN dotnet publish --configuration Release --no-build --output /dist
############################################
## Run
############################################
FROM mcr.microsoft.com/dotnet/nightly/aspnet:8.0.0-rc.2-jammy AS run
WORKDIR /app
COPY --from=build dist .
# Enable console logging in Release mode
ENV Serilog__WriteTo__0__Name=Async
ENV Serilog__WriteTo__0__Args__configure__0__Name=Console
# Set unattended install settings
ENV ConnectionStrings__umbracoDbDSN_ProviderName="Microsoft.Data.Sqlite"
ENV ConnectionStrings__umbracoDbDSN="Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True"
ENV Umbraco__CMS__Unattended__InstallUnattended="true"
ENV Umbraco__CMS__Unattended__UnattendedUserName="Playwright Test"
ENV Umbraco__CMS__Unattended__UnattendedUserEmail="playwright@umbraco.com"
ENV Umbraco__CMS__Unattended__UnattendedUserPassword="UmbracoAcceptance123!"
# Custom Umbraco settings
ENV Umbraco__CMS__Global__VersionCheckPeriod="0"
ENV Umbraco__CMS__Global__UseHttps="true"
ENV Umbraco__CMS__HealthChecks__Notification__Enabled="false"
ENV Umbraco__CMS__KeepAlive__DisableKeepAliveTask="true"
# Set application URL
ENV ASPNETCORE_URLS="http://0.0.0.0:5000;https://0.0.0.0:5001"
CMD dotnet AcceptanceTestProject.dll