/// <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); }
/// <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; }