Update Test-OPNSenseThreading cmdlet to work without connection (v2025.04.15.1749)

This commit is contained in:
GraceSolutions
2025-04-15 17:50:27 -04:00
parent 459940c32f
commit a413875058
13 changed files with 535 additions and 37 deletions
@@ -2,6 +2,7 @@ using System;
using System.Management.Automation;
using System.Threading;
using System.Threading.Tasks;
using PSOPNSenseAPI.Logging;
namespace PSOPNSenseAPI.Cmdlets
{
@@ -11,7 +12,7 @@ namespace PSOPNSenseAPI.Cmdlets
/// </summary>
[Cmdlet(VerbsDiagnostic.Test, "OPNSenseThreading")]
[OutputType(typeof(string))]
public class TestThreadingCmdlet : OPNSenseBaseCmdlet
public class TestThreadingCmdlet : PSCmdlet
{
/// <summary>
/// <para type="description">The test mode to run.</para>
@@ -26,41 +27,101 @@ namespace PSOPNSenseAPI.Cmdlets
[Parameter(Mandatory = false)]
public int Delay { get; set; } = 1000;
/// <summary>
/// Exception to be processed in ProcessRecord
/// </summary>
protected Exception ProcessingException { get; set; }
/// <summary>
/// Begins the processing of the cmdlet
/// </summary>
protected override void BeginProcessing()
{
base.BeginProcessing();
}
/// <summary>
/// Processes the cmdlet
/// </summary>
protected override void ProcessRecordInternal()
protected override void ProcessRecord()
{
WriteVerbose($"Starting test in mode: {Mode}");
WriteVerbose($"Current thread ID: {Thread.CurrentThread.ManagedThreadId}");
WriteVerbose($"Current synchronization context: {SynchronizationContext.Current != null}");
switch (Mode)
try
{
case "Direct":
TestDirect();
break;
case "ConfigureAwait":
TestConfigureAwait();
break;
case "SynchronizationContext":
TestSynchronizationContext();
break;
case "TaskRun":
TestTaskRun();
break;
}
WriteVerbose($"Starting test in mode: {Mode}");
WriteVerbose($"Current thread ID: {Thread.CurrentThread.ManagedThreadId}");
WriteVerbose($"Current synchronization context: {SynchronizationContext.Current != null}");
WriteVerbose("Test completed");
switch (Mode)
{
case "Direct":
TestDirect();
break;
case "ConfigureAwait":
TestConfigureAwait();
break;
case "SynchronizationContext":
TestSynchronizationContext();
break;
case "TaskRun":
TestTaskRun();
break;
}
WriteVerbose("Test completed");
}
catch (Exception ex)
{
WriteWarning($"Error occurred: {ex.Message}");
ProcessingException = ex;
}
finally
{
// Process any exceptions that occurred
if (ProcessingException != null)
{
WriteWarning($"Processing exception: {ProcessingException.Message}");
ProcessingException = null;
}
}
}
/// <summary>
/// Ends the processing of the cmdlet
/// </summary>
protected override void EndProcessing()
{
base.EndProcessing();
}
/// <summary>
/// Executes an async task synchronously and safely
/// </summary>
/// <typeparam name="T">The return type of the task</typeparam>
/// <param name="asyncFunc">The async function to execute</param>
/// <returns>The result of the async function</returns>
protected T ExecuteAsyncTask<T>(Func<Task<T>> asyncFunc)
{
try
{
// Use ConfigureAwait(false) to avoid deadlocks
return asyncFunc().ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (Exception ex)
{
// Store the exception to be processed in ProcessRecord
ProcessingException = ex;
WriteWarning($"Error occurred: {ex.Message}");
return default;
}
}
private void TestDirect()
{
WriteVerbose("Testing direct method call");
WriteVerbose($"Before delay - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
Task.Delay(Delay).Wait();
WriteVerbose($"After delay - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
WriteObject("Direct test completed");
}
@@ -69,13 +130,13 @@ namespace PSOPNSenseAPI.Cmdlets
{
WriteVerbose("Testing ConfigureAwait(false)");
WriteVerbose($"Before async call - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
var result = ExecuteAsyncTask(() => Task.Delay(Delay).ContinueWith(t =>
var result = ExecuteAsyncTask(() => Task.Delay(Delay).ContinueWith(t =>
{
WriteVerbose($"Inside async task - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
return "ConfigureAwait test completed";
}));
WriteVerbose($"After async call - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
WriteObject(result);
}
@@ -85,24 +146,24 @@ namespace PSOPNSenseAPI.Cmdlets
WriteVerbose("Testing SynchronizationContext");
WriteVerbose($"Before async call - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
WriteVerbose($"SynchronizationContext: {SynchronizationContext.Current != null}");
var syncContext = SynchronizationContext.Current;
var result = ExecuteAsyncTask(() => Task.Delay(Delay).ContinueWith(t =>
var result = ExecuteAsyncTask(() => Task.Delay(Delay).ContinueWith(t =>
{
var taskThreadId = Thread.CurrentThread.ManagedThreadId;
WriteVerbose($"Inside async task - Thread ID: {taskThreadId}");
if (syncContext != null)
{
syncContext.Post(_ =>
syncContext.Post(_ =>
{
WriteVerbose($"Inside SynchronizationContext.Post - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
}, null);
}
return "SynchronizationContext test completed";
}));
WriteVerbose($"After async call - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
WriteObject(result);
}
@@ -111,17 +172,17 @@ namespace PSOPNSenseAPI.Cmdlets
{
WriteVerbose("Testing Task.Run");
WriteVerbose($"Before Task.Run - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
var task = Task.Run(() =>
var task = Task.Run(() =>
{
WriteVerbose($"Inside Task.Run - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(Delay);
WriteVerbose($"After delay in Task.Run - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
return "TaskRun test completed";
});
var result = task.GetAwaiter().GetResult();
WriteVerbose($"After Task.Run - Thread ID: {Thread.CurrentThread.ManagedThreadId}");
WriteObject(result);
}
+1 -1
View File
@@ -3,7 +3,7 @@
RootModule = 'lib\PSOPNSenseAPI.dll'
# Version number of this module.
ModuleVersion = '2025.04.15.1740'
ModuleVersion = '2025.04.15.1749'
# Supported PSEditions
CompatiblePSEditions = @('Desktop', 'Core')