|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Aspire.Dashboard.Configuration;
using Aspire.Dashboard.Otlp.Model;
using Aspire.Tests.Shared.Telemetry;
using Google.Protobuf;
using Google.Protobuf.Collections;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using OpenTelemetry.Proto.Common.V1;
using Xunit;
namespace Aspire.Dashboard.Tests.TelemetryRepositoryTests;
public class OtlpHelpersTests
{
[Fact]
public void GetString_StringValue()
{
// Arrange
var anyValue = new AnyValue { StringValue = "string!" };
// Act
var s = OtlpHelpers.GetString(anyValue);
// Assert
Assert.Equal("string!", s);
}
[Fact]
public void GetString_BytesValue()
{
// Arrange
var anyValue = new AnyValue
{
BytesValue = ByteString.CopyFromUtf8("Hello world")
};
// Act
var s = OtlpHelpers.GetString(anyValue);
// Assert
Assert.Equal("48656c6c6f20776f726c64", s);
}
[Fact]
public void GetString_NoneValue()
{
// Arrange
var anyValue = new AnyValue();
// Act
var s = OtlpHelpers.GetString(anyValue);
// Assert
Assert.Equal("", s);
}
[Fact]
public void GetString_ArrayValue()
{
// Arrange
var anyValue = new AnyValue
{
ArrayValue = new ArrayValue
{
Values =
{
new AnyValue { BoolValue = true },
new AnyValue()
}
}
};
// Act
var s = OtlpHelpers.GetString(anyValue);
// Assert
Assert.Equal("[true,null]", s);
}
[Fact]
public void GetString_KeyValues()
{
// Arrange
var anyValue = new AnyValue
{
KvlistValue = new KeyValueList
{
Values =
{
new KeyValue
{
Key = "prop1",
Value = new AnyValue
{
ArrayValue = new ArrayValue
{
Values =
{
new AnyValue { StringValue = "string!" },
new AnyValue { DoubleValue = 1.1d },
new AnyValue { IntValue = 1 }
}
}
}
},
new KeyValue
{
Key = "prop2",
Value = new AnyValue
{
BytesValue = ByteString.CopyFromUtf8("Hello world")
}
},
new KeyValue
{
Key = "prop3",
Value = new AnyValue
{
KvlistValue = new KeyValueList
{
Values =
{
new KeyValue
{
Key = "nestedProp1",
Value = new AnyValue { StringValue = "nested!" }
}
}
}
}
}
}
}
};
// Act
var s = OtlpHelpers.GetString(anyValue);
// Assert
Assert.Equal(@"{""prop1"":[""string!"",1.1,1],""prop2"":""48656c6c6f20776f726c64"",""prop3"":{""nestedProp1"":""nested!""}}"{""prop1"":[""string!"",1.1,1],""prop2"":""48656c6c6f20776f726c64"",""prop3"":{""nestedProp1"":""nested!""}}", s);
}
[Fact]
public void CopyKeyValuePairs_UnderLimit_AllCopied()
{
// Arrange
KeyValuePair<string, string>[]? copiedAttributes = null;
// Act
OtlpHelpers.CopyKeyValuePairs(
new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } }
},
[],
TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 3 }),
out var copyCount,
ref copiedAttributes);
// Assert
Assert.Equal(1, copyCount);
Assert.Collection(copiedAttributes,
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1", a.Value);
});
}
[Fact]
public void CopyKeyValuePairs_OverLimit_LimitCopied()
{
// Arrange
KeyValuePair<string, string>[]? copiedAttributes = null;
// Act
OtlpHelpers.CopyKeyValuePairs(
new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2" } },
new KeyValue { Key = "key3", Value = new AnyValue { StringValue = "value3" } },
new KeyValue { Key = "key4", Value = new AnyValue { StringValue = "value4" } }
},
[],
TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 3 }),
out var copyCount,
ref copiedAttributes);
// Assert
Assert.Equal(3, copyCount);
Assert.Collection(copiedAttributes,
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1", a.Value);
},
a =>
{
Assert.Equal("key2", a.Key);
Assert.Equal("value2", a.Value);
},
a =>
{
Assert.Equal("key3", a.Key);
Assert.Equal("value3", a.Value);
});
}
[Fact]
public void CopyKeyValuePairs_OverLimitWithDuplicates_LimitCopied()
{
// Arrange
KeyValuePair<string, string>[]? copiedAttributes = null;
// Act
OtlpHelpers.CopyKeyValuePairs(
new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } },
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1-2" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2-2" } },
new KeyValue { Key = "key3", Value = new AnyValue { StringValue = "value3" } },
new KeyValue { Key = "key3", Value = new AnyValue { StringValue = "value3-2" } },
new KeyValue { Key = "key4", Value = new AnyValue { StringValue = "value4" } },
new KeyValue { Key = "key4", Value = new AnyValue { StringValue = "value4-2" } }
},
[],
TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 3 }),
out var copyCount,
ref copiedAttributes);
// Assert
Assert.Equal(3, copyCount);
Assert.Collection(copiedAttributes,
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1-2", a.Value);
},
a =>
{
Assert.Equal("key2", a.Key);
Assert.Equal("value2-2", a.Value);
},
a =>
{
Assert.Equal("key3", a.Key);
Assert.Equal("value3-2", a.Value);
});
}
[Fact]
public void CopyKeyValuePairs_HasParent_UnderLimit_LimitCopied()
{
// Arrange
KeyValuePair<string, string>[]? copiedAttributes = null;
// Act
OtlpHelpers.CopyKeyValuePairs(
new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } }
},
[
new KeyValuePair<string, string>("parentkey1", "parentvalue1")
],
TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 3 }),
out var copyCount,
ref copiedAttributes);
// Assert
Assert.Equal(2, copyCount);
Assert.Collection(copiedAttributes,
a =>
{
Assert.Equal("parentkey1", a.Key);
Assert.Equal("parentvalue1", a.Value);
},
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1", a.Value);
});
}
[Fact]
public void CopyKeyValuePairs_HasParent_OverLimit_LimitCopied()
{
// Arrange
KeyValuePair<string, string>[]? copiedAttributes = null;
// Act
OtlpHelpers.CopyKeyValuePairs(
new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2" } },
new KeyValue { Key = "key3", Value = new AnyValue { StringValue = "value3" } }
},
[
new KeyValuePair<string, string>("parentkey1", "parentvalue1")
],
TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 3 }),
out var copyCount,
ref copiedAttributes);
// Assert
Assert.Equal(3, copyCount);
Assert.Collection(copiedAttributes,
a =>
{
Assert.Equal("parentkey1", a.Key);
Assert.Equal("parentvalue1", a.Value);
},
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1", a.Value);
},
a =>
{
Assert.Equal("key2", a.Key);
Assert.Equal("value2", a.Value);
});
}
[Fact]
public void CopyKeyValuePairs_HasParent_ParentLimit_ParentValues()
{
// Arrange
KeyValuePair<string, string>[]? copiedAttributes = null;
// Act
OtlpHelpers.CopyKeyValuePairs(
new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2" } },
new KeyValue { Key = "key3", Value = new AnyValue { StringValue = "value3" } }
},
[
new KeyValuePair<string, string>("parentkey1", "parentvalue1"),
new KeyValuePair<string, string>("parentkey2", "parentvalue2"),
new KeyValuePair<string, string>("parentkey3", "parentvalue3")
],
TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 3 }),
out var copyCount,
ref copiedAttributes);
// Assert
Assert.Equal(3, copyCount);
Assert.Collection(copiedAttributes,
a =>
{
Assert.Equal("parentkey1", a.Key);
Assert.Equal("parentvalue1", a.Value);
},
a =>
{
Assert.Equal("parentkey2", a.Key);
Assert.Equal("parentvalue2", a.Value);
},
a =>
{
Assert.Equal("parentkey3", a.Key);
Assert.Equal("parentvalue3", a.Value);
});
}
[Fact]
public void ToKeyValuePairs_OverLimit_LimitReturned()
{
// Arrange
var attributes = new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2" } },
new KeyValue { Key = "key3", Value = new AnyValue { StringValue = "value3" } }
};
// Act
var results = attributes.ToKeyValuePairs(TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 2 }));
// Act
Assert.Collection(results,
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1", a.Value);
},
a =>
{
Assert.Equal("key2", a.Key);
Assert.Equal("value2", a.Value);
});
}
[Fact]
public void ToKeyValuePairs_OverLimitWithDuplicates_LimitReturned()
{
// Arrange
var attributes = new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } },
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1-2" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2" } }
};
var testSink = new TestSink();
var factory = LoggerFactory.Create(b =>
{
b.SetMinimumLevel(LogLevel.Debug);
b.AddProvider(new TestLoggerProvider(testSink));
});
// Act
var context = TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 2 }, logger: factory.CreateLogger<OtlpHelpersTests>());
var results = attributes.ToKeyValuePairs(context);
// Assert
Assert.Collection(results,
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1-2", a.Value);
},
a =>
{
Assert.Equal("key2", a.Key);
Assert.Equal("value2", a.Value);
});
var w = Assert.Single(testSink.Writes);
Assert.Equal("Duplicate attribute key1 with different value. Last value wins.", w.Message);
}
[Fact]
public void ToKeyValuePairs_OverLimitWithDuplicates_Filter_LimitReturned()
{
// Arrange
var attributes = new RepeatedField<KeyValue>
{
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1" } },
new KeyValue { Key = "key1", Value = new AnyValue { StringValue = "value1-2" } },
new KeyValue { Key = "key1-2", Value = new AnyValue { StringValue = "value1-2" } },
new KeyValue { Key = "key1-3", Value = new AnyValue { StringValue = "value1-3" } },
new KeyValue { Key = "key1-4", Value = new AnyValue { StringValue = "value1-4" } },
new KeyValue { Key = "key1-5", Value = new AnyValue { StringValue = "value1-5" } },
new KeyValue { Key = "key2", Value = new AnyValue { StringValue = "value2" } },
new KeyValue { Key = "key3", Value = new AnyValue { StringValue = "value3" } },
new KeyValue { Key = "key4", Value = new AnyValue { StringValue = "value4" } }
};
var testSink = new TestSink();
var factory = LoggerFactory.Create(b =>
{
b.SetMinimumLevel(LogLevel.Debug);
b.AddProvider(new TestLoggerProvider(testSink));
});
// Act
var context = TelemetryTestHelpers.CreateContext(options: new TelemetryLimitOptions { MaxAttributeCount = 3 }, logger: factory.CreateLogger<OtlpHelpersTests>());
var results = attributes.ToKeyValuePairs(context, kv =>
{
return !kv.Key.Contains('-');
});
// Assert
Assert.Collection(results,
a =>
{
Assert.Equal("key1", a.Key);
Assert.Equal("value1-2", a.Value);
},
a =>
{
Assert.Equal("key2", a.Key);
Assert.Equal("value2", a.Value);
},
a =>
{
Assert.Equal("key3", a.Key);
Assert.Equal("value3", a.Value);
});
var w = Assert.Single(testSink.Writes);
Assert.Equal("Duplicate attribute key1 with different value. Last value wins.", w.Message);
}
}
|