public void VerifyUnrecoverableHttpError(int errorStatus)
        {
            var errorCondition = ServerErrorCondition.FromStatus(errorStatus);

            WithServerErrorCondition(errorCondition, null, (uri, httpConfig, recorder) =>
            {
                using (var dataSource = MakeDataSource(uri, BasicUser,
                                                       c => c.DataSource(Components.PollingDataSource().PollInterval(BriefInterval))
                                                       .Http(httpConfig)))
                {
                    var initTask   = dataSource.Start();
                    bool completed = initTask.Wait(TimeSpan.FromSeconds(1));
                    Assert.True(completed);
                    Assert.False(dataSource.Initialized);

                    var status = _updateSink.ExpectStatusUpdate();
                    errorCondition.VerifyDataSourceStatusError(status);

                    recorder.RequireRequest();
                    recorder.RequireNoRequests(TimeSpan.FromMilliseconds(100)); // did not retry

                    errorCondition.VerifyLogMessage(logCapture);
                }
            });
        }
        public void VerifyUnrecoverableHttpError(int errorStatus)
        {
            var errorCondition = ServerErrorCondition.FromStatus(errorStatus);

            WithServerErrorCondition(errorCondition, StreamWithEmptyData, (uri, httpConfig, recorder) =>
            {
                using (var dataSource = MakeDataSource(uri, BasicUser,
                                                       c => c.DataSource(Components.StreamingDataSource().InitialReconnectDelay(TimeSpan.Zero))
                                                       .Http(httpConfig)))
                {
                    var initTask = dataSource.Start();
                    var status   = _updateSink.ExpectStatusUpdate();
                    errorCondition.VerifyDataSourceStatusError(status);

                    _updateSink.ExpectNoMoreActions();

                    recorder.RequireRequest();
                    recorder.RequireNoRequests(TimeSpan.FromMilliseconds(100));

                    Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1)));

                    errorCondition.VerifyLogMessage(logCapture);
                }
            });
        }
        public void VerifyRecoverableHttpError(int errorStatus)
        {
            var errorCondition = ServerErrorCondition.FromStatus(errorStatus);

            WithServerErrorCondition(errorCondition, StreamWithEmptyData, (uri, httpConfig, recorder) =>
            {
                using (var dataSource = MakeDataSource(uri, BasicUser,
                                                       c => c.DataSource(Components.StreamingDataSource().InitialReconnectDelay(TimeSpan.Zero))
                                                       .Http(httpConfig)))
                {
                    var initTask = dataSource.Start();

                    var status = _updateSink.ExpectStatusUpdate();
                    errorCondition.VerifyDataSourceStatusError(status);

                    // We don't check here for a second status update to the Valid state, because that was
                    // done by DataSourceUpdatesImpl when Init was called - our test fixture doesn't do it.

                    _updateSink.ExpectInit(BasicUser);

                    recorder.RequireRequest();
                    recorder.RequireRequest();

                    Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1)));

                    errorCondition.VerifyLogMessage(logCapture);
                }
            });
        }
        public void VerifyRecoverableError(int errorStatus)
        {
            var errorCondition  = ServerErrorCondition.FromStatus(errorStatus);
            var successResponse = PollingResponse(AllData);

            // Verify that it does not immediately retry the failed request

            WithServerErrorCondition(errorCondition, successResponse, (uri, httpConfig, recorder) =>
            {
                using (var dataSource = MakeDataSource(uri, BasicUser,
                                                       c => c.DataSource(Components.PollingDataSource().PollInterval(TimeSpan.FromHours(1)))
                                                       .Http(httpConfig)))
                {
                    dataSource.Start();

                    var status = _updateSink.ExpectStatusUpdate();
                    errorCondition.VerifyDataSourceStatusError(status);

                    recorder.RequireRequest();
                    recorder.RequireNoRequests(TimeSpan.FromMilliseconds(100));

                    errorCondition.VerifyLogMessage(logCapture);
                }
            });

            // Verify (with a small polling interval) that it does do another request at the next interval

            WithServerErrorCondition(errorCondition, successResponse, (uri, httpConfig, recorder) =>
            {
                using (var dataSource = MakeDataSource(uri, BasicUser,
                                                       c => c.DataSource(Components.PollingDataSource().PollIntervalNoMinimum(BriefInterval))
                                                       .Http(httpConfig)))
                {
                    var initTask   = dataSource.Start();
                    bool completed = initTask.Wait(TimeSpan.FromSeconds(1));
                    Assert.True(completed);
                    Assert.True(dataSource.Initialized);

                    var status = _updateSink.ExpectStatusUpdate();
                    errorCondition.VerifyDataSourceStatusError(status);

                    // We don't check here for a second status update to the Valid state, because that was
                    // done by DataSourceUpdatesImpl when Init was called - our test fixture doesn't do it.

                    recorder.RequireRequest();
                    recorder.RequireRequest();

                    errorCondition.VerifyLogMessage(logCapture);
                }
            });
        }
        /// <summary>
        /// Sets up the HttpTest framework to simulate a server error of some kind. If
        /// it is an HTTP error response, we'll use an embedded HttpServer. If it is an
        /// I/O error, we have to use a custom message handler instead.
        /// </summary>
        /// <param name="errorCondition"></param>
        /// <param name="successResponseAfterError">if not null, the second request will
        /// receive this response instead of the error</param>
        /// <param name="action"></param>
        public static void WithServerErrorCondition(ServerErrorCondition errorCondition,
                                                    Handler successResponseAfterError,
                                                    Action <Uri, HttpConfigurationBuilder, RequestRecorder> action)
        {
            var responseHandler = successResponseAfterError is null ? errorCondition.Handler :
                                  Handlers.Sequential(errorCondition.Handler, successResponseAfterError);

            if (errorCondition.IOException is null)
            {
                using (var server = HttpServer.Start(responseHandler))
                {
                    action(server.Uri, Components.HttpConfiguration(), server.Recorder);
                }
            }
            else
            {
                var handler = Handlers.Record(out var recorder).Then(responseHandler);
                action(
                    FakeUri,
                    Components.HttpConfiguration().MessageHandler(handler.AsMessageHandler()),
                    recorder
                    );
            }
        }