117 lines
4.1 KiB
C#
117 lines
4.1 KiB
C#
using System.Reflection;
|
|
using Jiaowu.Api.Controllers;
|
|
using Jiaowu.Api.Domain.Identity;
|
|
using Jiaowu.Api.Infrastructure.Persistence;
|
|
using Jiaowu.Api.Infrastructure.Plugins;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Jiaowu.Api.Infrastructure.Middleware;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace Jiaowu.Api.Tests;
|
|
|
|
public sealed class PluginRuntimeTests
|
|
{
|
|
[Fact]
|
|
public void Management_endpoints_require_super_admin()
|
|
{
|
|
var method = typeof(PluginsController).GetMethod(
|
|
nameof(PluginsController.SetState));
|
|
var authorize = method?.GetCustomAttribute<AuthorizeAttribute>();
|
|
|
|
Assert.NotNull(authorize);
|
|
Assert.Equal(SystemRoles.SuperAdmin, authorize.Roles);
|
|
}
|
|
|
|
[Fact]
|
|
public void Catalog_maps_only_complete_api_path_segments()
|
|
{
|
|
var catalog = new BuiltInPluginCatalog();
|
|
|
|
Assert.Equal(
|
|
"mingxu.experiments",
|
|
catalog.FindByApiPath("/api/experiments/123")?.Id);
|
|
Assert.Null(catalog.FindByApiPath("/api/experiments-other"));
|
|
Assert.Null(catalog.FindByApiPath("/api/plugins/runtime"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Plugins_are_enabled_by_default_and_state_is_persisted()
|
|
{
|
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
|
.UseSqlite("Data Source=:memory:")
|
|
.Options;
|
|
await using var db = new AppDbContext(options);
|
|
await db.Database.OpenConnectionAsync();
|
|
await db.Database.EnsureCreatedAsync();
|
|
var runtime = new PluginRuntimeService(
|
|
db,
|
|
new BuiltInPluginCatalog());
|
|
|
|
Assert.True(await runtime.IsEnabledAsync("mingxu.experiments"));
|
|
|
|
var updated = await runtime.SetEnabledAsync(
|
|
"mingxu.experiments",
|
|
false,
|
|
"admin-user");
|
|
|
|
Assert.NotNull(updated);
|
|
Assert.False(updated.IsEnabled);
|
|
Assert.False(await runtime.IsEnabledAsync("mingxu.experiments"));
|
|
var persisted = await db.PluginInstallations.SingleAsync();
|
|
Assert.Equal("admin-user", persisted.ChangedByUserId);
|
|
Assert.Equal("1.0.0", persisted.InstalledVersion);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Unknown_plugin_cannot_be_enabled()
|
|
{
|
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
|
.UseSqlite("Data Source=:memory:")
|
|
.Options;
|
|
await using var db = new AppDbContext(options);
|
|
await db.Database.OpenConnectionAsync();
|
|
await db.Database.EnsureCreatedAsync();
|
|
var runtime = new PluginRuntimeService(
|
|
db,
|
|
new BuiltInPluginCatalog());
|
|
|
|
Assert.Null(await runtime.SetEnabledAsync("unknown.plugin", true, null));
|
|
Assert.False(await runtime.IsEnabledAsync("unknown.plugin"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Disabled_plugin_blocks_its_api_without_invoking_the_endpoint()
|
|
{
|
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
|
.UseSqlite("Data Source=:memory:")
|
|
.Options;
|
|
await using var db = new AppDbContext(options);
|
|
await db.Database.OpenConnectionAsync();
|
|
await db.Database.EnsureCreatedAsync();
|
|
var catalog = new BuiltInPluginCatalog();
|
|
var runtime = new PluginRuntimeService(db, catalog);
|
|
await runtime.SetEnabledAsync("mingxu.experiments", false, "admin-user");
|
|
var endpointInvoked = false;
|
|
var middleware = new PluginAvailabilityMiddleware(_ =>
|
|
{
|
|
endpointInvoked = true;
|
|
return Task.CompletedTask;
|
|
});
|
|
var context = new DefaultHttpContext();
|
|
await using var requestServices = new ServiceCollection()
|
|
.AddLogging()
|
|
.AddProblemDetails()
|
|
.BuildServiceProvider();
|
|
context.RequestServices = requestServices;
|
|
context.Request.Path = "/api/experiments";
|
|
context.Response.Body = new MemoryStream();
|
|
|
|
await middleware.InvokeAsync(context, catalog, runtime);
|
|
|
|
Assert.False(endpointInvoked);
|
|
Assert.Equal(StatusCodes.Status404NotFound, context.Response.StatusCode);
|
|
}
|
|
}
|