Fix Sonar maintainability issues

Improved logging
Added missing comments
This commit is contained in:
Raymond den Haan 2024-05-30 15:34:26 +02:00 committed by raymonddenhaan
parent 218c839fc0
commit dc355413ce
11 changed files with 83 additions and 32 deletions

View file

@ -5,6 +5,13 @@ namespace Elsa.MassTransit.Messages;
/// </summary>
public class WorkflowDefinitionCreated(string id, bool usableAsActivity)
{
public string Id { get; set; } = id;
public bool UsableAsActivity { get; set; } = usableAsActivity;
/// <summary>
/// The ID of the created workflow definition.
/// </summary>
public string Id { get; } = id;
/// <summary>
/// Whether the created workflow definition is usable as an activity.
/// </summary>
public bool UsableAsActivity { get; } = usableAsActivity;
}

View file

@ -5,5 +5,8 @@ namespace Elsa.MassTransit.Messages;
/// </summary>
public class WorkflowDefinitionDeleted(string id)
{
public string Id { get; set; } = id;
/// <summary>
/// The ID of the deleted workflow definition.
/// </summary>
public string Id { get; } = id;
}

View file

@ -1,7 +1,17 @@
namespace Elsa.MassTransit.Messages;
/// <summary>
/// Represents a distributed message that is triggered when a workflow definition is published.
/// </summary>
public class WorkflowDefinitionPublished(string id, bool usableAsActivity)
{
public string Id { get; set; } = id;
public bool UsableAsActivity { get; set; } = usableAsActivity;
/// <summary>
/// The ID of the published workflow definition.
/// </summary>
public string Id { get; } = id;
/// <summary>
/// Whether the published workflow definition is usable as an activity.
/// </summary>
public bool UsableAsActivity { get; } = usableAsActivity;
}

View file

@ -91,7 +91,7 @@ public class DefaultTriggerScheduler(IWorkflowScheduler workflowScheduler, ISyst
}
catch (FormatException ex)
{
logger.LogWarning($"Cron expression format error: {ex.Message}. CronExpression: {cronExpression}");
logger.LogWarning(ex,"Cron expression format error: {exceptionMessage}. CronExpression: {cronExpression}", ex.Message, cronExpression);
}
}
}

View file

@ -5,6 +5,7 @@ using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Exceptions;
using Elsa.Workflows.Memory;
using Elsa.Workflows.Models;
using Elsa.Workflows.Options;
@ -580,7 +581,7 @@ public partial class WorkflowExecutionContext : IExecutionContext
/// </summary>
public async Task<ActivityExecutionContext> CreateActivityExecutionContext(IActivity activity, ActivityInvocationOptions? options = default)
{
var activityDescriptor = await ActivityRegistryLookup.Find(activity) ?? throw new Exception($"Activity with type {activity.Type} not found in registry");
var activityDescriptor = await ActivityRegistryLookup.Find(activity) ?? throw new ActivityNotFoundException(activity.Type);
var tag = options?.Tag;
var parentContext = options?.Owner;
var parentExpressionExecutionContext = parentContext?.ExpressionExecutionContext ?? ExpressionExecutionContext;

View file

@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Elsa.Workflows.Models;
namespace Elsa.Workflows.Contracts;
@ -74,7 +75,7 @@ public interface IActivityRegistry : IActivityProvider
/// </summary>
/// <param name="activityType">The activity type to register.</param>
/// <param name="cancellationToken">An optional cancellation token.</param>
Task RegisterAsync(Type activityType, CancellationToken cancellationToken = default);
Task RegisterAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type activityType, CancellationToken cancellationToken = default);
/// <summary>
/// Registers multiple activity types.

View file

@ -5,6 +5,12 @@ namespace Elsa.Workflows.Exceptions;
/// </summary>
public class ActivityNotFoundException : Exception
{
/// <inheritdoc />
public ActivityNotFoundException(string missingTypeName) : base($"Activity type '{missingTypeName}' could not be found.")
{
MissingTypeName = missingTypeName;
}
/// <inheritdoc />
public ActivityNotFoundException(string missingTypeName, int missingTypeVersion) : base($"Activity type '{missingTypeName}' version '{missingTypeVersion}' could not be found.")
{

View file

@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Helpers;
using Elsa.Workflows.Models;
@ -48,7 +49,7 @@ public class ActivityRegistry(IActivityDescriber activityDescriber, IEnumerable<
}
/// <inheritdoc />
public async Task RegisterAsync(Type activityType, CancellationToken cancellationToken)
public async Task RegisterAsync([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type activityType, CancellationToken cancellationToken)
{
var activityTypeName = ActivityTypeNameHelper.GenerateTypeName(activityType);
@ -70,6 +71,7 @@ public class ActivityRegistry(IActivityDescriber activityDescriber, IEnumerable<
/// <inheritdoc />
public ValueTask<IEnumerable<ActivityDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default) => new(_manualActivityDescriptors);
/// <inheritdoc />
public async Task RefreshDescriptors(IEnumerable<IActivityProvider> activityProviders, CancellationToken cancellationToken = default)
{
var providersDictionary = new ConcurrentDictionary<Type, ICollection<ActivityDescriptor>>();
@ -94,7 +96,7 @@ public class ActivityRegistry(IActivityDescriber activityDescriber, IEnumerable<
Add(descriptor, _activityDescriptors, target);
}
private void Add(ActivityDescriptor descriptor, ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> activityDescriptors, ICollection<ActivityDescriptor> providerDescriptors)
private void Add(ActivityDescriptor? descriptor, ConcurrentDictionary<(string Type, int Version), ActivityDescriptor> activityDescriptors, ICollection<ActivityDescriptor> providerDescriptors)
{
if (descriptor is null)
{

View file

@ -3,7 +3,6 @@ using Elsa.Http;
using Elsa.Http.Bookmarks;
using Elsa.Http.Contracts;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Helpers;
using Elsa.Workflows.Management.Contracts;
using Elsa.Workflows.Runtime.Filters;
using Microsoft.Extensions.Caching.Memory;
@ -14,7 +13,6 @@ namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities;
public class AutoUpdateTests : AppComponentTest
{
private readonly IMemoryCache _cache;
private readonly IBookmarkHasher _bookmarkHasher;
private readonly IHasher _hasher;
private readonly IWorkflowDefinitionCacheManager _definitionCacheManager;
private readonly IWorkflowDefinitionPublisher _publisher;
@ -26,9 +24,9 @@ public class AutoUpdateTests : AppComponentTest
private readonly IHttpWorkflowsCacheManager _httpCacheManager;
private readonly IWorkflowDefinitionCacheManager _workflowCacheManager;
private string _httpChangeToken;
private string _triggerChangeToken;
private string _graphChangeToken;
private string? _httpChangeToken;
private string? _triggerChangeToken;
private string? _graphChangeToken;
private static readonly object HttpChangeTokenSignal = new();
private static readonly object TriggerChangeTokenSignal = new();
@ -41,7 +39,6 @@ public class AutoUpdateTests : AppComponentTest
public AutoUpdateTests(App app) : base(app)
{
_cache = Scope.ServiceProvider.GetRequiredService<IMemoryCache>();
_bookmarkHasher = Scope.ServiceProvider.GetRequiredService<IBookmarkHasher>();
_hasher = Scope.ServiceProvider.GetRequiredService<IHasher>();
_definitionCacheManager = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionCacheManager>();
_publisher = Scope.ServiceProvider.GetRequiredService<IWorkflowDefinitionPublisher>();

View file

@ -1,5 +1,4 @@
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
using Elsa.Workflows.Management.Contracts;
using Microsoft.Extensions.DependencyInjection;
@ -28,43 +27,42 @@ public class DeleteWorkflowTests : AppComponentTest
[Fact]
public async Task DeleteWorkflow()
{
EnsureWorkflowInRegistry(_scope1);
EnsureWorkflowInRegistry(_scope1, Workflows.DeleteWorkflow.Type);
var workflowDefinitionManager = _scope1.ServiceProvider.GetRequiredService<IWorkflowDefinitionManager>();
await workflowDefinitionManager.DeleteByDefinitionIdAsync(Workflows.DeleteWorkflow.DefinitionId);
WorkflowTypeDeletedFromRegistry(_scope1);
WorkflowTypeDeletedFromRegistry(_scope1, Workflows.DeleteWorkflow.Type);
}
[Fact(Skip = "Clustered tests are interfering with other event driven tests")]
public async Task DeleteWorkflow_Clustered()
{
EnsureWorkflowInRegistry(_scope1);
EnsureWorkflowInRegistry(_scope2);
EnsureWorkflowInRegistry(_scope3);
EnsureWorkflowInRegistry(_scope1, Workflows.DeleteWorkflowClustered.Type);
EnsureWorkflowInRegistry(_scope2, Workflows.DeleteWorkflowClustered.Type);
EnsureWorkflowInRegistry(_scope3, Workflows.DeleteWorkflowClustered.Type);
var workflowDefinitionManager = _scope1.ServiceProvider.GetRequiredService<IWorkflowDefinitionManager>();
await workflowDefinitionManager.DeleteByDefinitionIdAsync(Workflows.DeleteWorkflow.DefinitionId);
await workflowDefinitionManager.DeleteByDefinitionIdAsync(Workflows.DeleteWorkflowClustered.DefinitionId);
WorkflowTypeDeletedFromRegistry(_scope1);
WorkflowTypeDeletedFromRegistry(_scope1, Workflows.DeleteWorkflowClustered.Type);
await _signalManager.WaitAsync<WorkflowDefinitionDeletedEventArgs>(WorkflowDeletedSignal);
WorkflowTypeDeletedFromRegistry(_scope2);
WorkflowTypeDeletedFromRegistry(_scope3);
WorkflowTypeDeletedFromRegistry(_scope2, Workflows.DeleteWorkflowClustered.Type);
WorkflowTypeDeletedFromRegistry(_scope3, Workflows.DeleteWorkflowClustered.Type);
}
private void EnsureWorkflowInRegistry(IServiceScope scope)
private static void EnsureWorkflowInRegistry(IServiceScope scope, string type)
{
var activityRegistry = scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
var descriptor = activityRegistry.Find(Workflows.DeleteWorkflow.Type);
if (descriptor is null)
activityRegistry.Add(typeof(WorkflowDefinitionActivityProvider), descriptor);
var descriptor = activityRegistry.Find(type);
Assert.NotNull(descriptor);
}
private void WorkflowTypeDeletedFromRegistry(IServiceScope scope)
private static void WorkflowTypeDeletedFromRegistry(IServiceScope scope, string type)
{
var activityRegistry = scope.ServiceProvider.GetRequiredService<IActivityRegistry>();
var descriptor = activityRegistry.Find(Workflows.DeleteWorkflow.Type);
var descriptor = activityRegistry.Find(type);
Assert.Null(descriptor);
}

View file

@ -0,0 +1,26 @@
using Elsa.Scheduling.Activities;
using Elsa.Workflows.Activities;
using Elsa.Workflows.Contracts;
namespace Elsa.Workflows.ComponentTests.Scenarios.WorkflowActivities.Workflows;
public class DeleteWorkflowClustered : WorkflowBase
{
public static readonly string DefinitionId = Guid.NewGuid().ToString();
public static readonly string Type = nameof(DeleteWorkflowClustered);
protected override void Build(IWorkflowBuilder builder)
{
builder.Name = Type;
builder.WithDefinitionId(DefinitionId);
builder.WorkflowOptions.UsableAsActivity = true;
builder.Root = new Sequence
{
Activities =
{
new Delay(TimeSpan.FromMilliseconds(250)),
new WriteLine("This workflow will be deleted!")
}
};
}
}