/// <summary> /// Performs validation of a method (request/response) with a given service /// target and zero or more test scenarios /// </summary> /// <param name="method"></param> /// <param name="account"></param> /// <param name="credentials"></param> /// <returns></returns> public static async Task<ValidationResults> ValidateServiceResponseAsync( this MethodDefinition method, ScenarioDefinition[] scenarios, IServiceAccount account, ValidationOptions options = null) { if (null == method) throw new ArgumentNullException("method"); if (null == account) throw new ArgumentNullException("account"); ValidationResults results = new ValidationResults(); if (scenarios.Length == 0) { // If no descenarios are defined for this method, add a new default scenario scenarios = new ScenarioDefinition[] { new ScenarioDefinition { Description = "verbatim", Enabled = true, MethodName = method.Identifier, RequiredScopes = method.RequiredScopes } }; // results.AddResult("init", new ValidationMessage(null, "No scenarios were defined for method {0}. Will request verbatim from docs.", method.Identifier), ValidationOutcome.None); } if (scenarios.Any() && !scenarios.Any(x => x.Enabled)) { results.AddResult("init", new ValidationWarning(ValidationErrorCode.AllScenariosDisabled, null, "All scenarios for method {0} were disabled.", method.Identifier), ValidationOutcome.Skipped); return results; } foreach (var scenario in scenarios.Where(x => x.Enabled)) { try { await ValidateMethodWithScenarioAsync(method, scenario, account, results, options); } catch (Exception ex) { results.AddResult( "validation", new ValidationError( ValidationErrorCode.ExceptionWhileValidatingMethod, method.SourceFile.DisplayName, ex.Message)); } } return results; }
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> /// Record the results from a validation test run into this object /// </summary> /// <param name="results"></param> internal void RecordResults(ValidationResults results, CheckServiceOptions options) { foreach (var result in results.Results) { if ((result.Outcome & ValidationOutcome.Error) > 0) { FailureCount++; } else if ((result.Outcome & ValidationOutcome.Warning) > 0) { if (options.IgnoreWarnings || options.SilenceWarnings) SuccessCount++; else WarningCount++; } else if ((result.Outcome & ValidationOutcome.Passed) > 0) { SuccessCount++; } } }