Skip to content

Commit

Permalink
Merge branch 'main' into feature/add-activity-source
Browse files Browse the repository at this point in the history
  • Loading branch information
sgryphon authored Nov 15, 2024
2 parents 9b6e579 + 4e8040f commit f9f305b
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 9 deletions.
4 changes: 2 additions & 2 deletions psake-project.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ Task Test -Depends Merge -Description "Run unit and integration tests against me
# support halting the whole execution pipeline when "dotnet test" command fails due to a failed test,
# silently allowing build process to continue its execution even with failed tests.
Exec { dotnet test -c Release --no-build "tests\Hangfire.Core.Tests" }
Exec { dotnet test -c Release --no-build "tests\Hangfire.SqlServer.Tests" }
Exec { dotnet test -c Release --no-build "tests\Hangfire.SqlServer.Msmq.Tests" }
Exec { dotnet test -c Release --no-build -p:TestTfmsInParallel=false "tests\Hangfire.SqlServer.Tests" }
Exec { dotnet test -c Release --no-build -p:TestTfmsInParallel=false "tests\Hangfire.SqlServer.Msmq.Tests" }
}

Task Collect -Depends Test -Description "Copy all artifacts to the build folder." {
Expand Down
2 changes: 2 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
<DebugType>embedded</DebugType>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<LangVersion>Latest</LangVersion>
<NuGetAuditMode>direct</NuGetAuditMode>
<CheckNotRecommendedTargetFramework>false</CheckNotRecommendedTargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
Expand Down
2 changes: 1 addition & 1 deletion src/Hangfire.AspNetCore/Hangfire.AspNetCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>net451;net461;netstandard1.3;netstandard2.0;netcoreapp3.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1591</NoWarn>
<NoWarn>$(NoWarn);1591</NoWarn>
<RootNamespace>Hangfire</RootNamespace>
</PropertyGroup>

Expand Down
5 changes: 4 additions & 1 deletion src/Hangfire.Core/States/BackgroundJobStateChanger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ public IState ChangeState(StateChangeContext context)
}
}

transaction.Commit();
if (context.Transaction == null)
{
transaction.Commit();
}

context.ProcessedJob = backgroundJob;
return appliedState;
Expand Down
20 changes: 16 additions & 4 deletions src/Hangfire.Core/States/EnqueuedState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ namespace Hangfire.States
/// <threadsafety static="true" instance="false" />
public class EnqueuedState : IState
{
private static readonly Regex ValidationRegex = new Regex(@"^[a-z0-9_-]+$", RegexOptions.Compiled | RegexOptions.CultureInvariant, TimeSpan.FromSeconds(5));

/// <summary>
/// Represents the default queue name. This field is constant.
/// </summary>
Expand Down Expand Up @@ -232,7 +230,7 @@ internal static bool TryValidateQueueName([NotNull] string value)
throw new ArgumentNullException(nameof(value));
}

return ValidationRegex.IsMatch(value);
return ValidateQueueNameInner(value);
}

internal static void ValidateQueueName([InvokerParameterName] string parameterName, [NotNull] string value)
Expand All @@ -242,14 +240,28 @@ internal static void ValidateQueueName([InvokerParameterName] string parameterNa
throw new ArgumentNullException(parameterName);
}

if (!ValidationRegex.IsMatch(value))
if (!ValidateQueueNameInner(value))
{
throw new ArgumentException(
$"The queue name must consist of lowercase letters, digits, underscore, and dash characters only. Given: '{value}'.",
parameterName);
}
}

private static bool ValidateQueueNameInner(string value)
{
foreach (var ch in value)
{
// ^[a-z0-9_-]+$
if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '_'))
{
return false;
}
}

return true;
}

internal sealed class Handler : IStateHandler
{
public void Apply(ApplyStateContext context, IWriteOnlyTransaction transaction)
Expand Down
4 changes: 4 additions & 0 deletions tests/Hangfire.Core.Tests/Mocks/StateChangeContextMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ public StateChangeContextMock()
() => new StateChangeContext(
Storage.Object,
Connection.Object,
Transaction?.Object,
BackgroundJobId,
NewState.Object,
ExpectedStates,
DisableFilters,
CompleteJob?.Object,
CancellationToken,
EmptyProfiler.Instance,
ServerId,
Expand All @@ -38,6 +40,8 @@ public StateChangeContextMock()

public Mock<JobStorage> Storage { get; set; }
public Mock<IStorageConnection> Connection { get; set; }
public Mock<JobStorageTransaction> Transaction { get; set; }
public Mock<IFetchedJob> CompleteJob { get; set; }
public string BackgroundJobId { get; set; }
public Mock<IState> NewState { get; set; }
public IEnumerable<string> ExpectedStates { get; set; }
Expand Down
39 changes: 39 additions & 0 deletions tests/Hangfire.Core.Tests/States/BackgroundJobStateChangerFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,45 @@ public void ChangeState_DoesNotInvokeApplyStateFilters_WhenFiltersDisabled()
_transaction.Verify(x => x.Commit());
}

[Fact]
public void ChangeState_WithTransaction_PassesTheGivenTransaction_AndDoesNotCommitTheImplicitOne()
{
_context.Transaction = new Mock<JobStorageTransaction>();
var stateChanger = CreateStateChanger();

stateChanger.ChangeState(_context.Object);

_stateMachine.Verify(x => x.ApplyState(It.Is<ApplyStateContext>(
ctx => ctx.Transaction == _context.Transaction.Object)));

_connection.Verify(x => x.CreateWriteTransaction(), Times.Never);
_transaction.Verify(x => x.Commit(), Times.Never);
}

[Fact]
public void ChangeState_WithTransaction_DoesNotCommitAndDoesNotDisposeTheExplicitTransaction()
{
_context.Transaction = new Mock<JobStorageTransaction>();
var stateChanger = CreateStateChanger();

stateChanger.ChangeState(_context.Object);

_context.Transaction.Verify(x => x.Commit(), Times.Never);
_context.Transaction.Verify(x => x.Dispose(), Times.Never);
}

[Fact]
public void ChangeState_WithTransaction_AcquiresATransactionLevelLockInstead()
{
_context.Transaction = new Mock<JobStorageTransaction>();
var stateChanger = CreateStateChanger();

stateChanger.ChangeState(_context.Object);

_context.Transaction.Verify(x => x.AcquireDistributedLock($"job:{JobId}:state-lock", It.IsAny<TimeSpan>()));
_connection.Verify(x => x.AcquireDistributedLock(It.IsAny<string>(), It.IsAny<TimeSpan>()), Times.Never);
}

private BackgroundJobStateChanger CreateStateChanger()
{
return new BackgroundJobStateChanger(_filterProvider.Object, _stateMachine.Object);
Expand Down
3 changes: 2 additions & 1 deletion tests/Hangfire.SqlServer.Tests/SqlServerJobQueueFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Data.Common;
using System.Linq;
using System.Threading;
using Hangfire.Annotations;
using ReferencedDapper::Dapper;
using Xunit;
// ReSharper disable ArgumentsStyleLiteral
Expand Down Expand Up @@ -675,7 +676,7 @@ private static SqlServerJobQueue CreateJobQueue(bool useMicrosoftDataSqlClient,
return new SqlServerJobQueue(storage, new SqlServerStorageOptions { SlidingInvisibilityTimeout = invisibilityTimeout });
}

private static void UseConnection(Action<DbConnection> action, bool useMicrosoftDataSqlClient)
private static void UseConnection([InstantHandle] Action<DbConnection> action, bool useMicrosoftDataSqlClient)
{
using (var connection = ConnectionUtils.CreateConnection(useMicrosoftDataSqlClient))
{
Expand Down

0 comments on commit f9f305b

Please sign in to comment.