public async Task GrpcAiInputTests_StopsAndRestarts()
        {
            // ARRANGE
            int            batchesReceived = 0;
            TelemetryBatch receivedBatch   = null;

            int port  = Common.GetPort();
            var input = new GrpcAiInput("localhost", port);

            input.Start(telemetryBatch =>
            {
                batchesReceived++;
                receivedBatch = telemetryBatch;
            });

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcAiInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(true, port);

            TelemetryBatch batch = new TelemetryBatch();

            batch.Items.Add(new Telemetry()
            {
                Event = new Event()
                {
                    Name = "Event1"
                }
            });

            await grpcWriter.Write(batch).ConfigureAwait(false);

            Common.AssertIsTrueEventually(
                () => input.GetStats().BatchesReceived == 1 && batchesReceived == 1 &&
                receivedBatch.Items.Single().Event.Name == "Event1", GrpcAiInputTests.DefaultTimeout);

            // ACT
            input.Stop();

            Common.AssertIsTrueEventually(
                () => !input.IsRunning && input.GetStats().BatchesReceived == 1 && batchesReceived == 1 &&
                receivedBatch.Items.Single().Event.Name == "Event1", GrpcAiInputTests.DefaultTimeout);

            input.Start(telemetryBatch =>
            {
                batchesReceived++;
                receivedBatch = telemetryBatch;
            });

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcAiInputTests.DefaultTimeout));

            grpcWriter = new GrpcWriter(true, port);
            batch.Items.Single().Event.Name = "Event2";
            await grpcWriter.Write(batch).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().BatchesReceived == 1 && batchesReceived == 2 &&
                receivedBatch.Items.Single().Event.Name == "Event2", GrpcAiInputTests.DefaultTimeout);
        }
        public async Task GrpcOpenCensusInputTests_StopsAndRestarts()
        {
            // ARRANGE
            int batchesReceived             = 0;
            ExportSpanRequest receivedBatch = null;

            int port  = GetPort();
            var input = new GrpcOpenCensusInput("localhost", port);

            input.Start(exportSpanRequest =>
            {
                batchesReceived++;
                receivedBatch = exportSpanRequest;
            });

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(false, port);

            ExportSpanRequest batch = new ExportSpanRequest();

            batch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Event1"
                }
            });

            await grpcWriter.Write(batch).ConfigureAwait(false);

            Common.AssertIsTrueEventually(
                () => input.GetStats().BatchesReceived == 1 && batchesReceived == 1 &&
                receivedBatch.Spans.Single().Name.Value == "Event1", GrpcOpenCensusInputTests.DefaultTimeout);

            // ACT
            input.Stop();

            Common.AssertIsTrueEventually(
                () => !input.IsRunning && input.GetStats().BatchesReceived == 1 && batchesReceived == 1 &&
                receivedBatch.Spans.Single().Name.Value == "Event1", GrpcOpenCensusInputTests.DefaultTimeout);

            input.Start(exportSpanRequest =>
            {
                batchesReceived++;
                receivedBatch = exportSpanRequest;
            });

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));

            grpcWriter = new GrpcWriter(false, port);
            batch.Spans.Single().Name.Value = "Event2";
            await grpcWriter.Write(batch).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().BatchesReceived == 1 && batchesReceived == 2 &&
                receivedBatch.Spans.Single().Name.Value == "Event2", GrpcOpenCensusInputTests.DefaultTimeout);
        }
예제 #3
0
        public async Task HostTests_StopsLibrary()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int portAI = Common.GetPort();
            int portOC = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<LocalForwarderConfiguration>
  <Inputs>
    <ApplicationInsightsInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portAI}</Port>
    </ApplicationInsightsInput>
    <OpenCensusInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portOC}</Port>
    </OpenCensusInput>
  </Inputs>
  <OpenCensusToApplicationInsights>
    <InstrumentationKey>ikey1</InstrumentationKey>
  </OpenCensusToApplicationInsights>
</LocalForwarderConfiguration>
";

            Host host = new Host(telemetryClient);

            host.Run(config, TimeSpan.FromSeconds(5));
            Thread.Sleep(TimeSpan.FromMilliseconds(250));

            // ACT
            host.Stop();
            Thread.Sleep(TimeSpan.FromMilliseconds(250));

            var telemetryBatch = new ExportTraceServiceRequest();

            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span1"
                }, Kind = Span.Types.SpanKind.Server
            });
            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span2"
                }, Kind = Span.Types.SpanKind.Client
            });

            // ASSERT
            var writer = new GrpcWriter(false, portOC);
            await writer.Write(telemetryBatch).ConfigureAwait(false);

            Assert.Fail();
        }
예제 #4
0
        public async Task HostTests_RestartsLibraryIfStoppedUnexpectedly()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int port = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<Configuration>
    <Host>0.0.0.0</Host>
    <Port>{port}</Port>
    <InstrumentationKey>[SPECIFY INSTRUMENTATION KEY HERE]</InstrumentationKey>
    <LiveMetricsStreamAuthenticationApiKey></LiveMetricsStreamAuthenticationApiKey>
    <Watchlist>
        <Namespaces>default</Namespaces>
    </Watchlist>
    <AdaptiveSampling Enabled=""true"">
      <MaxEventsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_EVENTS_LIMIT%</MaxEventsPerSecond>
      <!--Telemetry items other than events are counted together-->
      <MaxOtherItemsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_LIMIT%</MaxOtherItemsPerSecond>
    </AdaptiveSampling>
</Configuration>
";

            Host host = new Host(telemetryClient);

            host.Run(config, TimeSpan.FromSeconds(1));

            FieldInfo libraryFieldInfo = host.GetType().GetField("library", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

            Common.AssertIsTrueEventually(() => libraryFieldInfo.GetValue(host) != null);

            // ACT
            // stop the existing library (as if something went wrong)
            var library = libraryFieldInfo.GetValue(host) as Library;

            library.Stop();

            Common.AssertIsTrueEventually(() => !library.IsRunning);

            // ASSERT
            // wait for a new library
            Common.AssertIsTrueEventually(() => libraryFieldInfo.GetValue(host) != null);
            Common.AssertIsTrueEventually(() => (libraryFieldInfo.GetValue(host) as Library).IsRunning);

            // verify the new library works
            var request = new HandleTraceSpanRequest();

            request.Instances.Add(Common.GetStandardInstanceMsg());

            var writer = new GrpcWriter(port);
            await writer.Write(request).ConfigureAwait(false);

            Common.AssertIsTrueEventually(() => sentItems.Count == 2);

            Assert.AreEqual("source-1", (sentItems.Skip(0).First() as DependencyTelemetry).Context.Cloud.RoleInstance);
            Assert.AreEqual("destination-1", (sentItems.Skip(1).First() as RequestTelemetry).Context.Cloud.RoleInstance);
        }
예제 #5
0
        public async Task GrpcInputTests_StopsAndRestarts()
        {
            // ARRANGE
            int         instancesReceived = 0;
            InstanceMsg receivedInstance  = null;

            int port  = Common.GetPort();
            var input = new GrpcInput("localhost", port, instance =>
            {
                instancesReceived++;
                receivedInstance = instance;
            });

            input.Start();

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(port);

            var request = new HandleTraceSpanRequest();

            request.Instances.Add(new InstanceMsg()
            {
                SourceName = "SourceName1"
            });

            await grpcWriter.Write(request).ConfigureAwait(false);

            Common.AssertIsTrueEventually(
                () => input.GetStats().InstancesReceived == 1 && instancesReceived == 1 &&
                receivedInstance.SourceName == "SourceName1", GrpcInputTests.DefaultTimeout);

            // ACT
            input.Stop();

            Common.AssertIsTrueEventually(
                () => !input.IsRunning && input.GetStats().InstancesReceived == 1 && instancesReceived == 1 &&
                receivedInstance.SourceName == "SourceName1", GrpcInputTests.DefaultTimeout);

            input.Start();

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcInputTests.DefaultTimeout));

            grpcWriter = new GrpcWriter(port);
            request.Instances.Single().SourceName = "SourceName2";
            await grpcWriter.Write(request).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().InstancesReceived == 1 && instancesReceived == 2 &&
                receivedInstance.SourceName == "SourceName2", GrpcInputTests.DefaultTimeout);
        }
        public async Task GrpcOpenCensusInputTests_ReceivesConfigWithNode()
        {
            // ARRANGE
            int configsReceived = 0;
            CurrentLibraryConfig receivedConfigRequest = null;

            int port  = GetPort();
            var input = new GrpcOpenCensusInput("localhost", port);

            input.Start(
                (telemetryBatch, callContext) => { },
                (configRequest, callContext) =>
            {
                configsReceived++;
                receivedConfigRequest = configRequest;
                return(ConfigResponse);
            });
            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(false, port);

            // ACT
            CurrentLibraryConfig request =
                new CurrentLibraryConfig
            {
                Config = new TraceConfig {
                    RateLimitingSampler = new RateLimitingSampler {
                        Qps = 1
                    }
                },
                Node = new Node {
                    Identifier = new ProcessIdentifier {
                        Pid = 2
                    }
                }
            };

            await grpcWriter.Write(request).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.GetStats().ConfigsReceived == 1 && configsReceived == 1 &&
                receivedConfigRequest.Node.Identifier.Pid == 2 &&
                receivedConfigRequest.Config.RateLimitingSampler.Qps == 1,
                GrpcOpenCensusInputTests.DefaultTimeout);

            input.Stop();
            Assert.IsTrue(SpinWait.SpinUntil(() => !input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));
        }
예제 #7
0
        public async Task HostTests_StopsLibrary()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int port = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<Configuration>
    <Host>0.0.0.0</Host>
    <Port>{port}</Port>
    <InstrumentationKey>[SPECIFY INSTRUMENTATION KEY HERE]</InstrumentationKey>
    <LiveMetricsStreamAuthenticationApiKey></LiveMetricsStreamAuthenticationApiKey>
    <AdaptiveSampling Enabled=""true"">
      <MaxEventsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_EVENTS_LIMIT%</MaxEventsPerSecond>
      <!--Telemetry items other than events are counted together-->
      <MaxOtherItemsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_LIMIT%</MaxOtherItemsPerSecond>
    </AdaptiveSampling>
</Configuration>
";

            Host host = new Host(telemetryClient);

            host.Run(config, TimeSpan.FromSeconds(5));
            Thread.Sleep(TimeSpan.FromMilliseconds(250));

            // ACT
            host.Stop();
            Thread.Sleep(TimeSpan.FromMilliseconds(250));

            var request = new HandleTraceSpanRequest();

            request.Instances.Add(new InstanceMsg()
            {
                HttpStatusCode = 203,
                SpanTags       = { { "source.name",      new Value {
                                         StringValue = "some-app-1"
                                     } }, { "destination.name", new Value {
                                                StringValue = "some-other-app-1"
                                            } } }
            });

            // ASSERT
            var writer = new GrpcWriter(port);
            await writer.Write(request).ConfigureAwait(false);

            Assert.Fail();
        }
예제 #8
0
        public async Task GrpcAiInputTests_ReceivesDataFromMultipleClients()
        {
            // ARRANGE
            int            batchesReceived = 0;
            TelemetryBatch receivedBatch   = null;

            int port  = Common.GetPort();
            var input = new GrpcAiInput("localhost", port);

            input.Start(
                (telemetryBatch, callContext) =>
            {
                Interlocked.Increment(ref batchesReceived);
                receivedBatch = telemetryBatch;
            },
                null);
            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcAiInputTests.DefaultTimeout));

            // ACT
            TelemetryBatch batch = new TelemetryBatch();

            batch.Items.Add(new Telemetry()
            {
                Event = new Event()
                {
                    Name = "Event1"
                }
            });

            Parallel.For(0, 1000, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 1000
            }, async i =>
            {
                var grpcWriter = new GrpcWriter(true, port);

                await grpcWriter.Write(batch).ConfigureAwait(false);
            });

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.GetStats().BatchesReceived == 1000 && batchesReceived == 1000, GrpcAiInputTests.DefaultTimeout);

            input.Stop();
            Assert.IsTrue(SpinWait.SpinUntil(() => !input.IsRunning, GrpcAiInputTests.DefaultTimeout));
        }
        public async Task GrpcOpenCensusInputTests_ReceivesSpansWithNode()
        {
            // ARRANGE
            int batchesReceived = 0;
            ExportTraceServiceRequest receivedBatch = null;

            int port  = GetPort();
            var input = new GrpcOpenCensusInput("localhost", port);

            input.Start(
                (telemetryBatch, callContext) =>
            {
                batchesReceived++;
                receivedBatch = telemetryBatch;
            },
                null);
            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(false, port);

            // ACT
            ExportTraceServiceRequest batch = new ExportTraceServiceRequest();

            batch.Spans.Add(new Span {
                Name = new TruncatableString {
                    Value = "Event1"
                }
            });
            batch.Node = new Node {
                Identifier = new ProcessIdentifier {
                    Pid = 2
                }
            };

            await grpcWriter.Write(batch).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.GetStats().BatchesReceived == 1 && batchesReceived == 1 &&
                receivedBatch.Node.Identifier.Pid == 2 &&
                receivedBatch.Spans.Single().Name.Value == "Event1",
                GrpcOpenCensusInputTests.DefaultTimeout);

            input.Stop();
            Assert.IsTrue(SpinWait.SpinUntil(() => !input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));
        }
        public void GrpcOpenCensusInputTests_ReceivesDataFromMultipleClients()
        {
            // ARRANGE
            int batchesReceived = 0;
            ExportTraceServiceRequest receivedBatch = null;

            int port  = GetPort();
            var input = new GrpcOpenCensusInput("localhost", port);

            input.Start(
                (exportSpanRequest, callContext) =>
            {
                Interlocked.Increment(ref batchesReceived);
                receivedBatch = exportSpanRequest;
            },
                (configRequest, callContext) => ConfigResponse);
            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));

            // ACT
            ExportTraceServiceRequest batch = new ExportTraceServiceRequest();

            batch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Event1"
                }
            });

            Parallel.For(0, 1000, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 1000
            }, async i =>
            {
                var grpcWriter = new GrpcWriter(false, port);

                await grpcWriter.Write(batch).ConfigureAwait(false);
            });

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.GetStats().BatchesReceived == 1000 && batchesReceived == 1000, GrpcOpenCensusInputTests.DefaultTimeout);

            input.Stop();
            Assert.IsTrue(SpinWait.SpinUntil(() => !input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));
        }
        public async Task LibraryTests_LibraryProcessesRequestsCorrectly()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int port = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<Configuration>
    <Host>0.0.0.0</Host>
    <Port>{port}</Port>
    <InstrumentationKey>ikey1</InstrumentationKey>
    <LiveMetricsStreamAuthenticationApiKey></LiveMetricsStreamAuthenticationApiKey>
    <Watchlist>
        <Namespaces>default</Namespaces>
    </Watchlist>
    <AdaptiveSampling Enabled=""true"">
      <MaxEventsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_EVENTS_LIMIT%</MaxEventsPerSecond>
      <!--Telemetry items other than events are counted together-->
      <MaxOtherItemsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_LIMIT%</MaxOtherItemsPerSecond>
    </AdaptiveSampling>
</Configuration>
";

            var request = new HandleTraceSpanRequest();

            request.Instances.Add(Common.GetStandardInstanceMsg());

            var lib = new Library(config, telemetryClient);

            lib.Run();

            // ACT
            var writer = new GrpcWriter(port);
            await writer.Write(request).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(() => sentItems.Count == 2);

            lib.Stop();

            Assert.AreEqual("source-1", (sentItems.Skip(0).First() as DependencyTelemetry).Context.Cloud.RoleInstance);
            Assert.AreEqual("destination-1", (sentItems.Skip(1).First() as RequestTelemetry).Context.Cloud.RoleInstance);
        }
예제 #12
0
        public void GrpcInputTests_ReceivesDataFromMultipleClients()
        {
            // ARRANGE
            int         instancesReceived = 0;
            InstanceMsg receivedInstance  = null;

            int port  = Common.GetPort();
            var input = new GrpcInput("localhost", port, instance =>
            {
                Interlocked.Increment(ref instancesReceived);
                receivedInstance = instance;
            });

            input.Start();
            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcInputTests.DefaultTimeout));

            // ACT
            var request = new HandleTraceSpanRequest();

            request.Instances.Add(new InstanceMsg()
            {
                SourceName = "SourceName1"
            });

            Parallel.For(0, 1000, new ParallelOptions()
            {
                MaxDegreeOfParallelism = 1000
            }, async i =>
            {
                var grpcWriter = new GrpcWriter(port);

                await grpcWriter.Write(request).ConfigureAwait(false);
            });

            // ASSERT
            Common.AssertIsTrueEventually(
                () => input.GetStats().InstancesReceived == 1000 && instancesReceived == 1000, GrpcInputTests.DefaultTimeout);

            input.Stop();
            Assert.IsTrue(SpinWait.SpinUntil(() => !input.IsRunning, GrpcInputTests.DefaultTimeout));
        }
        public async Task GrpcOpenCensusInputTests_HandlesExceptionsInProcessingHandler()
        {
            // ARRANGE
            int port  = GetPort();
            var input = new GrpcOpenCensusInput("localhost", port);

            input.Start(exportSpanRequest => throw new InvalidOperationException());

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(false, port);

            ExportSpanRequest batch = new ExportSpanRequest();

            batch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Event1"
                }
            });

            // ACT
            await grpcWriter.Write(batch).ConfigureAwait(false);

            // ASSERT

            // must have handled the exception by logging it
            // should still be able to process items
            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().BatchesReceived == 0 && input.GetStats().BatchesFailed == 1,
                GrpcOpenCensusInputTests.DefaultTimeout);

            await grpcWriter.Write(batch).ConfigureAwait(false);

            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().BatchesReceived == 0 && input.GetStats().BatchesFailed == 2,
                GrpcOpenCensusInputTests.DefaultTimeout);
        }
예제 #14
0
        public async Task GrpcAiInputTests_HandlesExceptionsInProcessingHandler()
        {
            // ARRANGE
            int port  = Common.GetPort();
            var input = new GrpcAiInput("localhost", port);

            input.Start((telemetryBatch, callContext) => throw new InvalidOperationException(), null);

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcAiInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(true, port);

            TelemetryBatch batch = new TelemetryBatch();

            batch.Items.Add(new Telemetry()
            {
                Event = new Event {
                    Name = "Event1"
                }
            });

            // ACT
            await grpcWriter.Write(batch).ConfigureAwait(false);

            // ASSERT

            // must have handled the exception by logging it
            // should still be able to process items
            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().BatchesReceived == 0 && input.GetStats().BatchesFailed == 1,
                GrpcAiInputTests.DefaultTimeout);

            await grpcWriter.Write(batch).ConfigureAwait(false);

            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().BatchesReceived == 0 && input.GetStats().BatchesFailed == 2,
                GrpcAiInputTests.DefaultTimeout);
        }
        public async Task GrpcOpenCensusInputTests_HandlesExceptionsInConfigRequestsProcessingHandler()
        {
            // ARRANGE
            int port  = GetPort();
            var input = new GrpcOpenCensusInput("localhost", port);

            input.Start((exportSpanRequest, callContext) => { }, (cr, cc) => throw new InvalidOperationException());

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcOpenCensusInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(false, port);

            CurrentLibraryConfig configRequest = new CurrentLibraryConfig
            {
                Config = new TraceConfig {
                    RateLimitingSampler = new RateLimitingSampler {
                        Qps = 1
                    }
                }
            };

            // ACT
            await grpcWriter.Write(configRequest).ConfigureAwait(false);

            // ASSERT

            // must have handled the exception by logging it
            // should still be able to process items
            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().ConfigsReceived == 0 && input.GetStats().ConfigsFailed == 1,
                GrpcOpenCensusInputTests.DefaultTimeout);

            await grpcWriter.Write(configRequest).ConfigureAwait(false);

            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().ConfigsReceived == 0 && input.GetStats().ConfigsFailed == 2,
                GrpcOpenCensusInputTests.DefaultTimeout);
        }
예제 #16
0
        public async Task GrpcInputTests_HandlesExceptionsInProcessingHandler()
        {
            // ARRANGE
            int port  = Common.GetPort();
            var input = new GrpcInput("localhost", port, instance => throw new InvalidOperationException());

            input.Start();

            Assert.IsTrue(SpinWait.SpinUntil(() => input.IsRunning, GrpcInputTests.DefaultTimeout));

            var grpcWriter = new GrpcWriter(port);

            var request = new HandleTraceSpanRequest();

            request.Instances.Add(new InstanceMsg()
            {
                SourceName = "SourceName1"
            });

            // ACT
            await grpcWriter.Write(request).ConfigureAwait(false);

            // ASSERT

            // must have handled the exception by logging it
            // should still be able to process items
            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().InstancesReceived == 0 && input.GetStats().InstancesFailed == 1,
                GrpcInputTests.DefaultTimeout);

            await grpcWriter.Write(request).ConfigureAwait(false);

            Common.AssertIsTrueEventually(
                () => input.IsRunning && input.GetStats().InstancesReceived == 0 && input.GetStats().InstancesFailed == 2,
                GrpcInputTests.DefaultTimeout);
        }
예제 #17
0
        public async Task HostTests_RunsLibrary()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int portAI = Common.GetPort();
            int portOC = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<LocalForwarderConfiguration>
  <Inputs>
    <ApplicationInsightsInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portAI}</Port>
    </ApplicationInsightsInput>
    <OpenCensusInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portOC}</Port>
    </OpenCensusInput>
  </Inputs>
  <OpenCensusToApplicationInsights>
    <InstrumentationKey>ikey1</InstrumentationKey>
  </OpenCensusToApplicationInsights>
  <ApplicationInsights>
    <LiveMetricsStreamInstrumentationKey>ikey1</LiveMetricsStreamInstrumentationKey>
    <LiveMetricsStreamAuthenticationApiKey></LiveMetricsStreamAuthenticationApiKey>
    <AdaptiveSampling Enabled=""false"">
      <MaxEventsPerSecond>%APPINSIGHTS_ADAPTIVESAMPLINGEVENTSLIMIT%</MaxEventsPerSecond>
      <!--Telemetry items other than events are counted together-->
      <MaxOtherItemsPerSecond>%APPINSIGHTS_ADAPTIVESAMPLINGNONEVENTSLIMIT%</MaxOtherItemsPerSecond>
    </AdaptiveSampling>
  </ApplicationInsights>
</LocalForwarderConfiguration>
";

            // ACT
            Host host = new Host(telemetryClient);

            host.Run(config, TimeSpan.FromSeconds(5));

            Thread.Sleep(TimeSpan.FromMilliseconds(250));

            var telemetryBatch = new ExportTraceServiceRequest();

            telemetryBatch.Spans.Add(new Span {
                Name = new TruncatableString {
                    Value = "Span1"
                }, Kind = Span.Types.SpanKind.Server
            });
            telemetryBatch.Spans.Add(new Span {
                Name = new TruncatableString {
                    Value = "Span2"
                }, Kind = Span.Types.SpanKind.Client
            });
            telemetryBatch.Node = new Node {
                ServiceInfo = new ServiceInfo {
                    Name = "tests"
                }
            };

            var configRequest = new CurrentLibraryConfig
            {
                Config = new TraceConfig
                {
                    RateLimitingSampler = new RateLimitingSampler {
                        Qps = 1
                    }
                }
            };

            var writer = new GrpcWriter(false, portOC);
            await writer.Write(telemetryBatch).ConfigureAwait(false);

            await writer.Write(configRequest).ConfigureAwait(false);

            Common.AssertIsTrueEventually(() => sentItems.Count == 3);

            // ASSERT
            Assert.AreEqual("tests", (sentItems.Skip(0).First() as EventTelemetry).Context.Cloud.RoleName);
            Assert.AreEqual("Span1", (sentItems.Skip(1).First() as RequestTelemetry).Name);
            Assert.AreEqual("Span2", (sentItems.Skip(2).First() as DependencyTelemetry).Name);
        }
예제 #18
0
        public async Task HostTests_RestartsLibraryIfStoppedUnexpectedly()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int portAI = Common.GetPort();
            int portOC = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<LocalForwarderConfiguration>
  <Inputs>
    <ApplicationInsightsInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portAI}</Port>
    </ApplicationInsightsInput>
    <OpenCensusInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portOC}</Port>
    </OpenCensusInput>
  </Inputs>
  <OpenCensusToApplicationInsights>
    <InstrumentationKey>ikey1</InstrumentationKey>
  </OpenCensusToApplicationInsights>
  <ApplicationInsights>
    <LiveMetricsStreamInstrumentationKey>ikey1</LiveMetricsStreamInstrumentationKey>
    <LiveMetricsStreamAuthenticationApiKey></LiveMetricsStreamAuthenticationApiKey>
    <AdaptiveSampling Enabled=""false"">
      <MaxEventsPerSecond>%APPINSIGHTS_ADAPTIVESAMPLINGEVENTSLIMIT%</MaxEventsPerSecond>
      <!--Telemetry items other than events are counted together-->
      <MaxOtherItemsPerSecond>%APPINSIGHTS_ADAPTIVESAMPLINGNONEVENTSLIMIT%</MaxOtherItemsPerSecond>
    </AdaptiveSampling>
  </ApplicationInsights>
</LocalForwarderConfiguration>
";

            Host host = new Host(telemetryClient);

            host.Run(config, TimeSpan.FromSeconds(1));

            FieldInfo libraryFieldInfo = host.GetType().GetField("library", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);

            Common.AssertIsTrueEventually(() => libraryFieldInfo.GetValue(host) != null);

            // ACT
            // stop the existing library (as if something went wrong)
            var library = libraryFieldInfo.GetValue(host) as Library;

            library.Stop();

            Common.AssertIsTrueEventually(() => !library.IsRunning);

            // ASSERT
            // wait for a new library
            Common.AssertIsTrueEventually(() => libraryFieldInfo.GetValue(host) != null);
            Common.AssertIsTrueEventually(() => (libraryFieldInfo.GetValue(host) as Library).IsRunning);

            // verify the new library works
            var telemetryBatch = new ExportTraceServiceRequest();

            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span1"
                }, Kind = Span.Types.SpanKind.Server
            });
            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span2"
                }, Kind = Span.Types.SpanKind.Client
            });

            var writer = new GrpcWriter(false, portOC);
            await writer.Write(telemetryBatch).ConfigureAwait(false);

            Common.AssertIsTrueEventually(() => sentItems.Count == 2);

            Assert.AreEqual("Span1", (sentItems.Skip(0).First() as RequestTelemetry).Name);
            Assert.AreEqual("Span2", (sentItems.Skip(1).First() as DependencyTelemetry).Name);
        }
        public async Task LibraryTests_LibraryLogsInputStatsCorrectly()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int portAI = Common.GetPort();
            int portOC = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<LocalForwarderConfiguration>
  <Inputs>
    <ApplicationInsightsInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portAI}</Port>
    </ApplicationInsightsInput>
    <OpenCensusInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portOC}</Port>
    </OpenCensusInput>
  </Inputs>
  <OpenCensusToApplicationInsights>
    <InstrumentationKey>ikey1</InstrumentationKey>
  </OpenCensusToApplicationInsights>
  <ApplicationInsights>
    <LiveMetricsStreamInstrumentationKey>[SPECIFY LIVE METRICS STREAM INSTRUMENTATION KEY HERE]</LiveMetricsStreamInstrumentationKey>
    <LiveMetricsStreamAuthenticationApiKey></LiveMetricsStreamAuthenticationApiKey>
    <AdaptiveSampling Enabled=""true"">
      <MaxEventsPerSecond>%APPINSIGHTS_ADAPTIVESAMPLINGEVENTSLIMIT%</MaxEventsPerSecond>
      <!--Telemetry items other than events are counted together-->
      <MaxOtherItemsPerSecond>%APPINSIGHTS_ADAPTIVESAMPLINGNONEVENTSLIMIT%</MaxOtherItemsPerSecond>
    </AdaptiveSampling>
  </ApplicationInsights>
</LocalForwarderConfiguration>
";

            var telemetryBatchAI = new TelemetryBatch();

            telemetryBatchAI.Items.Add(new Telemetry()
            {
                Event = new Event()
                {
                    Name = "Event1"
                }
            });
            telemetryBatchAI.Items.Add(new Telemetry()
            {
                Message = new Message()
                {
                    Message_ = "Message1"
                }
            });
            telemetryBatchAI.Items.Add(new Telemetry()
            {
                Metric = new LocalForwarder.Library.Inputs.Contracts.Metric()
                {
                    Metrics = { new DataPoint()
                                {
                                    Name = "Metric1", Value = 1
                                } }
                }
            });
            telemetryBatchAI.Items.Add(new Telemetry()
            {
                Exception = new LocalForwarder.Library.Inputs.Contracts.Exception()
                {
                    ProblemId = "Exception1", Exceptions = { new ExceptionDetails()
                                                             {
                                                                 Message = "Exception1"
                                                             } }
                }
            });
            telemetryBatchAI.Items.Add(new Telemetry()
            {
                Dependency = new Dependency()
                {
                    Name = "Dependency1"
                }
            });
            telemetryBatchAI.Items.Add(new Telemetry()
            {
                Availability = new Availability()
                {
                    Name = "Availability1"
                }
            });
            telemetryBatchAI.Items.Add(new Telemetry()
            {
                PageView = new PageView()
                {
                    Id = "PageView1"
                }
            });
            telemetryBatchAI.Items.Add(new Telemetry()
            {
                Request = new Request()
                {
                    Name = "Request1"
                }
            });

            var telemetryBatchOC = new ExportTraceServiceRequest();

            telemetryBatchOC.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span1"
                }, Kind = Span.Types.SpanKind.Server
            });
            telemetryBatchOC.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span2"
                }, Kind = Span.Types.SpanKind.Client
            });

            // redirect loggging to a new file
            Diagnostics.Flush(TimeSpan.FromSeconds(5));
            string logFileName = Common.SwitchLoggerToDifferentFile();

            var lib = new Library(config, telemetryClient, TimeSpan.FromMilliseconds(10));

            lib.Run();

            // ACT
            var writer = new GrpcWriter(true, portAI);
            await writer.Write(telemetryBatchAI).ConfigureAwait(false);

            writer = new GrpcWriter(false, portOC);
            await writer.Write(telemetryBatchOC).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(() => sentItems.Count == 10);

            await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);

            lib.Stop();

            Diagnostics.Flush(TimeSpan.FromSeconds(5));

            // close the file
            Common.SwitchLoggerToDifferentFile();

            string logs = await File.ReadAllTextAsync(logFileName).ConfigureAwait(false);

            Assert.IsTrue(logs.Contains("|INFO|AI input: [ConnectionCount: 0, BatchesReceived: 0, BatchesFailed: 0, ConfigsReceived: 0, ConfigsFailed: 0]"));
            Assert.IsTrue(logs.Contains("|INFO|OpenCensus input: [ConnectionCount: 0, BatchesReceived: 0, BatchesFailed: 0, ConfigsReceived: 0, ConfigsFailed: 0]"));

            Assert.IsTrue(logs.Contains("|INFO|AI input: [ConnectionCount: 0, BatchesReceived: 1, BatchesFailed: 0, ConfigsReceived: 0, ConfigsFailed: 0]"));
            Assert.IsTrue(logs.Contains("|INFO|OpenCensus input: [ConnectionCount: 0, BatchesReceived: 1, BatchesFailed: 0, ConfigsReceived: 0, ConfigsFailed: 0]"));

            Assert.IsFalse(logs.Contains("|INFO|AI input: [ConnectionCount: 0, BatchesReceived: 2, BatchesFailed, ConfigsReceived: 0, ConfigsFailed: 0]"));
            Assert.IsFalse(logs.Contains("|INFO|OpenCensus input: [ConnectionCount: 0, BatchesReceived: 2, BatchesFailed, ConfigsReceived: 0, ConfigsFailed: 0]"));
        }
        public async Task HostTests_RunsLibrary()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int portAI = Common.GetPort();
            int portOC = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<LocalForwarderConfiguration>
  <Inputs>
    <ApplicationInsightsInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portAI}</Port>
    </ApplicationInsightsInput>
    <OpenCensusInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portOC}</Port>
    </OpenCensusInput>
  </Inputs>
  <OpenCensusToApplicationInsights>
    <InstrumentationKey>ikey1</InstrumentationKey>
  </OpenCensusToApplicationInsights>
  <ApplicationInsights>
    <LiveMetricsStreamInstrumentationKey>ikey1</LiveMetricsStreamInstrumentationKey>
  </ApplicationInsights>
</LocalForwarderConfiguration>
";

            // ACT
            Host host = new Host(telemetryClient);

            host.Run(config, TimeSpan.FromSeconds(5));

            Thread.Sleep(TimeSpan.FromMilliseconds(250));

            var telemetryBatch = new ExportSpanRequest();

            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span1"
                }, Kind = Span.Types.SpanKind.Server
            });
            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span2"
                }, Kind = Span.Types.SpanKind.Client
            });

            var writer = new GrpcWriter(false, portOC);
            await writer.Write(telemetryBatch).ConfigureAwait(false);

            Common.AssertIsTrueEventually(() => sentItems.Count == 2);

            // ASSERT
            Assert.AreEqual("Span1", (sentItems.Skip(0).First() as RequestTelemetry).Name);
            Assert.AreEqual("Span2", (sentItems.Skip(1).First() as DependencyTelemetry).Name);
        }
        public async Task LibraryTests_LibraryLogsInputStatsCorrectly()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int port = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<Configuration>
    <Host>0.0.0.0</Host>
    <Port>{port}</Port>
    <InstrumentationKey>ikey1</InstrumentationKey>
    <LiveMetricsStreamAuthenticationApiKey></LiveMetricsStreamAuthenticationApiKey>
    <Watchlist>
        <Namespaces>default</Namespaces>
    </Watchlist>
    <AdaptiveSampling Enabled=""true"">
      <MaxEventsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_EVENTS_LIMIT%</MaxEventsPerSecond>
      <!--Telemetry items other than events are counted together-->
      <MaxOtherItemsPerSecond>%ISTIO_MIXER_PLUGIN_AI_ADAPTIVE_SAMPLING_LIMIT%</MaxOtherItemsPerSecond>
    </AdaptiveSampling>
</Configuration>
";

            var request = new HandleTraceSpanRequest();

            request.Instances.Add(Common.GetStandardInstanceMsg());
            request.Instances.Add(Common.GetStandardInstanceMsg());


            // redirect loggging to a new file
            Diagnostics.Flush(TimeSpan.FromSeconds(5));
            string logFileName = Common.SwitchLoggerToDifferentFile();

            var lib = new Library(config, telemetryClient, TimeSpan.FromMilliseconds(10));

            lib.Run();

            // ACT
            var writer = new GrpcWriter(port);
            await writer.Write(request).ConfigureAwait(false);

            await writer.Write(request).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(() => sentItems.Count == 8);

            await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);

            lib.Stop();

            Diagnostics.Flush(TimeSpan.FromSeconds(5));

            // close the file
            Common.SwitchLoggerToDifferentFile();

            string logs = await File.ReadAllTextAsync(logFileName).ConfigureAwait(false);

            Assert.IsTrue(logs.Contains("|INFO|Istio's Mixer input: [ConnectionCount: 0, RequestsReceived: 0, InstancesSucceeded: 0, InstancesFailed: 0]"));
            Assert.IsTrue(logs.Contains("|INFO|Istio's Mixer input: [ConnectionCount: 0, RequestsReceived: 2, InstancesSucceeded: 4, InstancesFailed: 0]"));
        }
예제 #22
0
        public async Task LibraryTests_LibraryProcessesAiBatchesCorrectly()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int portAI = Common.GetPort();
            int portOC = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<LocalForwarderConfiguration>
  <Inputs>
    <ApplicationInsightsInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portAI}</Port>
    </ApplicationInsightsInput>
    <OpenCensusInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portOC}</Port>
    </OpenCensusInput>
  </Inputs>
  <OpenCensusToApplicationInsights>
    <InstrumentationKey>ikey1</InstrumentationKey>
  </OpenCensusToApplicationInsights>
  <ApplicationInsights>
    <LiveMetricsStreamInstrumentationKey>[SPECIFY LIVE METRICS STREAM INSTRUMENTATION KEY HERE]</LiveMetricsStreamInstrumentationKey>
  </ApplicationInsights>
</LocalForwarderConfiguration>
";

            var telemetryBatch = new TelemetryBatch();

            telemetryBatch.Items.Add(new Telemetry()
            {
                Event = new Event()
                {
                    Name = "Event1"
                }
            });
            telemetryBatch.Items.Add(new Telemetry()
            {
                Message = new Message()
                {
                    Message_ = "Message1"
                }
            });
            telemetryBatch.Items.Add(new Telemetry()
            {
                Metric = new LocalForwarder.Library.Inputs.Contracts.Metric()
                {
                    Metrics = { new DataPoint()
                                {
                                    Name = "Metric1", Value = 1
                                } }
                }
            });
            telemetryBatch.Items.Add(new Telemetry()
            {
                Exception = new LocalForwarder.Library.Inputs.Contracts.Exception()
                {
                    ProblemId = "Exception1", Exceptions = { new ExceptionDetails()
                                                             {
                                                                 Message = "Exception1"
                                                             } }
                }
            });
            telemetryBatch.Items.Add(new Telemetry()
            {
                Dependency = new Dependency()
                {
                    Name = "Dependency1"
                }
            });
            telemetryBatch.Items.Add(new Telemetry()
            {
                Availability = new Availability()
                {
                    Name = "Availability1"
                }
            });
            telemetryBatch.Items.Add(new Telemetry()
            {
                PageView = new PageView()
                {
                    Id = "PageView1"
                }
            });
            telemetryBatch.Items.Add(new Telemetry()
            {
                Request = new Request()
                {
                    Name = "Request1"
                }
            });

            var lib = new Library(config, telemetryClient);

            lib.Run();

            // ACT
            var writer = new GrpcWriter(true, portAI);
            await writer.Write(telemetryBatch).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(() => sentItems.Count == 8);

            lib.Stop();

            Assert.AreEqual("Event1", (sentItems.Skip(0).First() as EventTelemetry).Name);
            Assert.AreEqual("Message1", (sentItems.Skip(1).First() as TraceTelemetry).Message);
            Assert.AreEqual("Metric1", (sentItems.Skip(2).First() as MetricTelemetry).Name);
            Assert.AreEqual(1, (sentItems.Skip(2).First() as MetricTelemetry).Value);
            Assert.AreEqual("Exception1", (sentItems.Skip(3).First() as ExceptionTelemetry).ProblemId);
            Assert.AreEqual("Exception1", (sentItems.Skip(3).First() as ExceptionTelemetry).ExceptionDetailsInfoList.Single().Message);
            Assert.AreEqual("Dependency1", (sentItems.Skip(4).First() as DependencyTelemetry).Name);
            Assert.AreEqual("Availability1", (sentItems.Skip(5).First() as AvailabilityTelemetry).Name);
            Assert.AreEqual("PageView1", (sentItems.Skip(6).First() as PageViewTelemetry).Id);
            Assert.AreEqual("Request1", (sentItems.Skip(7).First() as RequestTelemetry).Name);
        }
예제 #23
0
        public async Task LibraryTests_LibraryProcessesOcBatchesCorrectly()
        {
            // ARRANGE
            var telemetryClient = Common.SetupStubTelemetryClient(out var sentItems);

            int portAI = Common.GetPort();
            int portOC = Common.GetPort();

            var config = $@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<LocalForwarderConfiguration>
  <Inputs>
    <ApplicationInsightsInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portAI}</Port>
    </ApplicationInsightsInput>
    <OpenCensusInput Enabled=""true"">
      <Host>0.0.0.0</Host>
      <Port>{portOC}</Port>
    </OpenCensusInput>
  </Inputs>
  <OpenCensusToApplicationInsights>
    <InstrumentationKey>ikey1</InstrumentationKey>
  </OpenCensusToApplicationInsights>
  <ApplicationInsights>
    <LiveMetricsStreamInstrumentationKey>[SPECIFY LIVE METRICS STREAM INSTRUMENTATION KEY HERE]</LiveMetricsStreamInstrumentationKey>
  </ApplicationInsights>
</LocalForwarderConfiguration>
";

            var telemetryBatch = new ExportSpanRequest();

            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span1"
                }, Kind = Span.Types.SpanKind.Server
            });
            telemetryBatch.Spans.Add(new Span()
            {
                Name = new TruncatableString()
                {
                    Value = "Span2"
                }, Kind = Span.Types.SpanKind.Client
            });

            var lib = new Library(config, telemetryClient);

            lib.Run();

            // ACT
            var writer = new GrpcWriter(false, portOC);
            await writer.Write(telemetryBatch).ConfigureAwait(false);

            // ASSERT
            Common.AssertIsTrueEventually(() => sentItems.Count == 2);

            lib.Stop();

            Assert.AreEqual("Span1", (sentItems.Skip(0).First() as RequestTelemetry).Name);
            Assert.AreEqual("Span2", (sentItems.Skip(1).First() as DependencyTelemetry).Name);
        }