From 94d06dd785919177e374ea3ddfc6515787c05b9a Mon Sep 17 00:00:00 2001
From: Piotr Osadkowski
Date: Sat, 4 Jan 2025 23:51:36 +0100
Subject: [PATCH 1/4] Added support for null in GetSessionStateAsync
SetSessionStateAsync
Added Tests
---
.../src/ServiceBusSessionMessageActions.cs | 16 +++--
.../ServiceBusSessionMessageActionsTests.cs | 59 +++++++++++++++++++
2 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActions.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActions.cs
index 6f435a536..69ba2320e 100644
--- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActions.cs
+++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActions.cs
@@ -43,7 +43,7 @@ protected ServiceBusSessionMessageActions()
public virtual DateTimeOffset SessionLockedUntil { get; protected set; }
///
- public virtual async Task GetSessionStateAsync(
+ public virtual async Task GetSessionStateAsync(
CancellationToken cancellationToken = default)
{
var request = new GetSessionStateRequest()
@@ -52,19 +52,25 @@ public virtual async Task GetSessionStateAsync(
};
GetSessionStateResponse result = await _settlement.GetSessionStateAsync(request, cancellationToken: cancellationToken);
- BinaryData binaryData = new BinaryData(result.SessionState.Memory);
- return binaryData;
+
+ if (result.SessionState is null || result.SessionState.IsEmpty)
+ {
+ return null;
+ }
+
+ return new BinaryData(result.SessionState.Memory);
}
///
public virtual async Task SetSessionStateAsync(
- BinaryData sessionState,
+ BinaryData? sessionState,
CancellationToken cancellationToken = default)
+
{
var request = new SetSessionStateRequest()
{
SessionId = _sessionId,
- SessionState = ByteString.CopyFrom(sessionState.ToMemory().Span),
+ SessionState = sessionState is null ? ByteString.Empty : ByteString.CopyFrom(sessionState.ToMemory().Span),
};
await _settlement.SetSessionStateAsync(request, cancellationToken: cancellationToken);
diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
index d9a508568..7806872f4 100644
--- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
+++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
@@ -49,6 +49,24 @@ public async Task CanRenewSessionLock()
await messageActions.RenewSessionLockAsync();
}
+ [Fact]
+ public async Task CanSetAndGetSessionStateWithNull()
+ {
+
+ string testString = "TestString";
+ var client = new SessionMockSettlementClient("test", ByteString.CopyFromUtf8(testString));
+ var message = ServiceBusModelFactory.ServiceBusReceivedMessage(lockTokenGuid: Guid.NewGuid(), sessionId: "test");
+ var messageActions = new ServiceBusSessionMessageActions(client, message.SessionId, message.LockedUntil);
+
+ var afterSetState = await messageActions.GetSessionStateAsync();
+ Assert.Equal(testString, afterSetState.ToString());
+
+ await messageActions.SetSessionStateAsync(null);
+ var afterSetNullState = await messageActions.GetSessionStateAsync();
+ Assert.Null(afterSetNullState);
+
+ }
+
private class MockSettlementClient : Settlement.SettlementClient
{
private readonly string _sessionId;
@@ -86,5 +104,46 @@ public override AsyncUnaryCall RenewSessionLockAsync(R
return new AsyncUnaryCall(Task.FromResult(response), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
}
}
+
+
+
+
+ private class SessionMockSettlementClient : Settlement.SettlementClient
+ {
+ private readonly string _sessionId;
+ private ByteString _sessionState;
+ public SessionMockSettlementClient(string sessionId, ByteString sessionState = null) : base()
+ {
+ _sessionId = sessionId;
+ _sessionState = sessionState ?? ByteString.Empty;
+ }
+
+ public override AsyncUnaryCall GetSessionStateAsync(GetSessionStateRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
+ {
+ Assert.Equal(_sessionId, request.SessionId);
+ return new AsyncUnaryCall(Task.FromResult(new GetSessionStateResponse { SessionState = _sessionState }), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+ }
+
+ public override AsyncUnaryCall SetSessionStateAsync(SetSessionStateRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
+ {
+ Assert.Equal(_sessionId, request.SessionId);
+ _sessionState = request.SessionState;
+ return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+ }
+
+ public override AsyncUnaryCall ReleaseSessionAsync(ReleaseSessionRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
+ {
+ Assert.Equal(_sessionId, request.SessionId);
+ return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+ }
+
+ public override AsyncUnaryCall RenewSessionLockAsync(RenewSessionLockRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
+ {
+ Assert.Equal(_sessionId, request.SessionId);
+ var response = new RenewSessionLockResponse();
+ response.LockedUntil = Timestamp.FromDateTime(DateTime.UtcNow.AddSeconds(30));
+ return new AsyncUnaryCall(Task.FromResult(response), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
+ }
+ }
}
}
From 1e4b979b21f59932d90ade854f745e2027cac2bf Mon Sep 17 00:00:00 2001
From: Piotr Osadkowski
Date: Mon, 6 Jan 2025 13:12:02 +0100
Subject: [PATCH 2/4] updated release notes
---
extensions/Worker.Extensions.ServiceBus/release_notes.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/extensions/Worker.Extensions.ServiceBus/release_notes.md b/extensions/Worker.Extensions.ServiceBus/release_notes.md
index 5b169b47d..cb8eeeab3 100644
--- a/extensions/Worker.Extensions.ServiceBus/release_notes.md
+++ b/extensions/Worker.Extensions.ServiceBus/release_notes.md
@@ -7,4 +7,5 @@
### Microsoft.Azure.Functions.Worker.Extensions.ServiceBus 5.22.0
- Updated `Azure.Identity` reference to 1.12.0
-- Updated `Microsoft.Extensions.Azure` to 1.7.5
\ No newline at end of file
+- Updated `Microsoft.Extensions.Azure` to 1.7.5
+- Added 'null' support in SetSessionState and GetSessionState methods (#2548)
\ No newline at end of file
From f1a5e61679785ca55a7dee484a029ddc69f3c7d9 Mon Sep 17 00:00:00 2001
From: Piotr Osadkowski
Date: Thu, 9 Jan 2025 15:44:54 +0100
Subject: [PATCH 3/4] Changed to Moq from manual mock Formatting
---
.../ServiceBusSessionMessageActionsTests.cs | 91 +++++++++----------
1 file changed, 41 insertions(+), 50 deletions(-)
diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
index 7806872f4..59a6fa751 100644
--- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
+++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
@@ -10,6 +10,7 @@
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Microsoft.Azure.ServiceBus.Grpc;
+using Moq;
using Xunit;
namespace Microsoft.Azure.Functions.Worker.Extensions.Tests
@@ -52,19 +53,50 @@ public async Task CanRenewSessionLock()
[Fact]
public async Task CanSetAndGetSessionStateWithNull()
{
-
- string testString = "TestString";
- var client = new SessionMockSettlementClient("test", ByteString.CopyFromUtf8(testString));
- var message = ServiceBusModelFactory.ServiceBusReceivedMessage(lockTokenGuid: Guid.NewGuid(), sessionId: "test");
- var messageActions = new ServiceBusSessionMessageActions(client, message.SessionId, message.LockedUntil);
-
- var afterSetState = await messageActions.GetSessionStateAsync();
- Assert.Equal(testString, afterSetState.ToString());
+ var sessionId = "test";
+ var initialTestString = "TestInitialState";
+ ByteString currentSessionState = ByteString.CopyFromUtf8(initialTestString);
+
+ var mockClient = new Mock();
+
+ mockClient
+ .Setup(x => x.GetSessionStateAsync(
+ It.Is(r => r.SessionId == sessionId),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny())
+ )
+ .Returns(() => CreateAsyncUnaryCall(new GetSessionStateResponse
+ {
+ SessionState = currentSessionState
+ }));
+
+ mockClient
+ .Setup(x => x.SetSessionStateAsync(
+ It.Is(r => r.SessionId == sessionId),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny())
+ )
+ .Returns((request, _, _, _) =>
+ {
+ currentSessionState = request.SessionState;
+ return CreateAsyncUnaryCall(new Empty());
+ });
+
+ var message = ServiceBusModelFactory.ServiceBusReceivedMessage(lockTokenGuid: Guid.NewGuid(), sessionId: sessionId);
+ var messageActions = new ServiceBusSessionMessageActions(settlement: mockClient.Object,sessionId: message.SessionId,sessionLockedUntil: message.LockedUntil);
+
+ var initialState = await messageActions.GetSessionStateAsync();
+ Assert.Equal(initialTestString, initialState.ToString());
await messageActions.SetSessionStateAsync(null);
var afterSetNullState = await messageActions.GetSessionStateAsync();
Assert.Null(afterSetNullState);
-
+ }
+ private static AsyncUnaryCall CreateAsyncUnaryCall(T response) where T : class
+ {
+ return new AsyncUnaryCall(Task.FromResult(response),Task.FromResult(new Metadata()),() => Status.DefaultSuccess,() => new Metadata(),() => { });
}
private class MockSettlementClient : Settlement.SettlementClient
@@ -104,46 +136,5 @@ public override AsyncUnaryCall RenewSessionLockAsync(R
return new AsyncUnaryCall(Task.FromResult(response), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
}
}
-
-
-
-
- private class SessionMockSettlementClient : Settlement.SettlementClient
- {
- private readonly string _sessionId;
- private ByteString _sessionState;
- public SessionMockSettlementClient(string sessionId, ByteString sessionState = null) : base()
- {
- _sessionId = sessionId;
- _sessionState = sessionState ?? ByteString.Empty;
- }
-
- public override AsyncUnaryCall GetSessionStateAsync(GetSessionStateRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
- {
- Assert.Equal(_sessionId, request.SessionId);
- return new AsyncUnaryCall(Task.FromResult(new GetSessionStateResponse { SessionState = _sessionState }), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
- }
-
- public override AsyncUnaryCall SetSessionStateAsync(SetSessionStateRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
- {
- Assert.Equal(_sessionId, request.SessionId);
- _sessionState = request.SessionState;
- return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
- }
-
- public override AsyncUnaryCall ReleaseSessionAsync(ReleaseSessionRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
- {
- Assert.Equal(_sessionId, request.SessionId);
- return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
- }
-
- public override AsyncUnaryCall RenewSessionLockAsync(RenewSessionLockRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default)
- {
- Assert.Equal(_sessionId, request.SessionId);
- var response = new RenewSessionLockResponse();
- response.LockedUntil = Timestamp.FromDateTime(DateTime.UtcNow.AddSeconds(30));
- return new AsyncUnaryCall(Task.FromResult(response), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { });
- }
- }
}
}
From 87132dfc87cd0b718758712d91ee55ecf7d279c9 Mon Sep 17 00:00:00 2001
From: Piotr Osadkowski
Date: Thu, 9 Jan 2025 23:16:13 +0100
Subject: [PATCH 4/4] Redesigned tests
---
.../ServiceBusSessionMessageActionsTests.cs | 59 ++++++++-----------
1 file changed, 24 insertions(+), 35 deletions(-)
diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
index 59a6fa751..7831001d4 100644
--- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
+++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs
@@ -50,53 +50,42 @@ public async Task CanRenewSessionLock()
await messageActions.RenewSessionLockAsync();
}
+
[Fact]
- public async Task CanSetAndGetSessionStateWithNull()
+ public async Task CanSetNullSessionState()
{
- var sessionId = "test";
- var initialTestString = "TestInitialState";
- ByteString currentSessionState = ByteString.CopyFromUtf8(initialTestString);
+ var mockClient = new Mock();
+ var message = ServiceBusModelFactory.ServiceBusReceivedMessage(lockTokenGuid: Guid.NewGuid(), sessionId: "test");
+ var messageActions = new ServiceBusSessionMessageActions(mockClient.Object, message.SessionId, message.LockedUntil);
+
+ await messageActions.SetSessionStateAsync(null);
+ mockClient.Verify(x => x.SetSessionStateAsync(
+ It.Is(r => r.SessionId == message.SessionId && r.SessionState == ByteString.Empty),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny()),
+ Times.Once);
+ }
+ [Fact]
+ public async Task CanGetNullSessionState()
+ {
var mockClient = new Mock();
-
- mockClient
- .Setup(x => x.GetSessionStateAsync(
- It.Is(r => r.SessionId == sessionId),
- It.IsAny(),
- It.IsAny(),
- It.IsAny())
- )
- .Returns(() => CreateAsyncUnaryCall(new GetSessionStateResponse
- {
- SessionState = currentSessionState
- }));
mockClient
- .Setup(x => x.SetSessionStateAsync(
- It.Is(r => r.SessionId == sessionId),
+ .Setup(x => x.GetSessionStateAsync(
+ It.IsAny(),
It.IsAny(),
It.IsAny(),
It.IsAny())
)
- .Returns((request, _, _, _) =>
- {
- currentSessionState = request.SessionState;
- return CreateAsyncUnaryCall(new Empty());
- });
+ .Returns(new AsyncUnaryCall(Task.FromResult(new GetSessionStateResponse() { SessionState = ByteString.Empty }), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }));
- var message = ServiceBusModelFactory.ServiceBusReceivedMessage(lockTokenGuid: Guid.NewGuid(), sessionId: sessionId);
- var messageActions = new ServiceBusSessionMessageActions(settlement: mockClient.Object,sessionId: message.SessionId,sessionLockedUntil: message.LockedUntil);
-
- var initialState = await messageActions.GetSessionStateAsync();
- Assert.Equal(initialTestString, initialState.ToString());
+ var message = ServiceBusModelFactory.ServiceBusReceivedMessage(lockTokenGuid: Guid.NewGuid(), sessionId: "test");
+ var messageActions = new ServiceBusSessionMessageActions(settlement: mockClient.Object, sessionId: message.SessionId, sessionLockedUntil: message.LockedUntil);
- await messageActions.SetSessionStateAsync(null);
- var afterSetNullState = await messageActions.GetSessionStateAsync();
- Assert.Null(afterSetNullState);
- }
- private static AsyncUnaryCall CreateAsyncUnaryCall(T response) where T : class
- {
- return new AsyncUnaryCall(Task.FromResult(response),Task.FromResult(new Metadata()),() => Status.DefaultSuccess,() => new Metadata(),() => { });
+ var nullState = await messageActions.GetSessionStateAsync();
+ Assert.Null(nullState);
}
private class MockSettlementClient : Settlement.SettlementClient