public void ShouldRaiseFlushFailedOnFlushAsyncWhenHttpClientFails()
        {
            var httpClient = HttpClientTestHelper.Create();
            httpClient.When(client => client.PostAsync(Arg.Any<string>(), Arg.Any<HttpContent>())).Do(action => { throw new Exception(); });

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
            using (var collectErrorsListener = new MockEventListener())
            {
                collectErrorsListener.EnableEvents(SemanticLoggingEventSource.Log, EventLevel.Error, Keywords.All);
                
                sink.OnNext(EventEntryTestHelper.Create());

                try
                {
                    sink.FlushAsync().Wait();
                    Assert.Fail("AggregateException should be thrown.");
                }
                catch (AggregateException ex)
                {
                    Assert.IsInstanceOfType(ex.InnerException, typeof(FlushFailedException));
                }

                Assert.IsTrue(collectErrorsListener.WrittenEntries.Any(x => x.EventId == 1));
            }
        }
        public void ShouldRaiseFlushFailedOnFlushAsyncWhenHttpClientFails()
        {
            var httpClient = HttpClientTestHelper.Create();

            httpClient.When(client => client.PostAsync(Arg.Any <string>(), Arg.Any <HttpContent>())).Do(action => { throw new Exception(); });

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
                using (var collectErrorsListener = new MockEventListener())
                {
                    collectErrorsListener.EnableEvents(SemanticLoggingEventSource.Log, EventLevel.Error, Keywords.All);

                    sink.OnNext(EventEntryTestHelper.Create());

                    try
                    {
                        sink.FlushAsync().Wait();
                        Assert.Fail("AggregateException should be thrown.");
                    }
                    catch (AggregateException ex)
                    {
                        Assert.IsInstanceOfType(ex.InnerException, typeof(FlushFailedException));
                    }

                    Assert.IsTrue(collectErrorsListener.WrittenEntries.Any(x => x.EventId == 1));
                }
        }
        public async Task ShouldWritePropertiesForBatchMessage()
        {
            var httpClient = HttpClientTestHelper.Create();

            httpClient.PostAsync(Arg.Any <string>(), Arg.Any <HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

            var entry = EventEntryTestHelper.Create();

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
            {
                sink.OnNext(entry);
                sink.OnNext(entry);

                await sink.FlushAsync();
            }

            IList <EventEntry> entries = new List <EventEntry> {
                entry, entry
            };
            var messages    = entries.Select(c => c.ToBatchMessage());
            var sendMessage = new ServiceBusHttpMessage
            {
                Body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(messages))
            };

            var byteRepresentation = sendMessage.Body;

            await httpClient.Received().PostAsync(Arg.Any <string>(), Arg.Is <HttpContent>(c => byteRepresentation.SequenceEqual(c.ReadAsByteArrayAsync().Result)));
        }
        public void ShouldNotStallOrThrowWhenHttpClientFails()
        {
            var httpClient = HttpClientTestHelper.Create();
            httpClient.PostAsync(Arg.Any<string>(), Arg.Any<HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.InternalServerError)));

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
            using (var collectErrorsListener = new MockEventListener())
            {
                collectErrorsListener.EnableEvents(SemanticLoggingEventSource.Log, EventLevel.Error, Keywords.All);
                
                sink.OnNext(EventEntryTestHelper.Create());

                Assert.IsTrue(Task.Run(() => sink.OnCompleted()).Wait(TimeSpan.FromSeconds(5)));
                Assert.IsTrue(collectErrorsListener.WrittenEntries.Any(x => x.EventId == 1));
            }
        }
        public async Task ShouldWriteEntriesOnFlushAsync()
        {
            var httpClient = HttpClientTestHelper.Create();

            httpClient.PostAsync(Arg.Any <string>(), Arg.Any <HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
            {
                sink.OnNext(EventEntryTestHelper.Create());
                sink.OnNext(EventEntryTestHelper.Create());

                await sink.FlushAsync();
            }

            await httpClient.Received().PostAsync(Arg.Any <string>(), Arg.Any <HttpContent>());
        }
        /// <summary>
        /// Subscribes to an <see cref="IObservable{EventEntry}" /> using an <see cref="EventHubHttpSink" />.
        /// </summary>
        /// <param name="eventStream">The event stream. Typically this is an instance of <see cref="ObservableEventListener" />.</param>
        /// <param name="eventHubNamespace">The namespace of the eventhub.</param>
        /// <param name="eventHubName">The name of the eventhub.</param>
        /// <param name="publisherId">The id of the event publisher.</param>
        /// <param name="sasToken">The shared access signature token.</param>
        /// <param name="bufferingInterval">The buffering interval between each batch publishing.</param>
        /// <param name="bufferingCount">The number of entries that will trigger a batch publishing.</param>
        /// <param name="maxBufferSize">The maximum number of entries that can be buffered while it's sending to the store before the sink starts dropping entries.</param>      
        /// <param name="onCompletedTimeout">Defines a timeout interval for when flushing the entries after an <see cref="OnCompleted"/> call is received and before disposing the sink.
        /// This means that if the timeout period elapses, some event entries will be dropped and not sent to the store. Normally, calling <see cref="IDisposable.Dispose"/> on 
        /// the <see cref="System.Diagnostics.Tracing.EventListener"/> will block until all the entries are flushed or the interval elapses.
        /// If <see langword="null"/> is specified, then the call will block indefinitely until the flush operation finishes.</param>
        /// <returns>
        /// A subscription to the sink that can be disposed to unsubscribe the sink and dispose it, or to get access to the sink instance.
        /// </returns>
        public static SinkSubscription<EventHubHttpSink> LogToEventHubUsingHttp(this IObservable<EventEntry> eventStream,
            string eventHubNamespace, string eventHubName, string publisherId, string sasToken, TimeSpan? bufferingInterval = null, int bufferingCount = Buffering.DefaultBufferingCount, TimeSpan? onCompletedTimeout = null, int maxBufferSize = Buffering.DefaultMaxBufferSize)
        {
            var sink = new EventHubHttpSink(
                    eventHubNamespace,
                    eventHubName,
                    publisherId,
                    sasToken,
                    bufferingInterval ?? Buffering.DefaultBufferingInterval,
                    bufferingCount,
                    maxBufferSize,
                    onCompletedTimeout ?? Timeout.InfiniteTimeSpan
                );

            var subscription = eventStream.Subscribe(sink);
            return new SinkSubscription<EventHubHttpSink>(subscription, sink);
        }
        public void ShouldNotStallOrThrowWhenHttpClientFails()
        {
            var httpClient = HttpClientTestHelper.Create();

            httpClient.PostAsync(Arg.Any <string>(), Arg.Any <HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.InternalServerError)));

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
                using (var collectErrorsListener = new MockEventListener())
                {
                    collectErrorsListener.EnableEvents(SemanticLoggingEventSource.Log, EventLevel.Error, Keywords.All);

                    sink.OnNext(EventEntryTestHelper.Create());

                    Assert.IsTrue(Task.Run(() => sink.OnCompleted()).Wait(TimeSpan.FromSeconds(5)));
                    Assert.IsTrue(collectErrorsListener.WrittenEntries.Any(x => x.EventId == 1));
                }
        }
        public async Task ShouldWritePropertiesForBatchMessageUsingAutoSizedBatch()
        {
            var httpClient = HttpClientTestHelper.Create();

            httpClient.PostAsync(Arg.Any <string>(), Arg.Any <HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

            var entry = EventEntryTestHelper.Create();

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, 0, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
            {
                foreach (var i in Enumerable.Range(0, 500))
                {
                    sink.OnNext(entry);
                }
                await sink.FlushAsync();
            }

            await httpClient.Received(2).PostAsync(Arg.Any <string>(), Arg.Is <HttpContent>(c => c.Headers.ContentLength < 256 * 1024));
        }
        public async Task ShouldNotUseBatchMessagesWhenBatchCountSetToOne()
        {
            var httpClient = HttpClientTestHelper.Create();

            httpClient.PostAsync(Arg.Any <string>(), Arg.Any <HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

            var entry = EventEntryTestHelper.Create();

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, 1, 500, TimeSpan.Zero))
            {
                sink.OnNext(entry);
                sink.OnNext(entry);

                await sink.FlushAsync();
            }

            var byteRepresentation = Encoding.Default.GetBytes(JsonConvert.SerializeObject(entry));
            await httpClient.Received(2).PostAsync(Arg.Any <string>(), Arg.Is <HttpContent>(c => byteRepresentation.SequenceEqual(c.ReadAsByteArrayAsync().Result)));
        }
        public async Task ShouldWriteEntriesOnFlushAsync()
        {
            var httpClient = HttpClientTestHelper.Create();
            httpClient.PostAsync(Arg.Any<string>(), Arg.Any<HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
            {
                sink.OnNext(EventEntryTestHelper.Create());
                sink.OnNext(EventEntryTestHelper.Create());

                await sink.FlushAsync();
            }

            await httpClient.Received().PostAsync(Arg.Any<string>(), Arg.Any<HttpContent>());
        }
        public async Task ShouldWritePropertiesForBatchMessage()
        {
            var httpClient = HttpClientTestHelper.Create();
            httpClient.PostAsync(Arg.Any<string>(), Arg.Any<HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

            var entry = EventEntryTestHelper.Create();
            
            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, Buffering.DefaultBufferingCount, Buffering.DefaultMaxBufferSize, TimeSpan.Zero))
            {
                sink.OnNext(entry);
                sink.OnNext(entry);

                await sink.FlushAsync();
            }

            IList<EventEntry> entries = new List<EventEntry> { entry, entry };
            var messages = entries.Select(c => c.ToBatchMessage());
            var sendMessage = new ServiceBusHttpMessage
            {
                Body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(messages))
            };

            var byteRepresentation = sendMessage.Body;

            await httpClient.Received().PostAsync(Arg.Any<string>(), Arg.Is<HttpContent>(c => byteRepresentation.SequenceEqual(c.ReadAsByteArrayAsync().Result)));
        }
        public async Task ShouldNotUseBatchMessagesWhenBatchCountSetToOne()
        {
            var httpClient = HttpClientTestHelper.Create();
            httpClient.PostAsync(Arg.Any<string>(), Arg.Any<HttpContent>()).Returns(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));

            var entry = EventEntryTestHelper.Create();

            using (var sink = new EventHubHttpSink(httpClient, "eventHubNameNs", "eventhubName", "pubId", "token", Buffering.DefaultBufferingInterval, 1, 500, TimeSpan.Zero))
            {
                sink.OnNext(entry);
                sink.OnNext(entry);

                await sink.FlushAsync();
            }

            var byteRepresentation = Encoding.Default.GetBytes(JsonConvert.SerializeObject(entry));
            await httpClient.Received(2).PostAsync(Arg.Any<string>(), Arg.Is<HttpContent>(c => byteRepresentation.SequenceEqual(c.ReadAsByteArrayAsync().Result)));
        }