From b092c7ee22d433df09fff63fc1f3bbfbc6c5abc7 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Thu, 5 Dec 2024 16:38:08 -0800 Subject: [PATCH 01/17] initial changes --- ...erviceBusSessionMessageActionsConverter.cs | 21 ++- test/DotNetWorkerTests/TestFunctionContext.cs | 6 + .../ServiceBus/MockSettlementClient.cs | 63 ++++++++ .../ServiceBusMessageActionsTests.cs | 52 +----- ...> ServiceBusSessionMessageActionsTests.cs} | 2 +- .../ServiceBusSessionMessageConverterTests.cs | 151 ++++++++++++++++++ 6 files changed, 240 insertions(+), 55 deletions(-) create mode 100644 test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs rename test/Worker.Extensions.Tests/ServiceBus/{ServiceBusSessionMessageActions.cs => ServiceBusSessionMessageActionsTests.cs} (99%) create mode 100644 test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index 1a37c3c47..b5f0d80b5 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -7,6 +7,11 @@ using Microsoft.Azure.Functions.Worker.Extensions.Abstractions; using Microsoft.Azure.ServiceBus.Grpc; using System.Text.Json; +using Microsoft.Azure.Functions.Worker.Core; +using Microsoft.Azure.Functions.Worker.Extensions.ServiceBus; +using Microsoft.Azure.Functions.Worker.Extensions; +using System.Text; +using Google.Protobuf.Collections; namespace Microsoft.Azure.Functions.Worker { @@ -15,7 +20,6 @@ namespace Microsoft.Azure.Functions.Worker /// [SupportsDeferredBinding] [SupportedTargetType(typeof(ServiceBusSessionMessageActions))] - [SupportedTargetType(typeof(ServiceBusSessionMessageActions[]))] internal class ServiceBusSessionMessageActionsConverter : IInputConverter { private readonly Settlement.SettlementClient _settlement; @@ -30,7 +34,8 @@ public ValueTask ConvertAsync(ConverterContext context) try { var foundSessionId = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionId", out object? sessionId); - if (!foundSessionId) + var foundSessionIdArray = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionIdArray", out object? sessionIdArray); + if (!foundSessionId && !foundSessionIdArray) { throw new InvalidOperationException($"Expecting SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } @@ -49,7 +54,17 @@ public ValueTask ConvertAsync(ConverterContext context) throw new InvalidOperationException("Expecting SessionLockedUntil within binding data of session actions and value was not present."); } - var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, sessionId!.ToString(), sessionLockedUntil.GetDateTimeOffset()); + // Logic for if isBatched is true, then sessionIdArray will be used to get the sessionId. + var sessionIdRepeatedFieldArray = sessionIdArray as RepeatedField; + + if (foundSessionIdArray && (sessionIdRepeatedFieldArray == null || sessionIdRepeatedFieldArray.Count != 1)) + { + throw new InvalidOperationException($"Expecting batched SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); + } + + // If sessionIdRepeatedFieldArray has a value, it will only have one value within the array. + var parsedSessionId = foundSessionId ? sessionId!.ToString() : (sessionIdRepeatedFieldArray![0].ToString()); + var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, parsedSessionId, sessionLockedUntil.GetDateTimeOffset()); var result = ConversionResult.Success(sessionActionResult); return new ValueTask(result); } diff --git a/test/DotNetWorkerTests/TestFunctionContext.cs b/test/DotNetWorkerTests/TestFunctionContext.cs index 731885dca..50eec1357 100644 --- a/test/DotNetWorkerTests/TestFunctionContext.cs +++ b/test/DotNetWorkerTests/TestFunctionContext.cs @@ -58,6 +58,12 @@ public TestFunctionContext(FunctionDefinition functionDefinition, FunctionInvoca { } + public TestFunctionContext(BindingContext context) + : this(new TestFunctionDefinition(), new TestFunctionInvocation(), CancellationToken.None) + { + BindingContext = context; + } + public TestFunctionContext(FunctionDefinition functionDefinition, FunctionInvocation invocation, CancellationToken cancellationToken, IInvocationFeatures features = null, IServiceProvider serviceProvider = null) { FunctionDefinition = functionDefinition; diff --git a/test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs b/test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs new file mode 100644 index 000000000..a57f673f1 --- /dev/null +++ b/test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Google.Protobuf.WellKnownTypes; +using Google.Protobuf; +using Grpc.Core; +using Microsoft.Azure.ServiceBus.Grpc; +using Xunit; + +namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBus +{ + internal class MockSettlementClient : Settlement.SettlementClient + { + private readonly string _lockToken; + private readonly ByteString _propertiesToModify; + public MockSettlementClient(string lockToken, IDictionary propertiesToModify = default) : base() + { + _lockToken = lockToken; + if (propertiesToModify != null) + { + _propertiesToModify = ServiceBusMessageActions.ConvertToByteString(propertiesToModify); + } + } + + public override AsyncUnaryCall CompleteAsync(CompleteRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall AbandonAsync(AbandonRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + Assert.Equal(_propertiesToModify, request.PropertiesToModify); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall DeadletterAsync(DeadletterRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + Assert.Equal(_propertiesToModify, request.PropertiesToModify); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall DeferAsync(DeferRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + Assert.Equal(_propertiesToModify, request.PropertiesToModify); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall RenewMessageLockAsync(RenewMessageLockRequest request, CallOptions options) + { + Assert.Equal(_lockToken, request.Locktoken); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + } +} diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs index 0edf5612e..d7fbfe197 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs @@ -9,6 +9,7 @@ using Google.Protobuf; using Google.Protobuf.WellKnownTypes; using Grpc.Core; +using Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBus; using Microsoft.Azure.ServiceBus.Grpc; using Xunit; @@ -102,56 +103,5 @@ public async Task PassingNullMessageThrows() await Assert.ThrowsAsync(async () => await messageActions.DeferMessageAsync(null)); await Assert.ThrowsAsync(async () => await messageActions.RenewMessageLockAsync(null)); } - - private class MockSettlementClient : Settlement.SettlementClient - { - private readonly string _lockToken; - private readonly ByteString _propertiesToModify; - public MockSettlementClient(string lockToken, IDictionary propertiesToModify = default) : base() - { - _lockToken = lockToken; - if (propertiesToModify != null) - { - _propertiesToModify = ServiceBusMessageActions.ConvertToByteString(propertiesToModify); - } - } - - public override AsyncUnaryCall CompleteAsync(CompleteRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall AbandonAsync(AbandonRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - Assert.Equal(_propertiesToModify, request.PropertiesToModify); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall DeadletterAsync(DeadletterRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - Assert.Equal(_propertiesToModify, request.PropertiesToModify); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall DeferAsync(DeferRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - Assert.Equal(_propertiesToModify, request.PropertiesToModify); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall RenewMessageLockAsync(RenewMessageLockRequest request, CallOptions options) - { - Assert.Equal(_lockToken, request.Locktoken); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - } } } diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActions.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs similarity index 99% rename from test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActions.cs rename to test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs index d9a508568..115f11ed0 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActions.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs @@ -53,7 +53,7 @@ private class MockSettlementClient : Settlement.SettlementClient { private readonly string _sessionId; private readonly ByteString _sessionState; - public MockSettlementClient(string sessionId, ByteString sessionState = null) : base() + public MockSettlementClient(string sessionId, ByteString? sessionState = null) : base() { _sessionId = sessionId; _sessionState = sessionState; diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs new file mode 100644 index 000000000..d2107b410 --- /dev/null +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs @@ -0,0 +1,151 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Messaging.ServiceBus; +using Google.Protobuf; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Converters; +using Microsoft.Azure.Functions.Worker.Extensions.ServiceBus; +using Microsoft.Azure.Functions.Worker.Grpc.Messages; +using Microsoft.Azure.Functions.Worker.Tests; +using Microsoft.Azure.Functions.Worker.Tests.Converters; +using Microsoft.Azure.Functions.Worker.Tests.Features; +using Moq; +using Xunit; +using Google.Protobuf.Collections; +using Microsoft.Azure.ServiceBus.Grpc; +using Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBus; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; + +namespace Microsoft.Azure.Functions.Worker.Extensions.Tests +{ + public class ServiceBusSessionMessageConverterTests + { + internal sealed class TestBindingContext : BindingContext + { + public TestBindingContext(IReadOnlyDictionary input) + { + BindingData = input; + } + + public override IReadOnlyDictionary BindingData { get; } + } + + [Fact] + public async Task ConvertAsync_ReturnsSuccess() + { + var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; + + var jsonObject = new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }; + var bindingDataDictionary = new Dictionary + { + { "SessionId", "test" }, + { "SessionActions", JsonSerializer.Serialize(new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }) + } + }; + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); + var result = await converter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Succeeded, result.Status); + var output = result.Value as ServiceBusSessionMessageActions; + Assert.NotNull(output); + } + + [Fact] + public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsSuccess() + { + var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; + + var jsonObject = new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }; + RepeatedField repeatedField = new RepeatedField(); + repeatedField.Add("test"); + + var bindingDataDictionary = new Dictionary + { + { "SessionIdArray", repeatedField }, + { "SessionActions", JsonSerializer.Serialize(new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }) + } + }; + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); + var result = await converter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Succeeded, result.Status); + var output = result.Value as ServiceBusSessionMessageActions; + Assert.NotNull(output); + } + + [Fact] + public async Task ConvertAsync_ReturnsFailure_NoSessionId() + { + var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; + + var jsonObject = new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }; + var bindingDataDictionary = new Dictionary + { + { "SessionActions", JsonSerializer.Serialize(new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }) + } + }; + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); + var result = await converter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Failed, result.Status); + } + + + [Fact] + public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsFailed_MultipleMessages() + { + var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; + + var jsonObject = new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }; + RepeatedField repeatedField = new RepeatedField(); + repeatedField.Add("test"); + repeatedField.Add("hi"); + + var bindingDataDictionary = new Dictionary + { + { "SessionIdArray", repeatedField }, + { "SessionActions", JsonSerializer.Serialize(new + { + SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" + }) + } + }; + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); + var result = await converter.ConvertAsync(context); + + Assert.Equal(ConversionStatus.Failed, result.Status); + } + } +} From 3d88a79fb65ac3c9934a2981fa29d9d5441a8c81 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Thu, 5 Dec 2024 16:46:05 -0800 Subject: [PATCH 02/17] removing extra method --- .../ServiceBusSessionMessageActionsTests.cs | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs index 115f11ed0..d58f51ba5 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs @@ -48,43 +48,5 @@ public async Task CanRenewSessionLock() var messageActions = new ServiceBusSessionMessageActions(new MockSettlementClient(message.SessionId), message.SessionId, message.LockedUntil); await messageActions.RenewSessionLockAsync(); } - - private class MockSettlementClient : Settlement.SettlementClient - { - private readonly string _sessionId; - private readonly ByteString _sessionState; - public MockSettlementClient(string sessionId, ByteString? sessionState = null) : base() - { - _sessionId = sessionId; - _sessionState = sessionState; - } - - 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()), 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); - Assert.Equal(_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 5a996e55b0ed87890f060c1ee90221299856c0d1 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Fri, 6 Dec 2024 10:58:43 -0800 Subject: [PATCH 03/17] remove unneccessary using statement --- .../ServiceBus/ServiceBusSessionMessageConverterTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs index d2107b410..476ff4141 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs @@ -15,7 +15,6 @@ using Microsoft.Azure.Functions.Worker.Grpc.Messages; using Microsoft.Azure.Functions.Worker.Tests; using Microsoft.Azure.Functions.Worker.Tests.Converters; -using Microsoft.Azure.Functions.Worker.Tests.Features; using Moq; using Xunit; using Google.Protobuf.Collections; From b31ae90e79bd4a6e6ba0d2d2341242b9eefe39ea Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Fri, 6 Dec 2024 11:40:32 -0800 Subject: [PATCH 04/17] trying to fix reference to testFunctionContext --- .../ServiceBus/ServiceBusSessionMessageConverterTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs index 476ff4141..8925aaecc 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs @@ -54,7 +54,7 @@ public async Task ConvertAsync_ReturnsSuccess() }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); @@ -84,7 +84,7 @@ public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsSuccess() }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); @@ -110,7 +110,7 @@ public async Task ConvertAsync_ReturnsFailure_NoSessionId() }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); @@ -140,7 +140,7 @@ public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsFailed_MultipleMe }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); From 5f6c5e200da80d9b3ae8583b7a8a33f556266ea9 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Fri, 6 Dec 2024 12:11:34 -0800 Subject: [PATCH 05/17] changing type to public --- test/DotNetWorkerTests/TestFunctionContext.cs | 2 +- .../ServiceBus/ServiceBusSessionMessageConverterTests.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/DotNetWorkerTests/TestFunctionContext.cs b/test/DotNetWorkerTests/TestFunctionContext.cs index 50eec1357..446c5fab5 100644 --- a/test/DotNetWorkerTests/TestFunctionContext.cs +++ b/test/DotNetWorkerTests/TestFunctionContext.cs @@ -14,7 +14,7 @@ namespace Microsoft.Azure.Functions.Worker.Tests { - internal class TestAsyncFunctionContext : TestFunctionContext, IAsyncDisposable + public class TestAsyncFunctionContext : TestFunctionContext, IAsyncDisposable { public TestAsyncFunctionContext() : base(new TestFunctionDefinition(), new TestFunctionInvocation(), CancellationToken.None) diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs index 8925aaecc..476ff4141 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs @@ -54,7 +54,7 @@ public async Task ConvertAsync_ReturnsSuccess() }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); @@ -84,7 +84,7 @@ public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsSuccess() }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); @@ -110,7 +110,7 @@ public async Task ConvertAsync_ReturnsFailure_NoSessionId() }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); @@ -140,7 +140,7 @@ public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsFailed_MultipleMe }) } }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new Microsoft.Azure.Functions.Worker.Tests.TestFunctionContext(new TestBindingContext(bindingDataDictionary))); + var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); var result = await converter.ConvertAsync(context); From 42c4c2e11b643ca7767fef1384e6f2e5ee1f5ffe Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Mon, 9 Dec 2024 10:29:27 -0800 Subject: [PATCH 06/17] changing order of using statements and removing dependency on protobuf --- .../src/ServiceBusSessionMessageActionsConverter.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index b5f0d80b5..e2c7f4240 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -2,16 +2,12 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System; +using System.Collections.Generic; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker.Converters; using Microsoft.Azure.Functions.Worker.Extensions.Abstractions; using Microsoft.Azure.ServiceBus.Grpc; -using System.Text.Json; -using Microsoft.Azure.Functions.Worker.Core; -using Microsoft.Azure.Functions.Worker.Extensions.ServiceBus; -using Microsoft.Azure.Functions.Worker.Extensions; -using System.Text; -using Google.Protobuf.Collections; namespace Microsoft.Azure.Functions.Worker { @@ -55,9 +51,9 @@ public ValueTask ConvertAsync(ConverterContext context) } // Logic for if isBatched is true, then sessionIdArray will be used to get the sessionId. - var sessionIdRepeatedFieldArray = sessionIdArray as RepeatedField; + var sessionIdRepeatedFieldArray = sessionIdArray as IList; - if (foundSessionIdArray && (sessionIdRepeatedFieldArray == null || sessionIdRepeatedFieldArray.Count != 1)) + if (foundSessionIdArray && (sessionIdRepeatedFieldArray is null || sessionIdRepeatedFieldArray.Count == 0)) { throw new InvalidOperationException($"Expecting batched SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } From deae0086966b289dcb72eb464d658c9c15e89ecc Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Mon, 9 Dec 2024 14:33:18 -0800 Subject: [PATCH 07/17] seeing if tests pass --- .../ServiceBus/MockSettlementClient.cs | 63 ------------------- .../ServiceBusMessageActionsTests.cs | 52 ++++++++++++++- .../ServiceBusSessionMessageActionsTests.cs | 38 +++++++++++ .../ServiceBusSessionMessageConverterTests.cs | 28 ++++++++- 4 files changed, 116 insertions(+), 65 deletions(-) delete mode 100644 test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs diff --git a/test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs b/test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs deleted file mode 100644 index a57f673f1..000000000 --- a/test/Worker.Extensions.Tests/ServiceBus/MockSettlementClient.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Google.Protobuf.WellKnownTypes; -using Google.Protobuf; -using Grpc.Core; -using Microsoft.Azure.ServiceBus.Grpc; -using Xunit; - -namespace Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBus -{ - internal class MockSettlementClient : Settlement.SettlementClient - { - private readonly string _lockToken; - private readonly ByteString _propertiesToModify; - public MockSettlementClient(string lockToken, IDictionary propertiesToModify = default) : base() - { - _lockToken = lockToken; - if (propertiesToModify != null) - { - _propertiesToModify = ServiceBusMessageActions.ConvertToByteString(propertiesToModify); - } - } - - public override AsyncUnaryCall CompleteAsync(CompleteRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall AbandonAsync(AbandonRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - Assert.Equal(_propertiesToModify, request.PropertiesToModify); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall DeadletterAsync(DeadletterRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - Assert.Equal(_propertiesToModify, request.PropertiesToModify); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall DeferAsync(DeferRequest request, Metadata headers = null, DateTime? deadline = null, - CancellationToken cancellationToken = default(CancellationToken)) - { - Assert.Equal(_lockToken, request.Locktoken); - Assert.Equal(_propertiesToModify, request.PropertiesToModify); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - - public override AsyncUnaryCall RenewMessageLockAsync(RenewMessageLockRequest request, CallOptions options) - { - Assert.Equal(_lockToken, request.Locktoken); - return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); - } - } -} diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs index d7fbfe197..49ffdc131 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusMessageActionsTests.cs @@ -9,7 +9,6 @@ using Google.Protobuf; using Google.Protobuf.WellKnownTypes; using Grpc.Core; -using Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBus; using Microsoft.Azure.ServiceBus.Grpc; using Xunit; @@ -103,5 +102,56 @@ public async Task PassingNullMessageThrows() await Assert.ThrowsAsync(async () => await messageActions.DeferMessageAsync(null)); await Assert.ThrowsAsync(async () => await messageActions.RenewMessageLockAsync(null)); } + + internal class MockSettlementClient : Settlement.SettlementClient + { + private readonly string _lockToken; + private readonly ByteString _propertiesToModify; + public MockSettlementClient(string lockToken, IDictionary propertiesToModify = default) : base() + { + _lockToken = lockToken; + if (propertiesToModify != null) + { + _propertiesToModify = ServiceBusMessageActions.ConvertToByteString(propertiesToModify); + } + } + + public override AsyncUnaryCall CompleteAsync(CompleteRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall AbandonAsync(AbandonRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + Assert.Equal(_propertiesToModify, request.PropertiesToModify); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall DeadletterAsync(DeadletterRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + Assert.Equal(_propertiesToModify, request.PropertiesToModify); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall DeferAsync(DeferRequest request, Metadata headers = null, DateTime? deadline = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + Assert.Equal(_lockToken, request.Locktoken); + Assert.Equal(_propertiesToModify, request.PropertiesToModify); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + + public override AsyncUnaryCall RenewMessageLockAsync(RenewMessageLockRequest request, CallOptions options) + { + Assert.Equal(_lockToken, request.Locktoken); + return new AsyncUnaryCall(Task.FromResult(new Empty()), Task.FromResult(new Metadata()), () => Status.DefaultSuccess, () => new Metadata(), () => { }); + } + } } } diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs index d58f51ba5..d9a508568 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageActionsTests.cs @@ -48,5 +48,43 @@ public async Task CanRenewSessionLock() var messageActions = new ServiceBusSessionMessageActions(new MockSettlementClient(message.SessionId), message.SessionId, message.LockedUntil); await messageActions.RenewSessionLockAsync(); } + + private class MockSettlementClient : Settlement.SettlementClient + { + private readonly string _sessionId; + private readonly ByteString _sessionState; + public MockSettlementClient(string sessionId, ByteString sessionState = null) : base() + { + _sessionId = sessionId; + _sessionState = sessionState; + } + + 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()), 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); + Assert.Equal(_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(), () => { }); + } + } } } diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs index 476ff4141..1fe014d2e 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs @@ -19,7 +19,7 @@ using Xunit; using Google.Protobuf.Collections; using Microsoft.Azure.ServiceBus.Grpc; -using Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBus; +using static Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBusMessageActionsTests; using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; namespace Microsoft.Azure.Functions.Worker.Extensions.Tests @@ -36,6 +36,32 @@ public TestBindingContext(IReadOnlyDictionary input) public override IReadOnlyDictionary BindingData { get; } } + internal sealed class TestFunctionContext : FunctionContext + { + public TestFunctionContext(BindingContext bindingContext) + { + BindingContext = bindingContext; + } + + public override BindingContext BindingContext { get; } + + public override string InvocationId => throw new NotImplementedException(); + + public override string FunctionId => throw new NotImplementedException(); + + public override TraceContext TraceContext => throw new NotImplementedException(); + + public override RetryContext RetryContext => throw new NotImplementedException(); + + public override IServiceProvider InstanceServices { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public override FunctionDefinition FunctionDefinition => throw new NotImplementedException(); + + public override IDictionary Items { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public override IInvocationFeatures Features => throw new NotImplementedException(); + } + [Fact] public async Task ConvertAsync_ReturnsSuccess() { From 20ae75e9fe06b9f77b830b9aa30f12f6f55eba7a Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Mon, 9 Dec 2024 14:42:08 -0800 Subject: [PATCH 08/17] reverting testFUnctionContext back to normal --- test/DotNetWorkerTests/TestFunctionContext.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/DotNetWorkerTests/TestFunctionContext.cs b/test/DotNetWorkerTests/TestFunctionContext.cs index 446c5fab5..731885dca 100644 --- a/test/DotNetWorkerTests/TestFunctionContext.cs +++ b/test/DotNetWorkerTests/TestFunctionContext.cs @@ -14,7 +14,7 @@ namespace Microsoft.Azure.Functions.Worker.Tests { - public class TestAsyncFunctionContext : TestFunctionContext, IAsyncDisposable + internal class TestAsyncFunctionContext : TestFunctionContext, IAsyncDisposable { public TestAsyncFunctionContext() : base(new TestFunctionDefinition(), new TestFunctionInvocation(), CancellationToken.None) @@ -58,12 +58,6 @@ public TestFunctionContext(FunctionDefinition functionDefinition, FunctionInvoca { } - public TestFunctionContext(BindingContext context) - : this(new TestFunctionDefinition(), new TestFunctionInvocation(), CancellationToken.None) - { - BindingContext = context; - } - public TestFunctionContext(FunctionDefinition functionDefinition, FunctionInvocation invocation, CancellationToken cancellationToken, IInvocationFeatures features = null, IServiceProvider serviceProvider = null) { FunctionDefinition = functionDefinition; From 3296c3fe5b6703659ad27dda73bc8f6456eaac7c Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Mon, 9 Dec 2024 14:54:29 -0800 Subject: [PATCH 09/17] remove failing test --- .../ServiceBusSessionMessageConverterTests.cs | 51 ++----------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs index 1fe014d2e..8ab00e9db 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs @@ -1,26 +1,14 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using Microsoft.Azure.Functions.Worker.Converters; +using static Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBusMessageActionsTests; +using Microsoft.Azure.Functions.Worker.Tests.Converters; using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Text.Json; using System.Threading.Tasks; -using Azure.Messaging.ServiceBus; -using Google.Protobuf; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.Azure.Functions.Worker; -using Microsoft.Azure.Functions.Worker.Converters; -using Microsoft.Azure.Functions.Worker.Extensions.ServiceBus; -using Microsoft.Azure.Functions.Worker.Grpc.Messages; -using Microsoft.Azure.Functions.Worker.Tests; -using Microsoft.Azure.Functions.Worker.Tests.Converters; -using Moq; using Xunit; -using Google.Protobuf.Collections; -using Microsoft.Azure.ServiceBus.Grpc; -using static Microsoft.Azure.Functions.Worker.Extensions.Tests.ServiceBusMessageActionsTests; -using Microsoft.VisualStudio.TestPlatform.ObjectModel.DataCollection; namespace Microsoft.Azure.Functions.Worker.Extensions.Tests { @@ -98,8 +86,7 @@ public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsSuccess() { SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" }; - RepeatedField repeatedField = new RepeatedField(); - repeatedField.Add("test"); + IList repeatedField = new List { "test" }; var bindingDataDictionary = new Dictionary { @@ -142,35 +129,5 @@ public async Task ConvertAsync_ReturnsFailure_NoSessionId() Assert.Equal(ConversionStatus.Failed, result.Status); } - - - [Fact] - public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsFailed_MultipleMessages() - { - var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; - - var jsonObject = new - { - SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" - }; - RepeatedField repeatedField = new RepeatedField(); - repeatedField.Add("test"); - repeatedField.Add("hi"); - - var bindingDataDictionary = new Dictionary - { - { "SessionIdArray", repeatedField }, - { "SessionActions", JsonSerializer.Serialize(new - { - SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" - }) - } - }; - var context = new TestConverterContext(typeof(ServiceBusSessionMessageActions), data, new TestFunctionContext(new TestBindingContext(bindingDataDictionary))); - var converter = new ServiceBusSessionMessageActionsConverter(new MockSettlementClient("test")); - var result = await converter.ConvertAsync(context); - - Assert.Equal(ConversionStatus.Failed, result.Status); - } } } From 8a444a415802d3d555284eaf5ea17bcd72a25ba1 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Tue, 10 Dec 2024 10:45:36 -0800 Subject: [PATCH 10/17] updated comment --- .../src/ServiceBusSessionMessageActionsConverter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index e2c7f4240..c9ef9c822 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -58,7 +58,8 @@ public ValueTask ConvertAsync(ConverterContext context) throw new InvalidOperationException($"Expecting batched SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } - // If sessionIdRepeatedFieldArray has a value, it will only have one value within the array. + // If sessionIdRepeatedFieldArray has a value, we can just parse the firset sessionId from the array, as all the values are guranteed to be the same. + // This is becuase there can be multiple messages but each message would belong to the same session. var parsedSessionId = foundSessionId ? sessionId!.ToString() : (sessionIdRepeatedFieldArray![0].ToString()); var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, parsedSessionId, sessionLockedUntil.GetDateTimeOffset()); var result = ConversionResult.Success(sessionActionResult); From 8ce9119b75fea3b9b67791f73ce97e313143398b Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Tue, 10 Dec 2024 10:52:49 -0800 Subject: [PATCH 11/17] updating comment --- .../src/ServiceBusSessionMessageActionsConverter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index c9ef9c822..037357f2e 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -58,8 +58,9 @@ public ValueTask ConvertAsync(ConverterContext context) throw new InvalidOperationException($"Expecting batched SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } - // If sessionIdRepeatedFieldArray has a value, we can just parse the firset sessionId from the array, as all the values are guranteed to be the same. + // If sessionIdRepeatedFieldArray has a value (isBatched = true), we can just parse the first sessionId from the array, as all the values are guranteed to be the same. // This is becuase there can be multiple messages but each message would belong to the same session. + // Note if web jobs extensions ever adds support for multiple sessions in a single batch, this logic will need to be updated. var parsedSessionId = foundSessionId ? sessionId!.ToString() : (sessionIdRepeatedFieldArray![0].ToString()); var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, parsedSessionId, sessionLockedUntil.GetDateTimeOffset()); var result = ConversionResult.Success(sessionActionResult); From bef048e132e30fe368b14b1c112f8e0a2a67b0f8 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Tue, 10 Dec 2024 11:07:19 -0800 Subject: [PATCH 12/17] addressing comments --- .../ServiceBusSessionMessageActionsConverter.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index 037357f2e..43912e48a 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -29,11 +29,20 @@ public ValueTask ConvertAsync(ConverterContext context) { try { + var foundSessionIdArray = false; + object? sessionIdArray = null; + var foundSessionId = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionId", out object? sessionId); - var foundSessionIdArray = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionIdArray", out object? sessionIdArray); + + // Only looks for sessionIdArray if sessionId is not found. + if (!foundSessionId) + { + foundSessionIdArray = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionIdArray", out sessionIdArray); + } + if (!foundSessionId && !foundSessionIdArray) { - throw new InvalidOperationException($"Expecting SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); + throw new InvalidOperationException($"Expecting SessionId or SessionIdArray within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } // Get the sessionLockedUntil property from the SessionActions binding data @@ -58,8 +67,8 @@ public ValueTask ConvertAsync(ConverterContext context) throw new InvalidOperationException($"Expecting batched SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } - // If sessionIdRepeatedFieldArray has a value (isBatched = true), we can just parse the first sessionId from the array, as all the values are guranteed to be the same. - // This is becuase there can be multiple messages but each message would belong to the same session. + // If sessionIdRepeatedFieldArray has a value (isBatched = true), we can just parse the first sessionId from the array, as all the values are guaranteed to be the same. + // This is because there can be multiple messages but each message would belong to the same session. // Note if web jobs extensions ever adds support for multiple sessions in a single batch, this logic will need to be updated. var parsedSessionId = foundSessionId ? sessionId!.ToString() : (sessionIdRepeatedFieldArray![0].ToString()); var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, parsedSessionId, sessionLockedUntil.GetDateTimeOffset()); From e60240798956c6f293f9cbe8abbd4a987f1aee2f Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Tue, 10 Dec 2024 14:44:56 -0800 Subject: [PATCH 13/17] addressing feedback for creating method for parseSessionIdFromBindingData --- ...erviceBusSessionMessageActionsConverter.cs | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index 43912e48a..3f6d9c7bb 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -29,21 +29,7 @@ public ValueTask ConvertAsync(ConverterContext context) { try { - var foundSessionIdArray = false; - object? sessionIdArray = null; - - var foundSessionId = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionId", out object? sessionId); - - // Only looks for sessionIdArray if sessionId is not found. - if (!foundSessionId) - { - foundSessionIdArray = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionIdArray", out sessionIdArray); - } - - if (!foundSessionId && !foundSessionIdArray) - { - throw new InvalidOperationException($"Expecting SessionId or SessionIdArray within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); - } + var sessionId = ParseSessionIdFromBindingData(context); // Get the sessionLockedUntil property from the SessionActions binding data var foundSessionActions = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionActions", out object? sessionActions); @@ -59,18 +45,7 @@ public ValueTask ConvertAsync(ConverterContext context) throw new InvalidOperationException("Expecting SessionLockedUntil within binding data of session actions and value was not present."); } - // Logic for if isBatched is true, then sessionIdArray will be used to get the sessionId. - var sessionIdRepeatedFieldArray = sessionIdArray as IList; - - if (foundSessionIdArray && (sessionIdRepeatedFieldArray is null || sessionIdRepeatedFieldArray.Count == 0)) - { - throw new InvalidOperationException($"Expecting batched SessionId within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); - } - - // If sessionIdRepeatedFieldArray has a value (isBatched = true), we can just parse the first sessionId from the array, as all the values are guaranteed to be the same. - // This is because there can be multiple messages but each message would belong to the same session. - // Note if web jobs extensions ever adds support for multiple sessions in a single batch, this logic will need to be updated. - var parsedSessionId = foundSessionId ? sessionId!.ToString() : (sessionIdRepeatedFieldArray![0].ToString()); + var parsedSessionId = sessionId!.ToString(); var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, parsedSessionId, sessionLockedUntil.GetDateTimeOffset()); var result = ConversionResult.Success(sessionActionResult); return new ValueTask(result); @@ -80,5 +55,32 @@ public ValueTask ConvertAsync(ConverterContext context) return new ValueTask(ConversionResult.Failed(exception)); } } + + private object? ParseSessionIdFromBindingData(ConverterContext context) + { + // Try to resolve sessionId directly + var bindingData = context.FunctionContext.BindingContext.BindingData; + bindingData.TryGetValue("SessionId", out object? sessionId); + + // If sessionId is not found and sessionIdRepeatedFieldArray has a value (isBatched = true), we can just parse the first sessionId from the array, as all the values are guaranteed to be the same. + // This is because there can be multiple messages but each message would belong to the same session. + // Note if web jobs extensions ever adds support for multiple sessions in a single batch, this logic will need to be updated. + if (sessionId == null && bindingData.TryGetValue("SessionIdArray", out object? sessionIdArray)) + { + var sessionIdRepeatedArray = sessionIdArray as IList; + if (sessionIdRepeatedArray is not null && sessionIdRepeatedArray.Count > 0) + { + sessionId = sessionIdRepeatedArray[0]; // Use the first sessionId in the array + } + } + + if (sessionId == null) + { + throw new InvalidOperationException( + $"Expecting SessionId or SessionIdArray within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); + } + + return sessionId; + } } } From d7026614cc945d9d7221c2415f9cca607b3e96a7 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Wed, 11 Dec 2024 09:45:12 -0800 Subject: [PATCH 14/17] returning string --- .../src/ServiceBusSessionMessageActionsConverter.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index 3f6d9c7bb..2da4c3e13 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -45,8 +45,7 @@ public ValueTask ConvertAsync(ConverterContext context) throw new InvalidOperationException("Expecting SessionLockedUntil within binding data of session actions and value was not present."); } - var parsedSessionId = sessionId!.ToString(); - var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, parsedSessionId, sessionLockedUntil.GetDateTimeOffset()); + var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, sessionId, sessionLockedUntil.GetDateTimeOffset()); var result = ConversionResult.Success(sessionActionResult); return new ValueTask(result); } @@ -56,7 +55,7 @@ public ValueTask ConvertAsync(ConverterContext context) } } - private object? ParseSessionIdFromBindingData(ConverterContext context) + private string ParseSessionIdFromBindingData(ConverterContext context) { // Try to resolve sessionId directly var bindingData = context.FunctionContext.BindingContext.BindingData; @@ -80,7 +79,7 @@ public ValueTask ConvertAsync(ConverterContext context) $"Expecting SessionId or SessionIdArray within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } - return sessionId; + return sessionId.ToString(); } } } From 5117c11cdcd19c546f70eff1e2b9e24e4fd52f22 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Thu, 12 Dec 2024 11:16:58 -0800 Subject: [PATCH 15/17] removing unused variable --- .../ServiceBusSessionMessageConverterTests.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs index 8ab00e9db..0b069be80 100644 --- a/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs +++ b/test/Worker.Extensions.Tests/ServiceBus/ServiceBusSessionMessageConverterTests.cs @@ -55,10 +55,6 @@ public async Task ConvertAsync_ReturnsSuccess() { var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; - var jsonObject = new - { - SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" - }; var bindingDataDictionary = new Dictionary { { "SessionId", "test" }, @@ -82,10 +78,6 @@ public async Task ConvertAsync_Batch_ForReceivedMessage_ReturnsSuccess() { var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; - var jsonObject = new - { - SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" - }; IList repeatedField = new List { "test" }; var bindingDataDictionary = new Dictionary @@ -111,10 +103,6 @@ public async Task ConvertAsync_ReturnsFailure_NoSessionId() { var data = "{\"SessionLockedUntil\":\"2024-12-05T21:10:36.1193094+00:00\"}"; - var jsonObject = new - { - SessionLockedUntil = "2024-12-05T21:10:36.1193094+00:00" - }; var bindingDataDictionary = new Dictionary { { "SessionActions", JsonSerializer.Serialize(new From a3f208f18bdc5a7469610a7b1021563b3a514eed Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Mon, 16 Dec 2024 11:05:35 -0800 Subject: [PATCH 16/17] cast converter --- .../src/ServiceBusSessionMessageActionsConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index 2da4c3e13..34ef96b8f 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -79,7 +79,7 @@ private string ParseSessionIdFromBindingData(ConverterContext context) $"Expecting SessionId or SessionIdArray within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } - return sessionId.ToString(); + return (string)sessionId; } } } From 93647926897a92ad6390e9bddd015e2d22a30e39 Mon Sep 17 00:00:00 2001 From: Aishwarya Bhandari Date: Tue, 17 Dec 2024 12:35:12 -0800 Subject: [PATCH 17/17] addressing comments regarding const --- .../src/Constants.cs | 12 ++++++++++-- .../ServiceBusSessionMessageActionsConverter.cs | 17 +++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/extensions/Worker.Extensions.ServiceBus/src/Constants.cs b/extensions/Worker.Extensions.ServiceBus/src/Constants.cs index 8c63d4124..97e7198ef 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/Constants.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/Constants.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. namespace Microsoft.Azure.Functions.Worker.Extensions.ServiceBus @@ -8,5 +8,13 @@ internal static class Constants internal const string BinaryContentType = "application/octet-stream"; internal const string BindingSource = "AzureServiceBusReceivedMessage"; + + internal const string SessionId = "SessionId"; + + internal const string SessionIdArray = "SessionIdArray"; + + internal const string SessionActions = "SessionActions"; + + internal const string SessionLockedUntil = "SessionLockedUntil"; } -} \ No newline at end of file +} diff --git a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs index 34ef96b8f..9df288b67 100644 --- a/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs +++ b/extensions/Worker.Extensions.ServiceBus/src/ServiceBusSessionMessageActionsConverter.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker.Converters; using Microsoft.Azure.Functions.Worker.Extensions.Abstractions; +using Microsoft.Azure.Functions.Worker.Extensions.ServiceBus; using Microsoft.Azure.ServiceBus.Grpc; namespace Microsoft.Azure.Functions.Worker @@ -32,17 +33,17 @@ public ValueTask ConvertAsync(ConverterContext context) var sessionId = ParseSessionIdFromBindingData(context); // Get the sessionLockedUntil property from the SessionActions binding data - var foundSessionActions = context.FunctionContext.BindingContext.BindingData.TryGetValue("SessionActions", out object? sessionActions); + var foundSessionActions = context.FunctionContext.BindingContext.BindingData.TryGetValue(Constants.SessionActions, out object? sessionActions); if (!foundSessionActions) { - throw new InvalidOperationException("Expecting SessionActions within binding data and value was not present."); + throw new InvalidOperationException($"Expecting {Constants.SessionActions} within binding data and value was not present."); } JsonDocument jsonDocument = JsonDocument.Parse(sessionActions!.ToString()); - var foundSessionLockedUntil = jsonDocument.RootElement.TryGetProperty("SessionLockedUntil", out JsonElement sessionLockedUntil); + var foundSessionLockedUntil = jsonDocument.RootElement.TryGetProperty(Constants.SessionLockedUntil, out JsonElement sessionLockedUntil); if (!foundSessionLockedUntil) { - throw new InvalidOperationException("Expecting SessionLockedUntil within binding data of session actions and value was not present."); + throw new InvalidOperationException($"Expecting {Constants.SessionLockedUntil} within binding data of session actions and value was not present."); } var sessionActionResult = new ServiceBusSessionMessageActions(_settlement, sessionId, sessionLockedUntil.GetDateTimeOffset()); @@ -59,12 +60,12 @@ private string ParseSessionIdFromBindingData(ConverterContext context) { // Try to resolve sessionId directly var bindingData = context.FunctionContext.BindingContext.BindingData; - bindingData.TryGetValue("SessionId", out object? sessionId); + bindingData.TryGetValue(Constants.SessionId, out object? sessionId); // If sessionId is not found and sessionIdRepeatedFieldArray has a value (isBatched = true), we can just parse the first sessionId from the array, as all the values are guaranteed to be the same. // This is because there can be multiple messages but each message would belong to the same session. // Note if web jobs extensions ever adds support for multiple sessions in a single batch, this logic will need to be updated. - if (sessionId == null && bindingData.TryGetValue("SessionIdArray", out object? sessionIdArray)) + if (sessionId is null && bindingData.TryGetValue(Constants.SessionIdArray, out object? sessionIdArray)) { var sessionIdRepeatedArray = sessionIdArray as IList; if (sessionIdRepeatedArray is not null && sessionIdRepeatedArray.Count > 0) @@ -73,10 +74,10 @@ private string ParseSessionIdFromBindingData(ConverterContext context) } } - if (sessionId == null) + if (sessionId is null) { throw new InvalidOperationException( - $"Expecting SessionId or SessionIdArray within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); + $"Expecting {Constants.SessionId} or {Constants.SessionIdArray} within binding data and value was not present. Sessions must be enabled when binding to {nameof(ServiceBusSessionMessageActions)}."); } return (string)sessionId;