public ConformanceTests(ServiceSerializer serializer)
        : base(serializer)
    {
        m_tests             = CreateTestProvider(JsonSerializer);
        m_contentSerializer = HttpContentSerializer.Create(Serializer);

        var service = new ConformanceApiService(new ConformanceApiServiceSettings {
            Tests = m_tests, JsonSerializer = JsonSerializer
        });
        var settings = new ServiceHttpHandlerSettings {
            ContentSerializer = m_contentSerializer
        };
        var handler = new ConformanceApiHttpHandler(service, settings)
        {
            InnerHandler = new NotFoundHttpHandler()
        };

        m_httpClient = new HttpClient(handler)
        {
            BaseAddress = new Uri("http://example.com/")
        };
    }
 private string?GetAcceptedMediaType(HttpRequestMessage httpRequest, HttpContentSerializer serializer) =>
 httpRequest.Headers.Accept
 .OrderByDescending(x => x.Quality)
 .Select(x => x.MediaType)
 .Where(x => x is not null)
Esempio n. 3
0
    public async Task <int> RunAsync(IReadOnlyList <string> args)
    {
        const string defaultUrl = "http://localhost:4117/";

        var argsReader = new ArgsReader(args);

        if (argsReader.ReadFlag("?|h|help"))
        {
            throw new ArgsReaderException("");
        }

        var serializerName           = argsReader.ReadOption("serializer")?.ToLowerInvariant();
        ServiceSerializer serializer = serializerName switch
        {
            null or "systemtextjson" => SystemTextJsonServiceSerializer.Instance,
            "newtonsoftjson" or "obsoletejson" => NewtonsoftJsonServiceSerializer.Instance,
                          _ => throw new ArgsReaderException("Unsupported serializer."),
        };
        var contentSerializer = HttpContentSerializer.Create(serializer);

#pragma warning disable CS0618 // Type or member is obsolete
        if (serializerName is "obsoletejson")
        {
            contentSerializer = new JsonHttpContentSerializer(new JsonHttpContentSerializerSettings {
                ForceAsyncIO = true
            });
        }
#pragma warning restore CS0618 // Type or member is obsolete

        var jsonSerializer = serializer as JsonServiceSerializer ?? NewtonsoftJsonServiceSerializer.Instance;
        var tests          = ConformanceTestsInfo.FromJson(m_testsJson, jsonSerializer).Tests !;

        var command = argsReader.ReadArgument();

        if (command == "host")
        {
            var url = argsReader.ReadOption("url") ?? defaultUrl;
            argsReader.VerifyComplete();

            var service = new ConformanceApiService(
                new ConformanceApiServiceSettings
            {
                Tests          = tests,
                JsonSerializer = jsonSerializer,
            });

            await new WebHostBuilder()
            .UseKestrel(options => options.AllowSynchronousIO = serializerName is "newtonsoftjson")
            .UseUrls(url)
            .Configure(app => app.Run(httpContext => HostAsync(httpContext, service, contentSerializer)))
            .Build()
            .RunAsync();

            return(0);
        }

        if (command == "test")
        {
            var baseUri   = new Uri(argsReader.ReadOption("url") ?? defaultUrl);
            var testNames = argsReader.ReadArguments();
            argsReader.VerifyComplete();

            var api = new HttpClientConformanceApi(
                new HttpClientServiceSettings
            {
                BaseUri           = baseUri,
                ContentSerializer = contentSerializer,
            });

            var tester = new ConformanceApiTester(
                new ConformanceApiTesterSettings
            {
                Tests      = tests,
                Api        = api,
                HttpClient = new HttpClient {
                    BaseAddress = baseUri
                },
                JsonSerializer = jsonSerializer,
            });

            var results = new List <ConformanceTestResult>();

            if (testNames.Count == 0)
            {
                results.AddRange((await tester.RunAllTestsAsync()).Results);
            }
            else
            {
                foreach (var testName in testNames)
                {
                    var testInfo = tests.SingleOrDefault(x => x.Test == testName);
                    if (testInfo == null)
                    {
                        Console.WriteLine($"Test not found: {testName}");
                        return(-1);
                    }

                    results.Add(await tester.RunTestAsync(testInfo));
                }
            }

            var failureCount = 0;
            foreach (var result in results.Where(x => x.Status == ConformanceTestStatus.Fail))
            {
                Console.WriteLine($"{result.TestName} fail: {result.Message}");
                failureCount++;
            }

            Console.WriteLine($"{results.Count} tests: {results.Count - failureCount} passed, {failureCount} failed.");

            return(failureCount == 0 ? 0 : 1);
        }

        if (command == "fsd")
        {
            var outputPath   = argsReader.ReadOption("output");
            var shouldVerify = argsReader.ReadFlag("verify");
            argsReader.VerifyComplete();

            return(WriteText(path: outputPath, contents: m_fsdText, shouldVerify: shouldVerify));
        }

        if (command == "json")
        {
            var outputPath   = argsReader.ReadOption("output");
            var shouldVerify = argsReader.ReadFlag("verify");
            argsReader.VerifyComplete();

            return(WriteText(path: outputPath, contents: m_testsJson, shouldVerify: shouldVerify));
        }

        if (command != null)
        {
            throw new ArgsReaderException($"Invalid command: {command}");
        }

        throw new ArgsReaderException("Missing command.");
    }
Esempio n. 4
0
    private async Task HostAsync(HttpContext httpContext, IConformanceApi service, HttpContentSerializer contentSerializer)
    {
        var httpRequest = httpContext.Request;
        var requestUrl  = httpRequest.GetEncodedUrl();

        var apiHandler = new ConformanceApiHttpHandler(service, new ServiceHttpHandlerSettings {
            ContentSerializer = contentSerializer
        });

        var requestMessage = new HttpRequestMessage(new HttpMethod(httpRequest.Method), requestUrl)
        {
            Content = new StreamContent(httpRequest.Body),
        };

        foreach (var header in httpRequest.Headers)
        {
            // Every header should be able to fit into one of the two header collections.
            // Try message.Headers first since that accepts more of them.
            if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.AsEnumerable()))
            {
                requestMessage.Content.Headers.TryAddWithoutValidation(header.Key, header.Value.AsEnumerable());
            }
        }

        HttpResponseMessage?responseMessage = null;
        ServiceErrorDto?    error           = null;

        try
        {
            responseMessage = await apiHandler.TryHandleHttpRequestAsync(requestMessage, httpContext.RequestAborted).ConfigureAwait(false);

            if (responseMessage == null)
            {
                error = ServiceErrors.CreateInvalidRequest($"Test not found for {httpRequest.Method} {requestUrl}");
            }
        }
        catch (Exception exception)
        {
            error = ServiceErrorUtility.CreateInternalErrorForException(exception);
        }

        if (error != null)
        {
            var statusCode = HttpServiceErrors.TryGetHttpStatusCode(error.Code) ?? HttpStatusCode.InternalServerError;
            responseMessage = new HttpResponseMessage(statusCode)
            {
                Content = contentSerializer.CreateHttpContent(error)
            };
        }

        if (responseMessage != null)
        {
            using (responseMessage)
            {
                var response = httpContext.Response;
                response.StatusCode = (int)responseMessage.StatusCode;

                var responseHeaders = responseMessage.Headers;

                // Ignore the Transfer-Encoding header if it is just "chunked".
                // We let the host decide about whether the response should be chunked or not.
                if (responseHeaders.TransferEncodingChunked == true && responseHeaders.TransferEncoding.Count == 1)
                {
                    responseHeaders.TransferEncoding.Clear();
                }

                foreach (var header in responseHeaders)
                {
                    response.Headers.Append(header.Key, header.Value.ToArray());
                }

                // ReSharper disable once ConditionIsAlwaysTrueOrFalse
                if (responseMessage.Content != null)
                {
                    var contentHeaders = responseMessage.Content.Headers;

                    // Copy the response content headers only after ensuring they are complete.
                    // We ask for Content-Length first because HttpContent lazily computes this
                    // and only afterwards writes the value into the content headers.
                    _ = contentHeaders.ContentLength;

                    foreach (var header in contentHeaders)
                    {
                        response.Headers.Append(header.Key, header.Value.ToArray());
                    }

                    await responseMessage.Content.CopyToAsync(response.Body).ConfigureAwait(false);
                }
            }
        }
    }