插件系统初步
This commit is contained in:
1 parent
ae4447841a
commit
7e3f138875
17 files changed
+9921
-12
No files matched your search
@@ -0,0 +1,116 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user