Unit tests for module lifecycle behavior in the SboxSuperuser.Contracts system. Exercises install/enable/disable flows, permission registration, command registration/commit/rollback, dependency ordering, security checks, and collision/error handling using TestAdminModule and a ModuleFixture.
using Xunit;
namespace SboxSuperuser.Contracts.Tests;
public sealed class ModuleLifecycleTests
{
[Fact]
public async Task FailedStartupRollsBackCommandsPermissionsAndEveryListener()
{
using var fixture = new ModuleFixture();
var cleanup = new List<int>();
var module = new TestAdminModule( "sample" ) { Start = ( registration, _ ) =>
{
registration.RegisterPermission( new PermissionDescriptor( "sample.use", "Owned permission" ) );
TestAdminModule.Command( registration, "sample.run" );
registration.Track( new ModuleSubscription( () => cleanup.Add( 1 ) ) );
registration.Track( new ModuleSubscription( () => cleanup.Add( 2 ) ) );
throw new InvalidOperationException( "Injected startup failure" );
} };
fixture.Manager.Install( new[] { module } );
Assert.Equal( CommandStatus.Failed, (await fixture.Enable( "sample" )).Status );
Assert.Null( fixture.Rig.Registry.Find( "sample.run" ) );
Assert.DoesNotContain( "sample.use", fixture.Rig.Policy.RegisteredPermissions );
Assert.Equal( new[] { 2, 1 }, cleanup );
Assert.Equal( 1, module.Stops );
Assert.Equal( ModuleState.Faulted, fixture.State( "sample" ) );
}
[Fact]
public async Task PendingStartupIsInvisibleAndCannotCommitItsOwnScope()
{
using var fixture = new ModuleFixture();
var ready = new TaskCompletionSource<bool>();
var module = new TestAdminModule( "sample" ) { Start = ( registration, _ ) =>
{
Assert.False( registration is CommandRegistrationScope );
TestAdminModule.Command( registration, "sample.run" );
return ready.Task;
} };
fixture.Manager.Install( new[] { module } );
var enable = fixture.Enable( "sample" );
Assert.Null( fixture.Rig.Registry.Find( "sample.run" ) );
Assert.Equal( CommandStatus.Conflict, (await fixture.Enable( "sample" )).Status );
ready.SetResult( true );
Assert.Equal( CommandStatus.Success, (await enable).Status );
Assert.NotNull( fixture.Rig.Registry.Find( "sample.run" ) );
}
[Fact]
public async Task RepeatEnableDisableLeavesOneHandlerAndRetainsStoredPolicy()
{
using var fixture = new ModuleFixture();
var listeners = 0;
var calls = 0;
var module = new TestAdminModule( "sample" ) { Start = ( registration, _ ) =>
{
listeners++;
registration.Track( new ModuleSubscription( () => listeners-- ) );
TestAdminModule.Command( registration, "sample.run", ( _, _ ) =>
{
calls++;
return Task.FromResult( new CommandResult( CommandStatus.Success, "Done" ) );
} );
return Task.CompletedTask;
} };
fixture.Manager.Install( new[] { module } );
var permissionCount = fixture.Rig.Policy.RegisteredPermissions.Count;
for ( var i = 0; i < 5; i++ )
{
Assert.Equal( CommandStatus.Success, (await fixture.Enable( "sample" )).Status );
Assert.Equal( CommandStatus.Success, (await fixture.Enable( "sample" )).Status );
Assert.Equal( 1, listeners );
Assert.Equal( CommandStatus.Success, (await fixture.Rig.Submit( "sample.run" )).Status );
Assert.Equal( CommandStatus.Success, (await fixture.Disable( "sample" )).Status );
Assert.Equal( 0, listeners );
Assert.Equal( CommandStatus.NotFound, (await fixture.Rig.Submit( "sample.run" )).Status );
}
Assert.Equal( 5, calls );
Assert.Equal( 5, module.Starts );
Assert.Equal( 5, module.Stops );
Assert.Equal( permissionCount, fixture.Rig.Policy.RegisteredPermissions.Count );
Assert.True( fixture.Rig.Policy.IsOwner( DispatcherRig.OwnerId ) );
}
[Fact]
public async Task DependenciesStartInOrderAndCannotStopUnderActiveConsumers()
{
using var fixture = new ModuleFixture();
var started = new List<string>();
var dependency = new TestAdminModule( "base" ) { Start = ( _, _ ) => { started.Add( "base" ); return Task.CompletedTask; } };
var consumer = new TestAdminModule( "consumer", false, new ModuleDependency( "base", 1 ) )
{ Start = ( _, _ ) => { started.Add( "consumer" ); return Task.CompletedTask; } };
fixture.Manager.Install( new[] { consumer, dependency } );
Assert.Equal( CommandStatus.Success, (await fixture.Enable( "consumer" )).Status );
Assert.Equal( new[] { "base", "consumer" }, started );
Assert.Equal( CommandStatus.Conflict, (await fixture.Disable( "base" )).Status );
Assert.Equal( CommandStatus.Success, (await fixture.Disable( "consumer" )).Status );
Assert.Equal( CommandStatus.Success, (await fixture.Disable( "base" )).Status );
}
[Fact]
public async Task OwnerOnlyManagementAndRequiredSecurityProtectionSurviveDirectGrants()
{
using var fixture = new ModuleFixture();
fixture.Manager.Install( new[] { new TestAdminModule( "security", required: true ), new TestAdminModule( "sample" ) } );
Assert.Equal( CommandStatus.Denied, (await fixture.Enable( "sample", DispatcherRig.User )).Status );
await fixture.Rig.Edit( PolicyChange.SetUserPermission( DispatcherRig.UserId, "admin.security.manage", PermissionEffect.Allow ) );
Assert.Equal( CommandStatus.Denied, (await fixture.Enable( "sample", DispatcherRig.User )).Status );
Assert.Equal( CommandStatus.Success, (await fixture.Enable( "security" )).Status );
Assert.Equal( CommandStatus.Denied, (await fixture.Disable( "security" )).Status );
Assert.Equal( CommandStatus.Denied, (await fixture.Disable( "superuser.core", DispatcherRig.ConsoleActor )).Status );
Assert.Equal( CommandStatus.Denied, (await fixture.Disable( "superuser.administration" )).Status );
}
[Fact]
public void InvalidInstallDoesNotPartiallyOwnCatalogAndDirectReplacementIsRefused()
{
using var fixture = new ModuleFixture();
Assert.Throws<ArgumentException>( () => fixture.Manager.Install( new[] { new TestAdminModule( "valid" ), new TestAdminModule( "bad", false, new ModuleDependency( "missing", 1 ) ) } ) );
Assert.False( fixture.Rig.Registry.HasModule( "valid" ) );
Assert.Equal( 2, fixture.Manager.Statuses.Count );
fixture.Manager.Install( new[] { new TestAdminModule( "valid" ) } );
using var replacement = new CommandRegistrationScope( fixture.Rig.Registry, "valid" );
Assert.Throws<InvalidOperationException>( replacement.Commit );
Assert.Throws<ArgumentException>( () => fixture.Manager.Install( new[] { new TestAdminModule( "valid" ) } ) );
}
[Fact]
public async Task CollisionAtCommitRollsBackWithoutReplacingExistingCommands()
{
using var fixture = new ModuleFixture();
using var existing = fixture.Rig.Register( "taken", ( _, _ ) => Task.FromResult( new CommandResult( CommandStatus.Success, "Original" ) ) );
var module = new TestAdminModule( "sample" ) { Start = ( registration, _ ) =>
{
TestAdminModule.Command( registration, "taken" );
TestAdminModule.Command( registration, "sample.run" );
return Task.CompletedTask;
} };
fixture.Manager.Install( new[] { module } );
Assert.Equal( CommandStatus.Failed, (await fixture.Enable( "sample" )).Status );
Assert.Null( fixture.Rig.Registry.Find( "sample.run" ) );
Assert.Equal( "Original", (await fixture.Rig.Submit( "taken" )).Message );
}
}