//
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using Moq;
using OpenTelemetry.Trace;
using OpenTelemetry.Trace.Configuration;
using StackExchange.Redis;
using StackExchange.Redis.Profiling;
using Xunit;
namespace OpenTelemetry.Instrumentation.StackExchangeRedis.Implementation
{
[Collection("Redis")]
public class RedisProfilerEntryToActivityConverterTests : IDisposable
{
private readonly ConnectionMultiplexer connection;
private readonly IDisposable sdk;
public RedisProfilerEntryToActivityConverterTests()
{
var connectionOptions = new ConfigurationOptions
{
AbortOnConnectFail = false,
};
connectionOptions.EndPoints.Add("localhost:6379");
this.connection = ConnectionMultiplexer.Connect(connectionOptions);
this.sdk = OpenTelemetrySdk.EnableOpenTelemetry(
(builder) => builder.AddRedisInstrumentation(this.connection));
}
public void Dispose()
{
this.sdk.Dispose();
this.connection.Dispose();
}
[Fact]
public void ProfilerCommandToActivity_UsesCommandAsName()
{
var activity = new Activity("redis-profiler");
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow);
profiledCommand.Setup(m => m.Command).Returns("SET");
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Equal("SET", result.DisplayName);
}
[Fact]
public void ProfilerCommandToActivity_UsesTimestampAsStartTime()
{
var now = DateTimeOffset.Now;
var activity = new Activity("redis-profiler");
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.CommandCreated).Returns(now.DateTime);
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Equal(now, result.StartTimeUtc);
}
[Fact]
public void ProfilerCommandToActivity_SetsDbTypeAttributeAsRedis()
{
var activity = new Activity("redis-profiler");
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow);
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Contains(result.Tags, kvp => kvp.Key == SpanAttributeConstants.DatabaseSystemKey);
Assert.Equal("redis", result.Tags.FirstOrDefault(kvp => kvp.Key == SpanAttributeConstants.DatabaseSystemKey).Value);
}
[Fact]
public void ProfilerCommandToActivity_UsesCommandAsDbStatementAttribute()
{
var activity = new Activity("redis-profiler");
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow);
profiledCommand.Setup(m => m.Command).Returns("SET");
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Contains(result.Tags, kvp => kvp.Key == SpanAttributeConstants.DatabaseStatementKey);
Assert.Equal("SET", result.Tags.FirstOrDefault(kvp => kvp.Key == SpanAttributeConstants.DatabaseStatementKey).Value);
}
[Fact]
public void ProfilerCommandToActivity_UsesFlagsForFlagsAttribute()
{
var activity = new Activity("redis-profiler");
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.CommandCreated).Returns(DateTime.UtcNow);
var expectedFlags = CommandFlags.FireAndForget |
CommandFlags.NoRedirect;
profiledCommand.Setup(m => m.Flags).Returns(expectedFlags);
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Contains(result.Tags, kvp => kvp.Key == StackExchangeRedisCallsInstrumentation.RedisFlagsKeyName);
Assert.Equal("PreferMaster, FireAndForget, NoRedirect", result.Tags.FirstOrDefault(kvp => kvp.Key == StackExchangeRedisCallsInstrumentation.RedisFlagsKeyName).Value);
}
[Fact]
public void ProfilerCommandToActivity_UsesIpEndPointAsEndPoint()
{
long address = 1;
int port = 2;
var activity = new Activity("redis-profiler");
IPEndPoint ipLocalEndPoint = new IPEndPoint(address, port);
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.EndPoint).Returns(ipLocalEndPoint);
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Contains(result.Tags, kvp => kvp.Key == SpanAttributeConstants.NetPeerIp);
Assert.Equal($"{address}.0.0.0", result.Tags.FirstOrDefault(kvp => kvp.Key == SpanAttributeConstants.NetPeerIp).Value);
Assert.Contains(result.Tags, kvp => kvp.Key == SpanAttributeConstants.NetPeerPort);
Assert.Equal($"{port}", result.Tags.FirstOrDefault(kvp => kvp.Key == SpanAttributeConstants.NetPeerPort).Value);
}
[Fact]
public void ProfilerCommandToActivity_UsesDnsEndPointAsEndPoint()
{
var dnsEndPoint = new DnsEndPoint("https://opentelemetry.io/", 443);
var activity = new Activity("redis-profiler");
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.EndPoint).Returns(dnsEndPoint);
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Contains(result.Tags, kvp => kvp.Key == SpanAttributeConstants.NetPeerName);
Assert.Equal(dnsEndPoint.Host, result.Tags.FirstOrDefault(kvp => kvp.Key == SpanAttributeConstants.NetPeerName).Value);
Assert.Contains(result.Tags, kvp => kvp.Key == SpanAttributeConstants.NetPeerPort);
Assert.Equal(dnsEndPoint.Port.ToString(), result.Tags.FirstOrDefault(kvp => kvp.Key == SpanAttributeConstants.NetPeerPort).Value);
}
#if !NET461
[Fact]
public void ProfilerCommandToActivity_UsesOtherEndPointAsEndPoint()
{
var unixEndPoint = new UnixDomainSocketEndPoint("https://opentelemetry.io/");
var activity = new Activity("redis-profiler");
var profiledCommand = new Mock();
profiledCommand.Setup(m => m.EndPoint).Returns(unixEndPoint);
var result = RedisProfilerEntryToActivityConverter.ProfilerCommandToActivity(activity, profiledCommand.Object);
Assert.Contains(result.Tags, kvp => kvp.Key == SpanAttributeConstants.PeerServiceKey);
Assert.Equal(unixEndPoint.ToString(), result.Tags.FirstOrDefault(kvp => kvp.Key == SpanAttributeConstants.PeerServiceKey).Value);
}
#endif
}
}