示例#1
0
        /// <summary>
        /// Based on data in the codeBlock, see if we can infer what kind of block this is
        /// </summary>
        /// <param name="codeBlock"></param>
        /// <returns></returns>
        private static CodeBlockType InferBlockType(Block codeBlock, string resourceTypeName = null)
        {
            if (codeBlock.CodeLanguage == "http")
            {
                // See if this is an HTTP request or HTTP response
                Http.HttpParser parser = new Http.HttpParser();
                try
                {
                    parser.ParseHttpRequest(codeBlock.Content);
                    return(CodeBlockType.Request);
                }
                catch { }

                try
                {
                    parser.ParseHttpResponse(codeBlock.Content);
                    return(CodeBlockType.Response);
                }
                catch { }
            }
            else if (codeBlock.CodeLanguage == "json" && !string.IsNullOrEmpty(resourceTypeName))
            {
                return(CodeBlockType.Resource);
            }

            return(CodeBlockType.Unknown);
        }
        private static async Task ValidateMethodWithScenarioAsync(
            MethodDefinition method,
            ScenarioDefinition scenario,
            IServiceAccount account,
            AuthenicationCredentials credentials,
            ValidationResults results)
        {
            if (null == method)
                throw new ArgumentNullException("method");
            if (null == scenario)
                throw new ArgumentNullException("scenario");
            if (null == account)
                throw new ArgumentNullException("account");
            if (null == credentials)
                throw new ArgumentNullException("credentials");
            if (null == results)
                throw new ArgumentNullException("results");

            var actionName = scenario.Description;

            // Generate the tested request by "previewing" the request and executing
            // all test-setup procedures
            long startTicks = DateTimeOffset.UtcNow.Ticks;
            var requestPreviewResult = await method.GenerateMethodRequestAsync(scenario, account.BaseUrl, credentials, method.SourceFile.Parent);
            TimeSpan generateMethodDuration = new TimeSpan(DateTimeOffset.UtcNow.Ticks - startTicks);
            
            // Check to see if an error occured building the request, and abort if so.
            var generatorResults = results[actionName + " [test-setup requests]"];
            generatorResults.AddResults(requestPreviewResult.Messages, requestPreviewResult.IsWarningOrError ? ValidationOutcome.Error :  ValidationOutcome.Passed);
            generatorResults.Duration = generateMethodDuration;

            if (requestPreviewResult.IsWarningOrError)
            {
                return;
            }

            // We've done all the test-setup work, now we have the real request to make to the service
            HttpRequest requestPreview = requestPreviewResult.Value;

            results.AddResult(
                actionName,
                new ValidationMessage(null, "Generated Method HTTP Request:\r\n{0}", requestPreview.FullHttpText()));

            HttpParser parser = new HttpParser();
            HttpResponse expectedResponse = null;
            if (!string.IsNullOrEmpty(method.ExpectedResponse))
            {
                expectedResponse = parser.ParseHttpResponse(method.ExpectedResponse);
            }

            // Execute the actual tested method (the result of the method preview call, which made the test-setup requests)
            startTicks = DateTimeOffset.UtcNow.Ticks;
            var actualResponse = await requestPreview.GetResponseAsync(account.BaseUrl);
            TimeSpan actualMethodDuration = new TimeSpan(DateTimeOffset.UtcNow.Ticks - startTicks);

            var requestResults = results[actionName];
            if (actualResponse.RetryCount > 0)
            {
                requestResults.AddResults(
                    new ValidationError[]
                    { new ValidationWarning(ValidationErrorCode.RequestWasRetried, null, "HTTP request was retried {0} times.", actualResponse.RetryCount) });
            }


            requestResults.AddResults(
                new ValidationError[]
                { new ValidationMessage(null, "HTTP Response:\r\n{0}", actualResponse.FullText(false)) });
            requestResults.Duration = actualMethodDuration;
           

            // Perform validation on the method's actual response
            ValidationError[] errors;
            method.ValidateResponse(actualResponse, expectedResponse, scenario, out errors);

            requestResults.AddResults(errors);

            // TODO: If the method is defined as a long running operation, we need to go poll the status 
            // URL to make sure that the operation finished and the response type is valid.

            if (errors.WereErrors())
                results.SetOutcome(actionName, ValidationOutcome.Error);
            else if (errors.WereWarnings())
                results.SetOutcome(actionName, ValidationOutcome.Warning);
            else
                results.SetOutcome(actionName, ValidationOutcome.Passed);
        }
示例#3
0
        /// <summary>
        /// Checks that the expected response of a method definition is valid with this resource.
        /// </summary>
        /// <param name="method"></param>
        /// <param name="errors"></param>
        /// <returns></returns>
        public bool ValidateExpectedResponse(MethodDefinition method, out ValidationError[] errors)
        {
            HttpParser parser = new HttpParser();
            var response = parser.ParseHttpResponse(method.ExpectedResponse);

            JsonExample example = new JsonExample(response.Body, method.ExpectedResponseMetadata);
            var otherSchemas = new Dictionary<string, JsonSchema>();
            return this.ValidateJson(example, out errors, otherSchemas, null);
        }
        /// <summary>
        /// Check to ensure the http request is valid
        /// </summary>
        /// <param name="detectedErrors"></param>
        internal void VerifyHttpRequest(List<ValidationError> detectedErrors)
        {
            HttpParser parser = new HttpParser();
            HttpRequest request;
            try
            {
                request = parser.ParseHttpRequest(this.Request);
            }
            catch (Exception ex)
            {
                detectedErrors.Add(new ValidationError(ValidationErrorCode.HttpParserError, null, "Exception while parsing HTTP request: {0}", ex.Message));
                return;
            }

            if (null != request.ContentType)
            {
                if (request.IsMatchingContentType(MimeTypeJson))
                {
                    // Verify that the request is valid JSON
                    try
                    {
                        JsonConvert.DeserializeObject(request.Body);
                    }
                    catch (Exception ex)
                    {
                        detectedErrors.Add(new ValidationError(ValidationErrorCode.JsonParserException, null, "Invalid JSON format: {0}", ex.Message));
                    }
                }
                else if (request.IsMatchingContentType(MimeTypeMultipartRelated))
                {
                    // TODO: Parse the multipart/form-data body to ensure it's properly formatted
                }
                else if (request.IsMatchingContentType(MimeTypePlainText))
                {
                    // Ignore this, because it isn't something we can verify
                }
                else
                {
                    detectedErrors.Add(new ValidationWarning(ValidationErrorCode.UnsupportedContentType, null, "Unvalidated request content type: {0}", request.ContentType));
                }
            }

            var verifyApiRequirementsResponse = request.IsRequestValid(this.SourceFile.DisplayName, this.SourceFile.Parent.Requirements);
            detectedErrors.AddRange(verifyApiRequirementsResponse.Messages);
        }
        public void SplitRequestUrl(out string relativePath, out string queryString, out string httpMethod)
        {
            var parser = new HttpParser();
            var request = parser.ParseHttpRequest(this.Request);
            httpMethod = request.Method;

            request.Url.SplitUrlComponents(out relativePath, out queryString);
        }
        internal static IEnumerable<ParameterDefinition> MissingRequestParameters(this MethodDefinition method, bool queryStringOnly = false)
        {
            HttpParser parser = new HttpParser();
            var request = parser.ParseHttpRequest(method.Request);
            string urlString = request.Url;

            string path, queryString;
            urlString.SplitUrlComponents(out path, out queryString);

            List<ParameterDefinition> missingParameters = new List<ParameterDefinition>();
            if (!queryStringOnly)
            {
                missingParameters.AddRange(from id in FindVariablesInString(path)
                                           where !method.Parameters.HasMatchingParameter(id, ParameterLocation.Path)
                                           select new ParameterDefinition { Name = id, Location = ParameterLocation.Path, Required = true, Type = ParameterDataType.String });
            }
            if (!string.IsNullOrEmpty(queryString))
            {
                missingParameters.AddRange(from id in FindVariablesInQueryString(queryString)
                                           where !method.Parameters.HasMatchingParameter(id, ParameterLocation.QueryString)
                                           select new ParameterDefinition { Name = id, Location = ParameterLocation.QueryString, Required = false, Type = ParameterDataType.String });
            }
            return missingParameters;
        }
        /// <summary>
        /// Take a scenario definition and convert the prototype request into a fully formed request. This includes appending
        /// the base URL to the request URL, executing any test-setup requests, and replacing the placeholders in the prototype
        /// request with proper values.
        /// </summary>
        /// <param name="scenario"></param>        
        /// <param name="documents"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public async Task<ValidationResult<HttpRequest>> GenerateMethodRequestAsync(ScenarioDefinition scenario, DocSet documents, IServiceAccount account)
        {
            var parser = new HttpParser();
            var request = parser.ParseHttpRequest(this.Request);

            AddAccessTokenToRequest(account.CreateCredentials(), request);
            AddTestHeaderToRequest(scenario, request);
            AddAdditionalHeadersToRequest(account, request);

            List<ValidationError> errors = new List<ValidationError>();

            if (null != scenario)
            {
                var storedValuesForScenario = new Dictionary<string, string>();

                if (null != scenario.TestSetupRequests)
                {
                    foreach (var setupRequest in scenario.TestSetupRequests)
                    {
                        var result = await setupRequest.MakeSetupRequestAsync(storedValuesForScenario, documents, scenario, account);
                        errors.AddRange(result.Messages);

                        if (result.IsWarningOrError)
                        {
                            // If we can an error or warning back from a setup method, we fail the whole request.
                            return new ValidationResult<HttpRequest>(null, errors);
                        }
                    }
                }

                try
                {
                    var placeholderValues = scenario.RequestParameters.ToPlaceholderValuesArray(storedValuesForScenario);
                    request.RewriteRequestWithParameters(placeholderValues);
                }
                catch (Exception ex)
                {
                    // Error when applying parameters to the request
                    errors.Add(
                        new ValidationError(
                            ValidationErrorCode.RewriteRequestFailure,
                            "GenerateMethodRequestAsync",
                            ex.Message));

                    return new ValidationResult<HttpRequest>(null, errors);
                }

                if (scenario.StatusCodesToRetry != null)
                {
                    request.RetryOnStatusCode =
                        (from status in scenario.StatusCodesToRetry select (System.Net.HttpStatusCode)status).ToList();
                }
            }

            if (string.IsNullOrEmpty(request.Accept))
            {
                if (!string.IsNullOrEmpty(ValidationConfig.ODataMetadataLevel))
                {
                    request.Accept = MimeTypeJson + "; " + ValidationConfig.ODataMetadataLevel;
                }
                else
                {
                    request.Accept = MimeTypeJson;
                }
            }

            return new ValidationResult<HttpRequest>(request, errors);
        }
        private static SwaggerResponse ToSwaggerResponse(this MethodDefinition method, out string httpStatusCode)
        {
            HttpParser parser = new HttpParser();
            var response = parser.ParseHttpResponse(method.ExpectedResponse);

            httpStatusCode = response.StatusCode.ToString();

            return new SwaggerResponse { Schema = method.ExpectedResponseAsSwaggerProperty() };
        }
        public void TruncatedExampleWithRequiredPropertiesTest()
        {
            DocSet docSet = new DocSet();
            DocFile testFile = new DocFileForTesting(Resources.ExampleValidateResponse, "\test\test.md", "test.md", docSet);

            ValidationError[] detectedErrors;
            testFile.Scan(string.Empty, out detectedErrors);

            Assert.IsEmpty(detectedErrors.Where(x => x.IsError));

            docSet.ResourceCollection.RegisterJsonResource(testFile.Resources.First());

            HttpParser parser = new HttpParser();
            var testMethod = testFile.Requests.First();

            var expectedResponse = parser.ParseHttpResponse(testMethod.ExpectedResponse);
            var actualResponse = parser.ParseHttpResponse(testMethod.ActualResponse);

            testMethod.ValidateResponse(actualResponse, expectedResponse, null, out detectedErrors);

            Assert.AreEqual(1, detectedErrors.Length);
            var error = detectedErrors.First();
            Assert.AreEqual(ValidationErrorCode.RequiredPropertiesMissing, error.Code);
        }
        public void TruncatedExampleSelectStatementOnChildrenExpectFailure()
        {
            DocSet docSet = new DocSet();
            DocFile testFile = new DocFileForTesting(Resources.ExampleValidationSelectStatementFailure, "\test\test.md", "test.md", docSet);

            ValidationError[] detectedErrors;
            testFile.Scan(string.Empty, out detectedErrors);

            Assert.IsEmpty(detectedErrors.Where(x => x.IsError));

            docSet.ResourceCollection.RegisterJsonResource(testFile.Resources.First());

            HttpParser parser = new HttpParser();
            var testMethod = testFile.Requests.First();

            var expectedResponse = parser.ParseHttpResponse(testMethod.ExpectedResponse);
            var actualResponse = parser.ParseHttpResponse(testMethod.ActualResponse);

            testMethod.ValidateResponse(actualResponse, expectedResponse, null, out detectedErrors);

            Assert.AreEqual(2, detectedErrors.Length);
            Assert.IsTrue(detectedErrors.Any(x => x.Code == ValidationErrorCode.RequiredPropertiesMissing), "Error with Code = RequiredPropertiesMissing");
            Assert.IsTrue(
                detectedErrors.Any(x => x.Code == ValidationErrorCode.SkippedSimilarErrors),
                "Error with Code = SkippedSimilarErrors");
        }
 private static HttpRequest ParseHttpRequest(string rawHttpRequest)
 {
     HttpParser parser = new HttpParser();
     HttpRequest request = parser.ParseHttpRequest(rawHttpRequest);
     return request;
 }
        /// <summary>
        /// Based on data in the codeBlock, see if we can infer what kind of block this is
        /// </summary>
        /// <param name="codeBlock"></param>
        /// <returns></returns>
        private static CodeBlockType InferBlockType(Block codeBlock, string resourceTypeName = null)
        {
            if (codeBlock.CodeLanguage == "http")
            {
                // See if this is an HTTP request or HTTP response
                Http.HttpParser parser = new Http.HttpParser();
                try
                {
                    parser.ParseHttpRequest(codeBlock.Content);
                    return CodeBlockType.Request;
                }
                catch { }

                try
                {
                    parser.ParseHttpResponse(codeBlock.Content);
                    return CodeBlockType.Response;
                }
                catch { }
            }
            else if (codeBlock.CodeLanguage == "json" && !string.IsNullOrEmpty(resourceTypeName))
            {
                return CodeBlockType.Resource;
            }

            return CodeBlockType.Unknown;
        }