Skip to content

Commit

Permalink
fix: Custom attribute values of type float and decimal were not seria…
Browse files Browse the repository at this point in the history
…lized correctly. (#2975)
  • Loading branch information
tippmar-nr authored Jan 30, 2025
1 parent 0ab2e1b commit 8812fe1
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,10 @@ public static AttributeDefinitionBuilder<object, object> CreateCustomAttribute(s
case TypeCode.Int32:
return Convert.ToInt64(input);

// don't convert Decimal and Single to double.
// The value ends up getting serialized as a string, so there's no need for the conversion
case TypeCode.Decimal:
case TypeCode.Single:
return Convert.ToDouble(input);

case TypeCode.Double:
case TypeCode.Int64:
Expand Down
50 changes: 25 additions & 25 deletions tests/Agent/UnitTests/Core.UnitTest/Attributes/AttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System;
using System.Linq;
using System.Collections.Generic;
using NUnit.Framework.Internal;

namespace NewRelic.Agent.Core.Attributes.Tests
{
Expand All @@ -25,38 +24,17 @@ public class AttributeTests
[TestCase((ulong)8, 8L)]
[TestCase((float)1.0, 1D)]
[TestCase(/*(double)*/2.0, 2D)]
[TestCase(0.2D, 0.2D)]
[TestCase(0.2F, 0.2F)]
public void Attributes_with_valid_type_are_valid_attributes(object attributeValue, object expectedResult)
{
TestValue(attributeValue, expectedResult);
}


private void TestValue(object attributeValue, object expectedResult)
{
var filter = new AttributeFilter(new AttributeFilter.Settings());

var attribDef = AttributeDefinitionBuilder
.CreateCustomAttribute("test", AttributeDestinations.All)
.Build(filter);

var attribVals = new AttributeValueCollection(AttributeValueCollection.AllTargetModelTypes);

attribDef.TrySetValue(attribVals, attributeValue);

var actualAttribVal = attribVals.GetAttributeValues(AttributeClassification.UserAttributes)
.FirstOrDefault(x => x.AttributeDefinition == attribDef);


NrAssert.Multiple(
() => Assert.That(actualAttribVal, Is.Not.Null),
() => Assert.That(actualAttribVal.Value, Is.EqualTo(expectedResult))
);
}

[Test]
public void Attributes_with_decimal_type_are_valid_attributes()
{
TestValue(1.0m, 1D);
TestValue(0.2M, 0.2M);
}

[Test]
Expand Down Expand Up @@ -261,5 +239,27 @@ public void Attributes_value_size_other_strings()
() => Assert.That(values.ElementAt(2).Value.ToString(), Has.Length.EqualTo(255))
);
}

private void TestValue(object attributeValue, object expectedResult)
{
var filter = new AttributeFilter(new AttributeFilter.Settings());

var attribDef = AttributeDefinitionBuilder
.CreateCustomAttribute("test", AttributeDestinations.All)
.Build(filter);

var attribVals = new AttributeValueCollection(AttributeValueCollection.AllTargetModelTypes);

attribDef.TrySetValue(attribVals, attributeValue);

var actualAttribVal = attribVals.GetAttributeValues(AttributeClassification.UserAttributes)
.FirstOrDefault(x => x.AttributeDefinition == attribDef);


NrAssert.Multiple(
() => Assert.That(actualAttribVal, Is.Not.Null),
() => Assert.That(actualAttribVal.Value, Is.EqualTo(expectedResult))
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void CustomEvents_MultipleEvents_Serialization()
var customEvents = new CustomEventWireModel[countEvents];
var expectedSerializations = new List<Dictionary<string, object>[]>();

for(var i = 0; i < countEvents; i++)
for (var i = 0; i < countEvents; i++)
{
var timestampVal = DateTime.UtcNow;
var typeVal = $"CustomEvent{i}";
Expand Down Expand Up @@ -87,7 +87,64 @@ public void CustomEvents_MultipleEvents_Serialization()
AttributeComparer.CompareDictionaries(expectedSerializations[0], deserialized[0]);
AttributeComparer.CompareDictionaries(expectedSerializations[1], deserialized[1]);
}
}

[Test]
public void CustomEvents_UserAttributes_AllAttributeTypesSerializeCorrectly()
{
var dateTime = DateTime.UtcNow;
var timestampVal = dateTime;
var typeVal = $"CustomEvent";

var guid = Guid.NewGuid();
var expectedSerialization = new Dictionary<string, object>[]
{
new Dictionary<string, object>()
{
{_attribDefs.Timestamp.Name, timestampVal.ToUnixTimeMilliseconds() },
{_attribDefs.CustomEventType.Name, typeVal }
},

new Dictionary<string, object>()
{
{ "boolVal", true},
{ "dateTimeVal", dateTime},
{ "decimalVal", 0.2M},
{ "doubleVal", 0.2D},
{ "enumVal", AttributeDestinations.CustomEvent},
{ "floatVal", 0.2f},
{ "guidVal", guid},
{ "intVal", 2},
{ "longVal", 2L},
{ "stringVal", "string"},
},

new Dictionary<string, object>()
};

var attribVals = new AttributeValueCollection(AttributeDestinations.CustomEvent);

_attribDefs.Timestamp.TrySetValue(attribVals, timestampVal);
_attribDefs.CustomEventType.TrySetValue(attribVals, typeVal);

_attribDefs.GetCustomAttributeForCustomEvent("boolVal").TrySetValue(attribVals, true);
_attribDefs.GetCustomAttributeForCustomEvent("dateTimeVal").TrySetValue(attribVals, dateTime);
_attribDefs.GetCustomAttributeForCustomEvent("decimalVal").TrySetValue(attribVals, 0.2M);
_attribDefs.GetCustomAttributeForCustomEvent("doubleVal").TrySetValue(attribVals, 0.2D);
_attribDefs.GetCustomAttributeForCustomEvent("enumVal").TrySetValue(attribVals, AttributeDestinations.CustomEvent);
_attribDefs.GetCustomAttributeForCustomEvent("floatVal").TrySetValue(attribVals, 0.2f);
_attribDefs.GetCustomAttributeForCustomEvent("guidVal").TrySetValue(attribVals, guid);
_attribDefs.GetCustomAttributeForCustomEvent("intVal").TrySetValue(attribVals, 2);
_attribDefs.GetCustomAttributeForCustomEvent("longVal").TrySetValue(attribVals, 2L);
_attribDefs.GetCustomAttributeForCustomEvent("stringVal").TrySetValue(attribVals, "string");

var customEvent = new CustomEventWireModel(.5f, attribVals);

var serialized = JsonConvert.SerializeObject(customEvent);
var expectedSerialized = JsonConvert.SerializeObject(expectedSerialization);

Assert.That(serialized, Is.Not.Null);
Assert.That(serialized, Is.EqualTo(expectedSerialized));
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public static bool IsEqualTo(this object val1, object val2)
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return Math.Abs((double)val1Comp - (double)val2Comp) < .0001;
return Math.Abs(Convert.ToDouble(val1Comp) - Convert.ToDouble(val2Comp)) < .0001; // close enough, I guess?

default:
return val1Comp.Equals(val2Comp);
Expand Down Expand Up @@ -111,25 +111,24 @@ public static object ConvertForCompare(object val)
{
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
return Convert.ToInt64(val);

case TypeCode.Decimal:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
return Convert.ToDouble(val);
case TypeCode.Int64:
case TypeCode.Boolean:
case TypeCode.String:
return val;

case TypeCode.DateTime:
return ((DateTime)val).ToString("o");

case TypeCode.String:
return val;

default:
return val.ToString();
}
Expand Down

0 comments on commit 8812fe1

Please sign in to comment.