Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 2 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,8 @@ env:

jobs:
test:
runs-on: ${{ matrix.os }}
runs-on: windows-latest
name: Build & Test
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
Expand All @@ -29,10 +25,5 @@ jobs:
- name: Install Playwright browsers & dependencies
run: pwsh test/OrchardCoreContrib.Testing.UI.Tests/bin/Release/net8.0/playwright.ps1 install --with-deps
- name: Test
run: |
if [ "${{ matrix.os }}" == "ubuntu-latest" ]; then
xvfb-run dotnet test test/OrchardCoreContrib.Testing.UI.Tests -c Release --no-restore --verbosity normal
else
run:
dotnet test test/OrchardCoreContrib.Testing.UI.Tests -c Release --no-restore --verbosity normal
fi
shell: bash
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,4 @@ FodyWeavers.xsd

# JetBrains Rider
*.sln.iml
src/OrchardCoreContrib.Testing.Web/Localization
25 changes: 23 additions & 2 deletions OrchardCoreContrib.Testing.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34701.34
# Visual Studio Version 18
VisualStudioVersion = 18.1.11312.151 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{20F306B8-D63F-4A61-AF6E-64B4E0918E30}"
EndProject
Expand All @@ -11,6 +11,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCoreContrib.Testing.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCoreContrib.Testing.UI.Tests", "test\OrchardCoreContrib.Testing.UI.Tests\OrchardCoreContrib.Testing.UI.Tests.csproj", "{985F5AD6-8C18-4E63-A35C-A5673F237A4D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCoreContrib.Testing", "src\OrchardCoreContrib.Testing\OrchardCoreContrib.Testing.csproj", "{60B9E226-55FF-4B5C-BFFE-57A14DE6CC58}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCoreContrib.Testing.Web", "src\OrchardCoreContrib.Testing.Web\OrchardCoreContrib.Testing.Web.csproj", "{A0FE9046-5B92-4C73-AB51-33CE15F14917}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCoreContrib.Testing.Tests", "test\OrchardCoreContrib.Testing.Tests\OrchardCoreContrib.Testing.Tests.csproj", "{F0C2E52D-4412-4A18-B0F7-FD99F85F192C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -25,13 +31,28 @@ Global
{985F5AD6-8C18-4E63-A35C-A5673F237A4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{985F5AD6-8C18-4E63-A35C-A5673F237A4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{985F5AD6-8C18-4E63-A35C-A5673F237A4D}.Release|Any CPU.Build.0 = Release|Any CPU
{60B9E226-55FF-4B5C-BFFE-57A14DE6CC58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60B9E226-55FF-4B5C-BFFE-57A14DE6CC58}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60B9E226-55FF-4B5C-BFFE-57A14DE6CC58}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60B9E226-55FF-4B5C-BFFE-57A14DE6CC58}.Release|Any CPU.Build.0 = Release|Any CPU
{A0FE9046-5B92-4C73-AB51-33CE15F14917}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0FE9046-5B92-4C73-AB51-33CE15F14917}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0FE9046-5B92-4C73-AB51-33CE15F14917}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0FE9046-5B92-4C73-AB51-33CE15F14917}.Release|Any CPU.Build.0 = Release|Any CPU
{F0C2E52D-4412-4A18-B0F7-FD99F85F192C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F0C2E52D-4412-4A18-B0F7-FD99F85F192C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F0C2E52D-4412-4A18-B0F7-FD99F85F192C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F0C2E52D-4412-4A18-B0F7-FD99F85F192C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A9E5A40B-78F8-4F02-9E73-C74F395B5BBD} = {20F306B8-D63F-4A61-AF6E-64B4E0918E30}
{985F5AD6-8C18-4E63-A35C-A5673F237A4D} = {27507B03-7D7C-492D-92A4-FF5812B9D7DB}
{60B9E226-55FF-4B5C-BFFE-57A14DE6CC58} = {20F306B8-D63F-4A61-AF6E-64B4E0918E30}
{A0FE9046-5B92-4C73-AB51-33CE15F14917} = {20F306B8-D63F-4A61-AF6E-64B4E0918E30}
{F0C2E52D-4412-4A18-B0F7-FD99F85F192C} = {27507B03-7D7C-492D-92A4-FF5812B9D7DB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DD153137-BF4D-4977-A4D7-4C448D23479A}
Expand Down
32 changes: 32 additions & 0 deletions src/OrchardCoreContrib.Testing.Web/NLog.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogLevel="Warn"
internalLogFile="${var:configDir}/logs/internal-nlog.txt">

<extensions>
<add assembly="NLog.Web.AspNetCore"/>
<add assembly="OrchardCore.Logging.NLog"/>
</extensions>

<targets>
<!-- file target -->
<target xsi:type="File" name="file"
fileName="${var:configDir}/logs/orchard-log-${shortdate}.log"
layout="${longdate}|${orchard-tenant-name}|${aspnet-traceidentifier}|${event-properties:item=EventId}|${logger}|${uppercase:${level}}|${message} ${exception:format=ToString,StackTrace}"
/>

<!-- console target -->
<target xsi:type="Console" name="console" />

</targets>

<rules>
<!-- all warnings and above go to the file target -->
<logger name="*" minlevel="Warn" writeTo="file" />

<!-- the hosting lifetime events go to the console and file targets -->
<logger name="Microsoft.Hosting.Lifetime" minlevel="Info" writeTo="file, console" />
</rules>
</nlog>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<Folder Include="wwwroot\" />
<Folder Include="Localization\" />
</ItemGroup>

<!-- Watcher include and excludes -->
<ItemGroup>
<Watch Include="**\*.cs" Exclude="Recipes\**;Assets\**;node_modules\**\*;**\*.js.map;obj\**\*;bin\**\*" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="OrchardCore.Logging.NLog" Version="2.2.1" />
<PackageReference Include="OrchardCore.Application.Cms.Targets" Version="2.2.1" />
</ItemGroup>

</Project>
35 changes: 35 additions & 0 deletions src/OrchardCoreContrib.Testing.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using OrchardCore.Logging;

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseNLogHost();

builder.Services
.AddOrchardCms()
// // Orchard Specific Pipeline
// .ConfigureServices( services => {
// })
// .Configure( (app, routes, services) => {
// })
;

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseOrchardCore();

app.Run();

namespace OrchardCoreContrib.Testing.Web
{
public partial class Program;
}
27 changes: 27 additions & 0 deletions src/OrchardCoreContrib.Testing.Web/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:8080",
"sslPort": 44300
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"OrchardCoreContrib.Testing.Web": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
9 changes: 9 additions & 0 deletions src/OrchardCoreContrib.Testing.Web/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
}
1 change: 1 addition & 0 deletions src/OrchardCoreContrib.Testing.Web/wwwroot/.placeholder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ÿþ
20 changes: 20 additions & 0 deletions src/OrchardCoreContrib.Testing/ISiteContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using OrchardCore.Environment.Shell;

namespace OrchardCoreContrib.Testing;

public interface ISiteContext : IDisposable
{
static IShellHost ShellHost { get; }

static IShellSettingsManager ShellSettingsManager { get; }

static HttpClient DefaultTenantClient { get; }

SiteContextOptions Options { init; get; }

HttpClient Client { get; }

string TenantName { get; }

Task InitializeAsync();
}
6 changes: 6 additions & 0 deletions src/OrchardCoreContrib.Testing/ISiteContextOfT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace OrchardCoreContrib.Testing;

public interface ISiteContext<TSiteStartup> : ISiteContext where TSiteStartup : class
{
static OrchardCoreWebApplicationFactory<TSiteStartup> Site { get; }
}
21 changes: 21 additions & 0 deletions src/OrchardCoreContrib.Testing/ModuleNamesProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using OrchardCore.Modules;
using OrchardCore.Modules.Manifest;
using System.Reflection;

namespace OrchardCoreContrib.Testing;

public sealed class ModuleNamesProvider : IModuleNamesProvider
{
private readonly IEnumerable<string> _moduleNames;

public ModuleNamesProvider(Assembly assembly)
{
ArgumentNullException.ThrowIfNull(assembly);

_moduleNames = Assembly.Load(new AssemblyName(assembly.GetName().Name))
.GetCustomAttributes<ModuleNameAttribute>()
.Select(m => m.Name);
}

public IEnumerable<string> GetModuleNames() => _moduleNames;
}
15 changes: 15 additions & 0 deletions src/OrchardCoreContrib.Testing/OrchardCoreContrib.Testing.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="OrchardCore.Abstractions" Version="2.2.1" />
<PackageReference Include="OrchardCore.Infrastructure.Abstractions" Version="2.2.1" />
<PackageReference Include="OrchardCore.Tenants" Version="2.2.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.24" />
</ItemGroup>

</Project>
27 changes: 27 additions & 0 deletions src/OrchardCoreContrib.Testing/OrchardCoreWebApplicationFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Hosting;

namespace OrchardCoreContrib.Testing;

public class OrchardCoreWebApplicationFactory<TEntryPoint> : WebApplicationFactory<TEntryPoint> where TEntryPoint : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
var shellsApplicationDataPath = Path.Combine(Directory.GetCurrentDirectory(), "App_Data");

if (Directory.Exists(shellsApplicationDataPath))
{
Directory.Delete(shellsApplicationDataPath, true);
}

builder.UseContentRoot(Directory.GetCurrentDirectory());
}

protected override IWebHostBuilder CreateWebHostBuilder()
=> WebHostBuilderFactory.CreateFromAssemblyEntryPoint(typeof(TEntryPoint).Assembly, []);

protected override IHostBuilder CreateHostBuilder()
=> Host.CreateDefaultBuilder().ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<TEntryPoint>());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using OrchardCore.Security;
using OrchardCore.Security.Permissions;

namespace OrchardCoreContrib.Testing.Security;

public sealed class PermissionContextAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
private readonly PermissionsContext _permissionsContext;

public PermissionContextAuthorizationHandler(IHttpContextAccessor httpContextAccessor, IDictionary<string, PermissionsContext> permissionsContexts)
{
_permissionsContext = new PermissionsContext();

if (httpContextAccessor.HttpContext is null)
{
return;
}

var request = httpContextAccessor.HttpContext.Request;

if (request?.Headers.ContainsKey(nameof(PermissionsContext)) == true &&
permissionsContexts.TryGetValue(request.Headers[nameof(PermissionsContext)], out var permissionsContext))
{
_permissionsContext = permissionsContext;
}
}

public PermissionContextAuthorizationHandler(PermissionsContext permissionsContext)
{
_permissionsContext = permissionsContext;
}

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
var permissions = (_permissionsContext.AuthorizedPermissions ?? []).ToList();

if (!_permissionsContext.UsePermissionsContext)
{
context.Succeed(requirement);
}
else if (permissions.Contains(requirement.Permission))
{
context.Succeed(requirement);
}
else
{
var grantingNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

GetGrantingNamesInternal(requirement.Permission, grantingNames);

if (permissions.Any(p => grantingNames.Contains(p.Name)))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}

return Task.CompletedTask;
}

private static void GetGrantingNamesInternal(Permission permission, HashSet<string> stack)
{
stack.Add(permission.Name);

if (permission.ImpliedBy != null && permission.ImpliedBy.Any())
{
foreach (var impliedBy in permission.ImpliedBy)
{
if (impliedBy == null || stack.Contains(impliedBy.Name))
{
continue;
}

GetGrantingNamesInternal(impliedBy, stack);
}
}
}
}
Loading