public async void Invoke__UnknownContenTypeReturnsUnsupportedMediaTypeWhenBodyHasContent()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var routeData  = BuildRouteData(routePath);
            var context    = BuildContext(routeData, ctx => Task.FromResult(0), contentType: "text/foobar");
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator);

            using (context.Request.Body = new MemoryStream())
                using (var sw = new StreamWriter(context.Request.Body))
                {
                    sw.Write("Foobar");
                    sw.Flush();
                    context.Request.Body.Position = 0L;
                    context.Request.ContentLength = context.Request.Body.Length;

                    await middleware.Invoke(context);

                    context.Response.StatusCode.ShouldBeEquivalentTo(HttpStatusCode.UnsupportedMediaType);
                }
        }
        public async Task Invoke__EmptyBodyContentSetsContentTypeToDefaultProvider()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedSerializationProvider = new Mock <ISerializationProvider>().SetupAllProperties();

            expectedSerializationProvider.SetupGet(x => x.ContentType).Returns("text/foobar");

            var sink = GetTestSink();

            var routeData = BuildRouteData(routePath);
            var options   = BuildRServiceOptions(opts =>
            {
                opts.DefaultSerializationProvider = expectedSerializationProvider.Object;
                opts.SerializationProviders.Add(opts.DefaultSerializationProvider.ContentType, opts.DefaultSerializationProvider);
            });
            var context    = BuildContext(routeData, ctx => Task.FromResult(0), contentType: "text/foobar");
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator, options: options);

            await middleware.Invoke(context);

            context.Features[typeof(IRServiceFeature)].As <IRServiceFeature>().RequestSerializer.ContentType
            .ShouldAllBeEquivalentTo(expectedSerializationProvider.Object.ContentType);
        }
        public async void Invoke__AcceptHeaderWithQualityReturnsOk()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Returns(Task.FromResult(0));

            var routeData = BuildRouteData(routePath);
            var options   = BuildRServiceOptions(opt =>
            {
                var json = new NetJsonProvider();
                opt.DefaultSerializationProvider = json;
                opt.SerializationProviders.Add(json.ContentType, json);
            });
            var context = BuildContext(routeData, ctx => Task.FromResult(0),
                                       accept: $"{new NetJsonProvider().ContentType};q=0.8");
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator, serviceProvider: provider.Object,
                                             options: options);

            await middleware.Invoke(context);

            context.Response.StatusCode.ShouldBeEquivalentTo(HttpStatusCode.OK);
        }
        public async void Invoke__AcceptHeaderNotMachingSerialzaitonProviderReturnsNotAcceptable()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Returns(Task.FromResult(0));

            var routeData  = BuildRouteData(routePath);
            var context    = BuildContext(routeData, ctx => Task.FromResult(0), accept: "text/foobar");
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator, serviceProvider: provider.Object);

            await middleware.Invoke(context);

            context.Response.StatusCode.ShouldBeEquivalentTo(HttpStatusCode.NotAcceptable);
        }
        public void Invoke__ThrowsApiExceptionIfDebugging()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Throws <ApiException>();

            var routeData = BuildRouteData(routePath);
            var context   = BuildContext(routeData, ctx => Task.FromResult(0));

            var options    = BuildRServiceOptions(opts => { opts.EnableDebugging = true; });
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator,
                                             options: options, serviceProvider: provider.Object);

            Func <Task> act = async() =>
            {
                await middleware.Invoke(context);
            };

            act.ShouldThrow <ApiException>();
        }
        public async void Invoke__CallsGlobalExceptionHandlerOnException()
        {
            var hasHandledException = false;

            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Throws <Exception>();

            var exceptionFilter = new Mock <IExceptionFilter>().SetupAllProperties();

            exceptionFilter.Setup(x => x.OnException(It.IsAny <HttpContext>(), It.IsAny <Exception>()))
            .Callback(() => hasHandledException = true);

            var routeData  = BuildRouteData(routePath);
            var context    = BuildContext(routeData, ctx => Task.FromResult(0), globalExceptionFilter: exceptionFilter.Object);
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator, serviceProvider: provider.Object);

            await middleware.Invoke(context);

            hasHandledException.Should().BeTrue();
        }
        public async void Invoke__ExceptionSetsStatusCode()
        {
            const HttpStatusCode expectedStatusCode = HttpStatusCode.InternalServerError;

            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Throws(new ApiException(string.Empty, expectedStatusCode));

            var routeData  = BuildRouteData(routePath);
            var context    = BuildContext(routeData, ctx => Task.FromResult(0));
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator, serviceProvider: provider.Object);
            var body       = context.Response.Body;

            await middleware.Invoke(context);

            body.Position = 0L;
            using (var response = new StreamReader(body))
                response.ReadToEnd().Should().BeEmpty();
            context.Response.StatusCode.Should().Be((int)expectedStatusCode);
        }
        public async void Invoke__CallsProviderIfActivatorFound()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Returns(Task.FromResult(0));

            var routeData  = BuildRouteData(routePath);
            var context    = BuildContext(routeData, ctx => Task.FromResult(0));
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator, serviceProvider: provider.Object);

            await middleware.Invoke(context);

            provider.Verify(x => x.Invoke(It.IsAny <HttpContext>()));
        }
        public async void Invoke__AcceptHeaderSecondaryUsesSecondaryProvider()
        {
            var          routePath        = "/Foobar".Substring(1);
            const string expectedResponse = "FizzBuzz";
            const string mimeType         = "application/foobar";

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var mockProvider = new Mock <ISerializationProvider>().SetupAllProperties();

            _options.Value.DefaultSerializationProvider = mockProvider.Object;
            mockProvider.Setup(x => x.DehydrateResponse(It.IsAny <object>())).Returns(expectedResponse);

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();
            var responseMessage = string.Empty;

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Callback <HttpContext>(ctx =>
            {
                var serializer  = ctx.GetResponseSerializationProvider();
                responseMessage = serializer.DehydrateResponse(null);
            })
            .Returns(Task.FromResult(0));

            var foobarProvider = new Mock <ISerializationProvider>().SetupAllProperties();

            foobarProvider.SetupGet(x => x.ContentType).Returns(mimeType);
            foobarProvider.Setup(x => x.DehydrateResponse(It.IsAny <object>())).Returns(expectedResponse);

            var routeData = BuildRouteData(routePath);
            var context   = BuildContext(routeData, ctx => Task.FromResult(0), accept: mimeType);
            var options   = BuildRServiceOptions(opt =>
            {
                opt.DefaultSerializationProvider = new NetJsonProvider();
                opt.SerializationProviders.Add(mimeType, foobarProvider.Object);
            });
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator,
                                             serviceProvider: provider.Object, options: options);

            await middleware.Invoke(context);

            context.Response.StatusCode.ShouldBeEquivalentTo(HttpStatusCode.OK);
            responseMessage.ShouldAllBeEquivalentTo(expectedResponse);
        }
        public async void Invoke__AddsRServiceFeatureIfRouteHandlerSet()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var expectedFeature = new Mock <IRServiceFeature>();

            expectedFeature.SetupGet(x => x.MethodActivator).Returns(routeActivator);

            var sink = GetTestSink();

            var routeData  = BuildRouteData(routePath);
            var context    = BuildContext(routeData);
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator);

            await middleware.Invoke(context);

            context.Features.ToDictionary(x => x.Key, x => x.Value)
            .Should().ContainKey(typeof(IRServiceFeature))
            .WhichValue.Should().NotBeNull();
            (context.Features[typeof(IRServiceFeature)] as IRServiceFeature)?
            .MethodActivator.Should().Be(expectedFeature.Object.MethodActivator);
        }
        public async void Invoke__SetsContextOfService()
        {
            var routePath = "/Foobar".Substring(1);

            Delegate.Activator routeActivator = (target, args) => null;
            var serviceMock = new Mock <IService>().SetupAllProperties();

            var sink = GetTestSink();

            var provider = new Mock <IServiceProvider>()
                           .SetupAllProperties();

            provider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
            .Returns(Task.FromResult(0));

            var routeData  = BuildRouteData(routePath);
            var context    = BuildContext(routeData, ctx => Task.FromResult(0), service: serviceMock.Object);
            var middleware = BuildMiddleware(sink, $"{routePath}:GET", routeActivator,
                                             serviceProvider: provider.Object, service: serviceMock.Object);

            await middleware.Invoke(context);

            serviceMock.Object.Context.Should().Be(context);
        }
        private RServiceMiddleware BuildMiddleware(TestSink sink, string routePath = null, Delegate.Activator routeActivator  = null,
                                                   RequestDelegate handler         = null, IOptions <RServiceOptions> options = null, IServiceProvider serviceProvider = null,
                                                   IService service = null)
        {
            options = options ?? _options;

            var loggerFactory = new TestLoggerFactory(sink, true);
            var next          = handler ?? (c => Task.FromResult <object>(null));
            var rservice      = new RService(options);

            if (serviceProvider == null)
            {
                var mockServiceProvider = new Mock <IServiceProvider>().SetupAllProperties();
                mockServiceProvider.Setup(x => x.Invoke(It.IsAny <HttpContext>()))
                .Returns(Task.FromResult(0));

                serviceProvider = mockServiceProvider.Object;
            }

            if (!routePath.IsNullOrEmpty() && routeActivator != null)
            {
                rservice.Routes.Add(routePath, new ServiceDef
                {
                    ServiceMethod = routeActivator,
                    ServiceType   = service?.GetType() ?? typeof(IService)
                });
            }

            return(new RServiceMiddleware(next, loggerFactory, rservice, serviceProvider, options));
        }