Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Introduce default version setting to DurableTaskClient and expose to orchestrator ([#393](https://github.com/microsoft/durabletask-dotnet/pull/393))
- Add support for local credential types in DTS libraries ([#396](https://github.com/microsoft/durabletask-dotnet/pull/396))
- Add utility for easier version comparison in orchestration context ([#394](https://github.com/microsoft/durabletask-dotnet/pull/394))

## v1.8.1

Expand Down
46 changes: 46 additions & 0 deletions src/Abstractions/TaskOrchestrationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,52 @@ public virtual ILogger CreateReplaySafeLogger(Type type)
public virtual ILogger CreateReplaySafeLogger<T>()
=> new ReplaySafeLogger(this, this.LoggerFactory.CreateLogger<T>());

/// <summary>
/// Checks if the current orchestration version is greater than the specified version.
/// </summary>
/// <remarks>
/// <para>
/// If both versions are empty, this is considered false as neither can be greater.
/// </para>
/// <para>
/// An empty context version is less than a defined version in the parameter.
/// </para>
/// <para>
/// An empty parameter version is less than a defined version in the context.
/// </para>
/// </remarks>
/// <param name="version">The version to check against.</param>
/// <returns>True if the orchestration's version is greater than the provided version, false otherwise.</returns>
public virtual int CompareVersionTo(string version)
{
// Both versions are empty, treat as equal.
if (string.IsNullOrWhiteSpace(this.Version) && string.IsNullOrWhiteSpace(version))
{
return 0;
}

// An empty version in the context is always less than a defined version in the parameter.
if (string.IsNullOrWhiteSpace(this.Version))
{
return -1;
}

// An empty version in the parameter is always less than a defined version in the context.
if (string.IsNullOrWhiteSpace(version))
{
return 1;
}

// If both versions use the .NET Version class, return that comparison.
if (System.Version.TryParse(this.Version, out Version contextVersion) && System.Version.TryParse(version, out Version otherVersion))
{
return contextVersion.CompareTo(otherVersion);
}

// If we have gotten to here, we don't know the syntax of the versions we are comparing, use a string comparison as a final check.
return string.Compare(this.Version, version, StringComparison.OrdinalIgnoreCase);
}

class ReplaySafeLogger : ILogger
{
readonly TaskOrchestrationContext context;
Expand Down
106 changes: 106 additions & 0 deletions test/Abstractions.Tests/TaskOrchestrationContextVersionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.Extensions.Logging;

namespace Microsoft.DurableTask.Abstractions.Tests;
public class TaskOrchestrationContextVersionTests
{
[Theory]
[InlineData("1.1", "1.0", 1)]
[InlineData("1.0", "1.1", -1)]
[InlineData("1.0", "1.0", 0)]
[InlineData("", "1.0", -1)]
[InlineData("1.0", "", 1)]
[InlineData("", "", 0)]
[InlineData("1.0.1", "1.0.0", 1)]
[InlineData("1.0.0", "1.0.1", -1)]
[InlineData("alpha", "beta", -1)]
[InlineData("beta", "alpha", 1)]
[InlineData("alpha", "alpha", 0)]
public void OrchestrationContext_Version_ComparisonTests(string orchestrationVersion, string otherVersion, int comparisonResult)
{
TaskOrchestrationContext orchestrationContext = new TestTaskOrchestrationContext(orchestrationVersion);

if (comparisonResult > 0)
{
orchestrationContext.CompareVersionTo(otherVersion).Should().BeGreaterThan(0);
}
else if (comparisonResult < 0)
{
orchestrationContext.CompareVersionTo(otherVersion).Should().BeLessThan(0);
}
else
{
orchestrationContext.CompareVersionTo(otherVersion).Should().Be(0);
}
}

class TestTaskOrchestrationContext : TaskOrchestrationContext
{
internal readonly string version = string.Empty;

public TestTaskOrchestrationContext(string version)
{
this.version = version;
}
public override TaskName Name => throw new NotImplementedException();

public override string InstanceId => throw new NotImplementedException();

public override ParentOrchestrationInstance? Parent => throw new NotImplementedException();

public override DateTime CurrentUtcDateTime => throw new NotImplementedException();

public override bool IsReplaying => throw new NotImplementedException();

public override string Version => this.version;

protected override ILoggerFactory LoggerFactory => throw new NotImplementedException();

public override Task<TResult> CallActivityAsync<TResult>(TaskName name, object? input = null, TaskOptions? options = null)
{
throw new NotImplementedException();
}

public override Task<TResult> CallSubOrchestratorAsync<TResult>(TaskName orchestratorName, object? input = null, TaskOptions? options = null)
{
throw new NotImplementedException();
}

public override void ContinueAsNew(object? newInput = null, bool preserveUnprocessedEvents = true)
{
throw new NotImplementedException();
}

public override Task CreateTimer(DateTime fireAt, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}

public override T? GetInput<T>() where T : default
{
throw new NotImplementedException();
}

public override Guid NewGuid()
{
throw new NotImplementedException();
}

public override void SendEvent(string instanceId, string eventName, object payload)
{
throw new NotImplementedException();
}

public override void SetCustomStatus(object? customStatus)
{
throw new NotImplementedException();
}

public override Task<T> WaitForExternalEvent<T>(string eventName, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
}
}
Loading