Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Messaging] Allow binary application properties #43181

Merged
merged 4 commits into from
Apr 4, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -522,10 +522,14 @@ public static bool TryCreateAmqpPropertyValueFromNetProperty(
amqpPropertyValue = new DescribedType((AmqpSymbol)AmqpMessageConstants.TimeSpan, ((TimeSpan)propertyValue).Ticks);
break;

case AmqpType.Unknown when allowBodyTypes && propertyValue is byte[] byteArray:
case AmqpType.Unknown when propertyValue is byte[] byteArray:
amqpPropertyValue = new ArraySegment<byte>(byteArray);
break;

case AmqpType.Unknown when propertyValue is ArraySegment<byte> byteSegment:
amqpPropertyValue = byteSegment;
break;

case AmqpType.Unknown when allowBodyTypes && propertyValue is IDictionary dict:
amqpPropertyValue = new AmqpMap(dict);
break;
Expand Down Expand Up @@ -811,8 +815,7 @@ private static void ThrowSerializationFailed(string propertyName, KeyValuePair<s
///
/// <returns>The typed value of the symbol, if it belongs to the well-known set; otherwise, <c>null</c>.</returns>
///
private static object? TranslateSymbol(AmqpSymbol symbol,
object value)
private static object? TranslateSymbol(AmqpSymbol symbol, object value)
{
if (symbol.Equals(AmqpMessageConstants.Uri))
{
Expand Down
281 changes: 270 additions & 11 deletions sdk/core/Azure.Core.Amqp/tests/AmqpAnnotatedMessageConverterTests.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the MIT License.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Azure.Messaging.EventHubs.Tests
Expand Down Expand Up @@ -115,7 +117,33 @@ public static bool IsEquivalentTo(this EventData instance,
return false;
}

return instance.Properties.OrderBy(kvp => kvp.Key).SequenceEqual(other.Properties.OrderBy(kvp => kvp.Key));
foreach (var key in instance.Properties.Keys)
{
if (!other.Properties.TryGetValue(key, out object otherValue))
{
return false;
}

// Properties can contain byte[] or ArraySegment<byte> values, which need to be compared
// as a sequence rather than by strict equality. Both forms implement IList<byte>, so they
// can be normalized for comparison.

if ((instance.Properties[key] is IList<byte> instanceList) && (otherValue is IList<byte> otherList))
{
if (!instanceList.SequenceEqual(otherList))
{
return false;
}
}
else if (!instance.Properties[key].Equals(otherValue))
{
return false;
}
}

// No inequalities were found, so the events are equal.

return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,114 @@ public void IsEquivalentToDetectsDifferentProperties()
Assert.That(firstEvent.IsEquivalentTo(secondEvent), Is.False);
}

/// <summary>
/// Verifies functionality of the <see cref="EventDataExtensions.IsEquivalentTo" /> test
/// helper.
/// </summary>
///
[Test]
public void IsEquivalentToComparesByteArrayPropertiesBySequence()
{
var body = new byte[] { 0x22, 0x44, 0x88 };
var firstEvent = new EventData((byte[])body.Clone());
var secondEvent = new EventData((byte[])body.Clone());

firstEvent.Properties["test"] = new byte[] { 0x1, 0x2, 0x3 };
secondEvent.Properties["test"] = new byte[] { 0x1, 0x2, 0x3 };

Assert.That(firstEvent.IsEquivalentTo(secondEvent), Is.True);
}

/// <summary>
/// Verifies functionality of the <see cref="EventDataExtensions.IsEquivalentTo" /> test
/// helper.
/// </summary>
///
[Test]
public void IsEquivalentToDetectsDifferentArrayProperties()
{
var body = new byte[] { 0x22, 0x44, 0x88 };
var firstEvent = new EventData((byte[])body.Clone());
var secondEvent = new EventData((byte[])body.Clone());

firstEvent.Properties["test"] = new byte[] { 0x1, 0x2, 0x3 };
secondEvent.Properties["test"] = new byte[] { 0x2, 0x3, 0x4 };

Assert.That(firstEvent.IsEquivalentTo(secondEvent), Is.False);
}

/// <summary>
/// Verifies functionality of the <see cref="EventDataExtensions.IsEquivalentTo" /> test
/// helper.
/// </summary>
///
[Test]
public void IsEquivalentToComparesArraySegmentPropertiesBySequence()
{
var body = new byte[] { 0x22, 0x44, 0x88 };
var firstEvent = new EventData((byte[])body.Clone());
var secondEvent = new EventData((byte[])body.Clone());

firstEvent.Properties["test"] = new ArraySegment<byte>(new byte[] { 0x1, 0x2, 0x3 });
secondEvent.Properties["test"] = new ArraySegment<byte>(new byte[] { 0x1, 0x2, 0x3 });

Assert.That(firstEvent.IsEquivalentTo(secondEvent), Is.True);
}

/// <summary>
/// Verifies functionality of the <see cref="EventDataExtensions.IsEquivalentTo" /> test
/// helper.
/// </summary>
///
[Test]
public void IsEquivalentToDetectsDifferentArraySegmentProperties()
{
var body = new byte[] { 0x22, 0x44, 0x88 };
var firstEvent = new EventData((byte[])body.Clone());
var secondEvent = new EventData((byte[])body.Clone());

firstEvent.Properties["test"] = new ArraySegment<byte>(new byte[] { 0x1, 0x2, 0x3 });
secondEvent.Properties["test"] = new ArraySegment<byte>(new byte[] { 0x2, 0x3, 0x4 });

Assert.That(firstEvent.IsEquivalentTo(secondEvent), Is.False);
}

/// <summary>
/// Verifies functionality of the <see cref="EventDataExtensions.IsEquivalentTo" /> test
/// helper.
/// </summary>
///
[Test]
public void IsEquivalentToComparesMixedBinaryPropertiesBySequence()
{
var body = new byte[] { 0x22, 0x44, 0x88 };
var firstEvent = new EventData((byte[])body.Clone());
var secondEvent = new EventData((byte[])body.Clone());

firstEvent.Properties["test"] = new ArraySegment<byte>(new byte[] { 0x1, 0x2, 0x3 });
secondEvent.Properties["test"] = new byte[] { 0x1, 0x2, 0x3 };

Assert.That(firstEvent.IsEquivalentTo(secondEvent), Is.True);
}

/// <summary>
/// Verifies functionality of the <see cref="EventDataExtensions.IsEquivalentTo" /> test
/// helper.
/// </summary>
///
[Test]
public void IsEquivalentToDetectsMixedBinaryProperties()
{
var body = new byte[] { 0x22, 0x44, 0x88 };
var firstEvent = new EventData((byte[])body.Clone());
var secondEvent = new EventData((byte[])body.Clone());

firstEvent.Properties["test"] = new byte[] { 0x1, 0x2, 0x3 };
secondEvent.Properties["test"] = new ArraySegment<byte>(new byte[] { 0x2, 0x3, 0x4 });

Assert.That(firstEvent.IsEquivalentTo(secondEvent), Is.False);
}

/// <summary>
/// Verifies functionality of the <see cref="EventDataExtensions.IsEquivalentTo" /> test
/// helper.
Expand Down
2 changes: 2 additions & 0 deletions sdk/eventhub/Azure.Messaging.EventHubs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

### Other Changes

- It is now possible to set `byte[]` values as [application properties](https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html#type-application-properties) in the `EventData.Properties` collection.

## 5.11.1 (2024-03-05)

### Other Changes
Expand Down
Loading
Loading