//-----------------------------------------------------------------------------
//
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
// http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file 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.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using Amazon.XRay.Recorder.Core;
using Amazon.XRay.Recorder.Core.Exceptions;
using Amazon.XRay.Recorder.Core.Internal.Context;
using Amazon.XRay.Recorder.Core.Internal.Emitters;
using Amazon.XRay.Recorder.Core.Internal.Entities;
using Amazon.XRay.Recorder.Core.Internal.Utils;
using Amazon.XRay.Recorder.Core.Sampling;
using Amazon.XRay.Recorder.Core.Strategies;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using static Amazon.XRay.Recorder.UnitTests.AwsXrayRecorderBuilderTests;
namespace Amazon.XRay.Recorder.UnitTests
{
[TestClass]
public class AwsXrayRecorderTests : TestBase
{
private const string DisableXRayTracingKey = "DisableXRayTracing";
private AWSXRayRecorder _recorder;
#if !NETFRAMEWORK
private XRayOptions _xRayOptions = new XRayOptions();
#endif
[TestInitialize]
public void Initialize()
{
_recorder = new AWSXRayRecorder();
}
[TestCleanup]
public new void TestCleanup()
{
base.TestCleanup();
#if NETFRAMEWORK
ConfigurationManager.AppSettings[DisableXRayTracingKey] = string.Empty;
AppSettings.Reset();
#else
_xRayOptions = new XRayOptions();
#endif
Environment.SetEnvironmentVariable(AWSXRayRecorder.EnvironmentVariableContextMissingStrategy, null);
_recorder.Dispose();
AWSXRayRecorder.Instance.Dispose();
_recorder = null;
}
[TestMethod]
public void TestSyncCreateSegmentAndSubsegments()
{
_recorder.BeginSegment("parent", TraceId);
Segment parent = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.BeginSubsegment("child");
Subsegment child = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSubsegment();
Assert.ReferenceEquals(AWSXRayRecorder.Instance.TraceContext.GetEntity(), parent);
_recorder.EndSegment();
Assert.ReferenceEquals(parent, child.Parent);
Assert.IsTrue(parent.Subsegments.Contains(child));
}
[TestMethod]
public void TestSegmentAndSubsegmentsWithNoTraceId()
{
_recorder.BeginSegment("parent");
Segment parent = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.BeginSubsegment("child");
Subsegment child = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSubsegment();
Assert.ReferenceEquals(AWSXRayRecorder.Instance.TraceContext.GetEntity(), parent);
_recorder.EndSegment();
Assert.AreEqual(SampleDecision.Sampled, parent.Sampled);
Assert.ReferenceEquals(parent, child.Parent);
Assert.IsTrue(parent.Subsegments.Contains(child));
}
[TestMethod]
public void TestSegmentAndSubsegmentsWithNullSampleResponse()
{
_recorder.BeginSegment("parent", samplingResponse:null);
Segment parent = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.BeginSubsegment("child");
Subsegment child = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSubsegment();
Assert.ReferenceEquals(AWSXRayRecorder.Instance.TraceContext.GetEntity(), parent);
_recorder.EndSegment();
Assert.ReferenceEquals(parent, child.Parent);
Assert.IsTrue(parent.Subsegments.Contains(child));
}
[TestMethod]
public async Task TestAsyncCreateSegmentAndSubsegments()
{
_recorder.BeginSegment("parent", TraceId);
Segment parent = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
Subsegment child = null;
await Task.Run(() =>
{
_recorder.BeginSubsegment("child");
child = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSubsegment();
});
_recorder.EndSegment();
Assert.IsNotNull(child);
Assert.ReferenceEquals(parent, child.Parent);
Assert.IsTrue(parent.Subsegments.Contains(child));
}
[TestMethod]
public void TestAsyncCreateTwoSubsegment()
{
_recorder.BeginSegment("parent", TraceId);
Segment parent = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
Subsegment child1 = null;
Subsegment child2 = null;
Task task1 = Task.Run(async () =>
{
_recorder.BeginSubsegment("child1");
await Task.Delay(1000); // Ensure task1 will not complete when task1 is running
child1 = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSubsegment();
});
Task task2 = Task.Run(() =>
{
_recorder.BeginSubsegment("child2");
child2 = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSubsegment();
});
Task.WaitAll(task1, task2);
_recorder.EndSegment();
Assert.IsNotNull(child1);
Assert.IsNotNull(child2);
Assert.ReferenceEquals(parent, child1.Parent);
Assert.ReferenceEquals(parent, child2.Parent);
Assert.IsTrue(parent.Subsegments.Contains(child1));
Assert.IsTrue(parent.Subsegments.Contains(child2));
}
[TestMethod]
public void TestCreateThousandSubsegmentsParallel()
{
_recorder.BeginSegment("parent", TraceId);
Segment parent = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
Action action = () =>
{
_recorder.BeginSubsegment("child");
_recorder.EndSubsegment();
};
var actions = Enumerable.Repeat(action, 1000).ToArray();
Parallel.Invoke(actions);
_recorder.EndSegment();
Assert.IsTrue(parent.Subsegments.Count < 100);
Assert.AreEqual(0, parent.Reference);
Assert.AreEqual(parent.Size, parent.Subsegments.Count);
}
[TestMethod]
public async Task TestAsyncCreateSubsegmentInAChain()
{
_recorder.BeginSegment("parent", TraceId);
var parent = AWSXRayRecorder.Instance.TraceContext.GetEntity();
Subsegment subsegment1 = null;
Subsegment subsegment2 = null;
await Task.Run(async () =>
{
_recorder.BeginSubsegment("subsegment1");
subsegment1 = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
await Task.Run(() =>
{
_recorder.BeginSubsegment("subsegment2");
subsegment2 = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSubsegment();
});
_recorder.EndSubsegment();
});
_recorder.EndSegment();
Assert.ReferenceEquals(parent, subsegment1.Parent);
Assert.IsTrue(parent.Subsegments.Contains(subsegment1));
Assert.ReferenceEquals(subsegment1, subsegment2.Parent);
Assert.IsTrue(subsegment1.Subsegments.Contains(subsegment2));
}
[TestMethod]
public void TaskAsyncCreateThousandSubsegments()
{
_recorder.BeginSegment("parent", TraceId);
Segment parent = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
Action action = () =>
{
_recorder.BeginSubsegment("child");
_recorder.EndSubsegment();
};
var tasks = new Task[1000];
for (int i = 0; i < 1000; i++)
{
tasks[i] = Task.Run(action);
}
Task.WaitAll(tasks);
_recorder.EndSegment();
Assert.IsTrue(parent.Subsegments.Count < 100);
Assert.AreEqual(0, parent.Reference);
Assert.AreEqual(parent.Size, parent.Subsegments.Count);
}
[TestMethod]
public async Task TestSubsegmentOutLiveParent()
{
var mockEmitter = new Mock();
using (var client = AWSXRayRecorderFactory.CreateAWSXRayRecorder(mockEmitter.Object))
{
client.BeginSegment("parent", TraceId);
var parent = AWSXRayRecorder.Instance.TraceContext.GetEntity();
Subsegment child = null;
Task task = Task.Run(async () =>
{
client.BeginSubsegment("child");
child = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
await Task.Delay(1000); // Wait for parent to end first
client.EndSubsegment();
});
await Task.Delay(50); // Wait to ensure subsegment has started
client.EndSegment();
// Subsegment is not ended
mockEmitter.Verify(x => x.Send(It.IsAny()), Times.Never);
task.Wait();
Assert.IsNotNull(child);
// subsegment ends
mockEmitter.Verify(x => x.Send(It.IsAny()), Times.Once);
}
}
[TestMethod]
public void TestAddAnnotation()
{
_recorder.BeginSegment("test", TraceId);
_recorder.AddAnnotation("int", 98109);
_recorder.AddAnnotation("string", "US");
_recorder.AddAnnotation("bool", true);
_recorder.AddAnnotation("long", 123L);
_recorder.AddAnnotation("double", 100.2);
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
Assert.AreEqual(98109, segment.Annotations["int"]);
Assert.AreEqual("US", segment.Annotations["string"]);
Assert.AreEqual(true, segment.Annotations["bool"]);
Assert.AreEqual(123L, segment.Annotations["long"]);
Assert.AreEqual(100.2, segment.Annotations["double"]);
_recorder.EndSegment();
}
[TestMethod]
public void TestAddException()
{
_recorder.BeginSegment("test", TraceId);
var e = new ArgumentNullException("value");
_recorder.AddException(e);
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
Assert.IsNotNull(segment);
Assert.IsTrue(segment.HasFault);
Assert.ReferenceEquals(e, segment.Cause.ExceptionDescriptors[0].Exception);
_recorder.EndSegment();
}
[TestMethod]
public void TestMarkFault()
{
_recorder.BeginSegment("test", TraceId);
_recorder.MarkFault();
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
Assert.IsTrue(segment.HasFault);
_recorder.EndSegment();
}
[TestMethod]
public void TestMarkError()
{
_recorder.BeginSegment("test", TraceId);
_recorder.MarkError();
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
Assert.IsTrue(segment.HasError);
_recorder.EndSegment();
}
[TestMethod]
public void TestTraceMethodWithReturnValue()
{
_recorder.BeginSegment("test", TraceId);
int count = _recorder.TraceMethod("PlusOneReturn", () => AwsXrayRecorderTests.PlusOneReturn(0));
Assert.AreEqual(1, count);
var subsegment = AWSXRayRecorder.Instance.TraceContext.GetEntity().Subsegments[0];
Assert.AreEqual("PlusOneReturn", subsegment.Name);
_recorder.EndSegment();
}
[TestMethod]
public void TestTraceMethodReturnVoid()
{
_recorder.BeginSegment("test", TraceId);
int count = 0;
_recorder.TraceMethod("PlusOneNoReturn", () => AwsXrayRecorderTests.PlusOneNoReturn(ref count));
Assert.AreEqual(1, count);
var subsegment = AWSXRayRecorder.Instance.TraceContext.GetEntity().Subsegments[0];
Assert.AreEqual("PlusOneNoReturn", subsegment.Name);
_recorder.EndSegment();
}
[TestMethod]
public async Task TestTraceMethodAsyncReturnVoid()
{
_recorder.BeginSegment("test", TraceId);
int count = 0;
await _recorder.TraceMethodAsync("PlusOneNoReturnAsync", () => AwsXrayRecorderTests.PlusOneNoReturnAsync(count));
var subsegment = AWSXRayRecorder.Instance.TraceContext.GetEntity().Subsegments[0];
Assert.AreEqual("PlusOneNoReturnAsync", subsegment.Name);
_recorder.EndSegment();
}
[TestMethod]
public async Task TestTraceMethodAsyncWithReturnValueAsync()
{
_recorder.BeginSegment("test", TraceId);
int count = 0;
var result = await _recorder.TraceMethodAsync("PlusOneReturnAsync", () => AwsXrayRecorderTests.PlusOneReturnAsync(count));
Assert.AreEqual(1, result);
var subsegment = AWSXRayRecorder.Instance.TraceContext.GetEntity().Subsegments[0];
Assert.AreEqual("PlusOneReturnAsync", subsegment.Name);
_recorder.EndSegment();
}
[TestMethod]
public void TestTraceMethodThrowException()
{
_recorder.BeginSegment("test", TraceId);
try
{
_recorder.TraceMethod("exception", () => { throw new ArgumentNullException("value"); });
Assert.Fail();
}
catch (ArgumentNullException)
{
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
var subsegment = segment.Subsegments[0];
Assert.IsTrue(subsegment.HasFault);
Assert.AreEqual("ArgumentNullException", subsegment.Cause.ExceptionDescriptors[0].Type);
}
finally
{
_recorder.EndSegment();
}
}
[TestMethod]
public async Task TestTraceMethodAsyncThrowException()
{
_recorder.BeginSegment("test", TraceId);
try
{
await _recorder.TraceMethodAsync("exception", () => AwsXrayRecorderTests.PlusOneReturnAsyncThrowException(0));
Assert.Fail();
}
catch (ArgumentNullException)
{
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
var subsegment = segment.Subsegments[0];
Assert.IsTrue(subsegment.HasFault);
Assert.AreEqual("ArgumentNullException", subsegment.Cause.ExceptionDescriptors[0].Type);
}
finally
{
_recorder.EndSegment();
}
}
[TestMethod]
public void TestSegmentMissingInTraceContextUsingRuntimeError()
{
var recorder = new AWSXRayRecorder();
recorder.ContextMissingStrategy = ContextMissingStrategy.RUNTIME_ERROR;
try
{
recorder.EndSegment();
Assert.Fail();
}
catch (EntityNotAvailableException)
{
// Expected;
}
try
{
recorder.BeginSubsegment("test");
Assert.Fail();
}
catch (EntityNotAvailableException)
{
// Expected;
}
try
{
recorder.EndSubsegment();
Assert.Fail();
}
catch (EntityNotAvailableException)
{
// Expected;
}
}
[TestMethod]
public void TestSegmentMissingInTraceContextUsingDefaultStrategy()
{
var recorder = new AWSXRayRecorder();
try
{
recorder.EndSegment();
}
catch (EntityNotAvailableException)
{
Assert.Fail();
}
try
{
recorder.BeginSubsegment("test");
}
catch (EntityNotAvailableException)
{
Assert.Fail();
}
try
{
recorder.EndSubsegment();
}
catch (EntityNotAvailableException)
{
Assert.Fail();
}
}
[TestMethod]
public void TestStartSegmentWithNotSampledDecision()
{
var mockEmitter = new Mock();
using (var recorder = AWSXRayRecorderFactory.CreateAWSXRayRecorder(mockEmitter.Object))
{
recorder.BeginSegment("test", TraceId, samplingResponse: new SamplingResponse(SampleDecision.NotSampled));
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
// BeginSubsegment shouldn't overwrite the segment in trace context
recorder.BeginSubsegment("sub");
Assert.ReferenceEquals(segment, AWSXRayRecorder.Instance.TraceContext.GetEntity());
// EndSubsegment shouldn't release the segment
recorder.EndSubsegment();
Assert.AreEqual(1, segment.Reference);
recorder.EndSegment();
mockEmitter.Verify(x => x.Send(It.IsAny()), Times.Never);
}
}
[TestMethod]
public void TestAddHttp()
{
_recorder.BeginSegment("test", TraceId);
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.AddHttpInformation("key", "value");
Assert.AreEqual("value", segment.Http["key"]);
_recorder.EndSegment();
}
[TestMethod]
public void TestAddHttpInvalidInput()
{
_recorder.BeginSegment("test", TraceId);
try
{
_recorder.AddHttpInformation(null, "value");
Assert.Fail();
}
catch (ArgumentException)
{
// expected
}
try
{
_recorder.AddHttpInformation(string.Empty, "value");
Assert.Fail();
}
catch (ArgumentException)
{
// expected
}
try
{
_recorder.AddHttpInformation("key", null);
Assert.Fail();
}
catch (ArgumentNullException)
{
// expected
}
}
[TestMethod]
public void TestOverwriteHttpInformationKey()
{
_recorder.BeginSegment("TestOverwriteHttpInformationKey", TraceId);
_recorder.AddHttpInformation("key", "value");
_recorder.AddHttpInformation("key", "newValue");
_recorder.EndSegment();
}
[TestMethod]
public void TestSubsegmentStreaming()
{
_recorder.BeginSegment(GetType().Name, TraceId);
var segment = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.BeginSubsegment("first 50");
for (int i = 0; i < 50; i++)
{
_recorder.BeginSubsegment("job" + i);
_recorder.EndSubsegment();
}
_recorder.EndSubsegment();
_recorder.BeginSubsegment("second 50");
for (int i = 0; i < 50; i++)
{
_recorder.BeginSubsegment("job" + i);
_recorder.EndSubsegment();
}
_recorder.EndSubsegment();
_recorder.EndSegment();
Assert.AreEqual(3, segment.Size);
}
[TestMethod]
public void TestSubsegmentStreamingParentSubsegmentDoNotGetRemoved()
{
_recorder.BeginSegment(GetType().Name, TraceId);
var segment = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.BeginSubsegment("parent");
for (int i = 0; i < 98; i++)
{
_recorder.BeginSubsegment("job" + i);
_recorder.EndSubsegment();
}
_recorder.BeginSubsegment("last job");
var lastJob = (Subsegment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
// End parent subsegment, and trigger subsegment stream
AWSXRayRecorder.Instance.TraceContext.SetEntity(lastJob.Parent);
_recorder.EndSubsegment();
Assert.AreEqual(2, segment.Size);
Assert.AreEqual(1, segment.Subsegments.Count);
Assert.AreEqual(1, segment.Subsegments[0].Subsegments.Count);
AWSXRayRecorder.Instance.TraceContext.ClearEntity();
}
[TestMethod]
public void TestAddPrecursorIdOnSubsegment()
{
_recorder.BeginSegment(GetType().Name, TraceId);
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.BeginSubsegment("child");
var newSegmentId = ThreadSafeRandom.GenerateHexNumber(16);
_recorder.AddPrecursorId(newSegmentId);
_recorder.EndSubsegment();
Assert.AreEqual(newSegmentId, segment.Subsegments[0].PrecursorIds.First());
_recorder.EndSegment();
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void TestAddInvalidPrecursorId()
{
_recorder.BeginSegment(GetType().Name, TraceId);
_recorder.BeginSubsegment("child");
_recorder.AddPrecursorId("zzzzzzzzzzzzzzzz");
}
[TestMethod]
public void TestAdd()
{
_recorder.BeginSegment(GetType().Name, TraceId);
_recorder.AddSqlInformation("key1", "value1");
_recorder.AddSqlInformation("key2", "value2");
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
Assert.AreEqual(2, segment.Sql.Count);
Assert.AreEqual("value1", segment.Sql["key1"]);
Assert.AreEqual("value2", segment.Sql["key2"]);
_recorder.EndSegment();
}
[TestMethod]
public void TestAddSqlInvalidInput()
{
_recorder.BeginSegment(GetType().Name, TraceId);
try
{
_recorder.AddSqlInformation("key", string.Empty);
Assert.Fail();
}
catch (ArgumentException)
{
// expected
}
try
{
_recorder.AddSqlInformation("key", null);
Assert.Fail();
}
catch (ArgumentException)
{
// expected
}
try
{
_recorder.AddSqlInformation(null, "value");
Assert.Fail();
}
catch (ArgumentException)
{
// expected
}
_recorder.EndSegment();
}
[TestMethod]
public void TestOverwriteSqlInformationKey()
{
_recorder.BeginSegment("TestOverwriteSqlInformationKey", TraceId);
_recorder.AddSqlInformation("key", "value");
_recorder.AddSqlInformation("key", "newValue");
_recorder.EndSegment();
}
[TestMethod]
public void TestDisableXRayTracingAndNoSegmentSent()
{
#if NETFRAMEWORK
ConfigurationManager.AppSettings[DisableXRayTracingKey] = "true";
AppSettings.Reset();
#else
_xRayOptions.IsXRayTracingDisabled = true;
#endif
Mock mockSegmentEmitter = new Mock();
#if NETFRAMEWORK
AppSettings.Reset();
#endif
using (var recorder = AWSXRayRecorderFactory.CreateAWSXRayRecorder(mockSegmentEmitter.Object))
{
#if !NETFRAMEWORK
recorder.XRayOptions = _xRayOptions;
#endif
recorder.BeginSegment("test", TraceId);
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity(); // The segment will be created even if tracing is disabled.
recorder.BeginSubsegment("test");
Assert.ReferenceEquals(segment, AWSXRayRecorder.Instance.TraceContext.GetEntity());
Assert.IsFalse(segment.IsSubsegmentsAdded);
recorder.EndSubsegment();
recorder.MarkFault();
recorder.MarkError();
recorder.MarkThrottle();
recorder.AddAnnotation("key", "value");
recorder.AddHttpInformation("key", "value");
recorder.AddPrecursorId("id");
recorder.AddSqlInformation("key", "value");
recorder.SetNamespace("namespace");
recorder.TraceMethod("method", () => AwsXrayRecorderTests.PlusOneReturn(1));
recorder.EndSegment();
mockSegmentEmitter.Verify(x => x.Send(It.IsAny()), Times.Never);
}
}
[TestMethod]
public void TestXrayContext()
{
_recorder.BeginSegment("test", TraceId);
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSegment();
IDictionary xray = (ConcurrentDictionary)segment.Aws["xray"];
var versionText =
FileVersionInfo.GetVersionInfo(Assembly.GetAssembly(typeof(AWSXRayRecorderBuilder)).Location)
.ProductVersion;
Assert.AreEqual(versionText, xray["sdk_version"]);
#if NETFRAMEWORK
Assert.AreEqual("X-Ray for .NET", xray["sdk"]);
#else
Assert.AreEqual("X-Ray for .NET Core", xray["sdk"]);
#endif
}
[TestMethod]
public void TestServiceContext()
{
_recorder.BeginSegment("test", TraceId);
var segment = (Segment)AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSegment();
#if NETFRAMEWORK
Assert.AreEqual(".NET Framework", segment.Service["runtime"]);
#else
Assert.AreEqual(".NET Core Framework", segment.Service["runtime"]);
#endif
Assert.AreEqual(Environment.Version.ToString(), segment.Service["runtime_version"]);
}
[TestMethod]
public void TestNotInitializeSamplingStrategy()
{
SamplingInput input = new SamplingInput("randomName", "testPath", "get","test","*");
_recorder.SamplingStrategy.ShouldTrace(input);
}
[TestMethod]
public void TestAddMetadata()
{
_recorder.BeginSegment("metadata", TraceId);
_recorder.AddMetadata("key1", "value1");
_recorder.AddMetadata("aws", "key2", "value2");
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSegment();
Assert.AreEqual("value1", segment.Metadata["default"]["key1"]);
Assert.AreEqual("value2", segment.Metadata["aws"]["key2"]);
}
[TestMethod]
public void TestUpdateMetadata()
{
_recorder.BeginSegment("metadata", TraceId);
_recorder.AddMetadata("key1", "value1");
_recorder.AddMetadata("key1", "updated1");
_recorder.AddMetadata("aws", "key2", "value2");
_recorder.AddMetadata("aws", "key2", "updated2");
var segment = AWSXRayRecorder.Instance.TraceContext.GetEntity();
_recorder.EndSegment();
Assert.AreEqual("updated1", segment.Metadata["default"]["key1"]);
Assert.AreEqual("updated2", segment.Metadata["aws"]["key2"]);
}
[TestMethod]
public void TestSetDaemonAddress()
{
string address = "1.2.3.4:56";
var mockEmitter = new Mock();
using (var recorder = AWSXRayRecorderFactory.CreateAWSXRayRecorder(mockEmitter.Object))
{
recorder.SetDaemonAddress(address);
}
mockEmitter.Verify(x => x.SetDaemonAddress(address), Times.Once);
}
[TestMethod]
public void TestEndSubsegmentWithSegment()
{
try
{
_recorder.BeginSegment("segment", TraceId);
_recorder.EndSubsegment();
}
catch (EntityNotAvailableException e)
{
Assert.Fail();
}
}
[TestMethod]
public void TestStartSubsegmentWithoutSegment()
{
try
{
_recorder.BeginSubsegment("subsegment");
}
catch (EntityNotAvailableException e)
{
Assert.Fail();
}
}
[TestMethod]
public void TestEndSegmentWithSubsegment()
{
try
{
_recorder.BeginSegment("segment", TraceId);
_recorder.BeginSubsegment("subsegment");
_recorder.EndSegment();
}
catch (EntityNotAvailableException e)
{
Assert.Fail();
}
}
[TestMethod]
[ExpectedException(typeof(EntityNotAvailableException))]
public void TestEndSubsegmentWithSegmentUsingRuntimeError()
{
var recorder = new AWSXRayRecorder();
recorder.ContextMissingStrategy = ContextMissingStrategy.RUNTIME_ERROR;
recorder.BeginSegment("segment", TraceId);
recorder.EndSubsegment();
}
[TestMethod]
[ExpectedException(typeof(EntityNotAvailableException))]
public void TestStartSubsegmentWithoutSegmentUsingRuntimeError()
{
var recorder = new AWSXRayRecorder();
recorder.ContextMissingStrategy = ContextMissingStrategy.RUNTIME_ERROR;
recorder.BeginSubsegment("subsegment");
}
[TestMethod]
[ExpectedException(typeof(EntityNotAvailableException))]
public void TestEndSegmentWithSubsegmentUsingRuntimeError()
{
var recorder = new AWSXRayRecorder();
recorder.ContextMissingStrategy = ContextMissingStrategy.RUNTIME_ERROR;
recorder.BeginSegment("segment", TraceId);
recorder.BeginSubsegment("subsegment");
recorder.EndSegment();
}
[TestMethod]
public void TestSuppressEntityNotAvailableException()
{
string name = StringComparison.InvariantCulture.ToString();
Assert.IsNotNull(name);
}
[TestMethod]
public void TestDefaultValueOfContextMissingStrategy()
{
Assert.AreEqual(ContextMissingStrategy.LOG_ERROR, _recorder.ContextMissingStrategy);
}
[TestMethod]
public void TestLogErrorModeForContextMissingStrategy()
{
using (var recorder = new AWSXRayRecorder())
{
recorder.ContextMissingStrategy = ContextMissingStrategy.LOG_ERROR;
recorder.EndSegment();
recorder.BeginSubsegment("no segment");
recorder.EndSubsegment();
recorder.SetNamespace("dummy namespace");
recorder.AddAnnotation("key", "value");
recorder.AddHttpInformation("key", "value");
recorder.MarkError();
recorder.MarkFault();
recorder.MarkThrottle();
recorder.AddException(new ArgumentNullException());
recorder.AddPrecursorId(Entity.GenerateId());
recorder.AddSqlInformation("sqlKey", "value");
recorder.AddMetadata("key", "value");
}
}
[TestMethod]
public void TestDefaultContextMissingStrategy()
{
// Environment.SetEnvironmentVariable(AWSXRayRecorder.EnvironmentVariableContextMissingStrategy, "log_error");
var recorder = AWSXRayRecorder.Instance;
Assert.AreEqual(ContextMissingStrategy.LOG_ERROR, recorder.ContextMissingStrategy);
}
[TestMethod]
public void TestOverrideContextMissingStrategyToRuntimeError()
{
Environment.SetEnvironmentVariable(AWSXRayRecorder.EnvironmentVariableContextMissingStrategy, "runtime_error");
using (var recorder = new AWSXRayRecorder())
{
recorder.ContextMissingStrategy = ContextMissingStrategy.LOG_ERROR;
Assert.AreEqual(ContextMissingStrategy.RUNTIME_ERROR, recorder.ContextMissingStrategy);
}
}
[TestMethod]
public void TestOverrideContextMissingStrategyToLogError()
{
Environment.SetEnvironmentVariable(AWSXRayRecorder.EnvironmentVariableContextMissingStrategy, "log_error");
using (var recorder = new AWSXRayRecorder())
{
recorder.ContextMissingStrategy = ContextMissingStrategy.RUNTIME_ERROR;
Assert.AreEqual(ContextMissingStrategy.LOG_ERROR, recorder.ContextMissingStrategy);
}
}
[TestMethod]
public void TestDefaultTraceContext()
{
var recorder = AWSXRayRecorder.Instance;
#if NETFRAMEWORK
Assert.AreEqual(typeof(CallContextContainer).FullName, recorder.TraceContext.GetType().FullName);
#else
Assert.AreEqual(typeof(AsyncLocalContextContainer).FullName, recorder.TraceContext.GetType().FullName);
#endif
}
[TestMethod]
public void TestInitializeInstanceWithRecorder1()
{
AWSXRayRecorder recorder = BuildAWSXRayRecorder(new TestSamplingStrategy());
AWSXRayRecorder.InitializeInstance(recorder: recorder);
Assert.AreEqual(AWSXRayRecorder.Instance.SamplingStrategy, recorder.SamplingStrategy); // Custom recorder set in AWSXRayRecorder.Instance.TraceContext
Assert.AreEqual(typeof(TestSamplingStrategy), recorder.SamplingStrategy.GetType()); // custom strategy set
Assert.AreEqual(typeof(UdpSegmentEmitter), recorder.Emitter.GetType()); // Default emitter set
recorder.Dispose();
}
[TestMethod]
public void TestInitializeInstanceWithRecorder2() // setting custom daemon address
{
string daemonAddress = "udp:127.0.0.2:2001 tcp:127.0.0.1:2000";
IPEndPoint expectedUDPEndpoint = new IPEndPoint(IPAddress.Parse("127.0.0.2"), 2001);
IPEndPoint expectedTCPEndpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2000);
AWSXRayRecorder recorder = BuildAWSXRayRecorder(new TestSamplingStrategy(), daemonAddress: daemonAddress);
AWSXRayRecorder.InitializeInstance(recorder: recorder);
Assert.AreEqual(AWSXRayRecorder.Instance.SamplingStrategy, recorder.SamplingStrategy);
Assert.AreEqual(typeof(TestSamplingStrategy), recorder.SamplingStrategy.GetType()); // custom strategy set
Assert.AreEqual(typeof(UdpSegmentEmitter), recorder.Emitter.GetType()); // Default emitter set
var udpEmitter = (UdpSegmentEmitter) recorder.Emitter;
Assert.AreEqual(expectedUDPEndpoint, udpEmitter.EndPoint);
recorder.Dispose();
}
[TestMethod]
public void TestInitializeInstanceWithRecorder3() // setting custom daemon address to DefaultSamplingStrategy()
{
string daemonAddress = "udp:127.0.0.2:2001 tcp:127.0.0.1:2000";
IPEndPoint expectedUDPEndpoint = new IPEndPoint(IPAddress.Parse("127.0.0.2"), 2001);
IPEndPoint expectedTCPEndpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 2000);
AWSXRayRecorder recorder = BuildAWSXRayRecorder(daemonAddress: daemonAddress);
AWSXRayRecorder.InitializeInstance(recorder: recorder);
Assert.AreEqual(AWSXRayRecorder.Instance.SamplingStrategy, recorder.SamplingStrategy);
Assert.AreEqual(typeof(DefaultSamplingStrategy), recorder.SamplingStrategy.GetType()); // Default startegy set
Assert.AreEqual(typeof(UdpSegmentEmitter), recorder.Emitter.GetType()); // Default emitter set
var udpEmitter = (UdpSegmentEmitter) recorder.Emitter;
Assert.AreEqual(expectedUDPEndpoint, udpEmitter.EndPoint);
var defaultStartegy = (DefaultSamplingStrategy) recorder.SamplingStrategy;
Assert.AreEqual(expectedUDPEndpoint,defaultStartegy.DaemonCfg.UDPEndpoint);
Assert.AreEqual(expectedTCPEndpoint, defaultStartegy.DaemonCfg.TCPEndpoint);
recorder.Dispose();
}
[TestMethod]
public void TestInitializeInstanceWithRecorde4() // Set custom trace context
{
AWSXRayRecorder recorder = BuildAWSXRayRecorder(traceContext:new DummyTraceContext());
AWSXRayRecorder.InitializeInstance(recorder: recorder);
Assert.AreEqual(typeof(DummyTraceContext), AWSXRayRecorder.Instance.TraceContext.GetType()); // Custom trace context
recorder.Dispose();
AWSXRayRecorder.Instance.Dispose();
}
[TestMethod]
public void TestDefaultStreamingStrategyWithDefaultValue()
{
IStreamingStrategy defaultStreamingStrategy = new DefaultStreamingStrategy();
AWSXRayRecorder recorder = new AWSXRayRecorderBuilder().WithStreamingStrategy(defaultStreamingStrategy).Build();
Assert.AreEqual(typeof(DefaultStreamingStrategy), recorder.StreamingStrategy.GetType());
DefaultStreamingStrategy dss = (DefaultStreamingStrategy)recorder.StreamingStrategy;
Assert.AreEqual(100, dss.MaxSubsegmentSize);
}
[TestMethod]
public void TestDefaultStreamingStrategyWithCustomValue()
{
IStreamingStrategy defaultStreamingStrategy = new DefaultStreamingStrategy(50);
AWSXRayRecorder recorder = new AWSXRayRecorderBuilder().WithStreamingStrategy(defaultStreamingStrategy).Build();
Assert.AreEqual(typeof(DefaultStreamingStrategy), recorder.StreamingStrategy.GetType());
DefaultStreamingStrategy dss = (DefaultStreamingStrategy)recorder.StreamingStrategy;
Assert.AreEqual(50, dss.MaxSubsegmentSize);
}
[TestMethod]
public void TestDefaultStreamingStrategyWithNegativeValue()
{
Assert.ThrowsException(() => new AWSXRayRecorderBuilder().WithStreamingStrategy(new DefaultStreamingStrategy(-100)));
}
[TestMethod]
public void TestBeginSegmentWithCustomTime()
{
var custom_time = new DateTime(2020, 1, 13, 21, 18, 47, 228, DateTimeKind.Utc);
AWSXRayRecorder recorder = new AWSXRayRecorderBuilder().Build();
recorder.BeginSegment("Segment1", timestamp: custom_time);
Segment segment = (Segment)recorder.TraceContext.GetEntity();
Assert.AreEqual(1578950327.228m, segment.StartTime);
recorder.EndSegment();
}
[TestMethod]
public void TestBeginSubsegmentWithCustomTime()
{
AWSXRayRecorder recorder = new AWSXRayRecorderBuilder().Build();
recorder.BeginSegment("Segment1");
var custom_time = new DateTime(2019, 07, 14);
recorder.BeginSubsegment("Subsegment1", custom_time);
Subsegment subsegment = (Subsegment)recorder.TraceContext.GetEntity();
Assert.AreEqual(1563062400, subsegment.StartTime);
recorder.EndSubsegment();
Assert.IsTrue(DateTime.UtcNow.ToUnixTimeSeconds() >= subsegment.EndTime);
recorder.EndSegment();
}
[TestMethod]
public void TestEndSubsegmentWithCustomTime()
{
AWSXRayRecorder recorder = new AWSXRayRecorderBuilder().Build();
recorder.BeginSegment("Segment1");
recorder.BeginSubsegment("Subsegment1");
Subsegment subsegment = (Subsegment)recorder.TraceContext.GetEntity();
Assert.IsTrue(DateTime.UtcNow.ToUnixTimeSeconds() >= subsegment.StartTime);
var custom_time = new DateTime(2019, 07, 14);
recorder.EndSubsegment(custom_time);
Assert.AreEqual(1563062400, subsegment.EndTime);
recorder.EndSegment();
}
public static AWSXRayRecorder BuildAWSXRayRecorder(ISamplingStrategy samplingStrategy = null, ISegmentEmitter segmentEmitter = null, string daemonAddress = null, ITraceContext traceContext = null)
{
AWSXRayRecorderBuilder builder = new AWSXRayRecorderBuilder();
if (samplingStrategy != null)
{
builder.WithSamplingStrategy(samplingStrategy);
}
if (segmentEmitter != null)
{
builder.WithSegmentEmitter(segmentEmitter);
}
if (!string.IsNullOrEmpty(daemonAddress))
{
builder.WithDaemonAddress(daemonAddress);
}
if(traceContext != null)
{
builder.WithTraceContext(traceContext);
}
var result = builder.Build();
return result;
}
public class TestSamplingStrategy : ISamplingStrategy
{
public SamplingResponse ShouldTrace(SamplingInput input)
{
throw new NotImplementedException();
}
}
public sealed class DummyEmitter : ISegmentEmitter
{
public void Dispose()
{
}
public void Send(Entity segment)
{
}
public void SetDaemonAddress(string daemonAddress)
{
}
}
private static int PlusOneReturn(int count)
{
return count + 1;
}
private static void PlusOneNoReturn(ref int count)
{
count++;
}
private static async Task PlusOneReturnAsync (int count)
{
await Task.FromResult(count++);
return count;
}
private static async Task PlusOneNoReturnAsync( int count)
{
await Task.FromResult(count++);
}
private static async Task PlusOneReturnAsyncThrowException(int count)
{
await Task.FromResult(count++);
throw new ArgumentNullException(null);
}
}
}