Ejemplo n.º 1
0
        /// <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);
        }
Ejemplo n.º 2
0
        public PoorManControllerFactory(IServiceUser serviceUser, IServiceAccount serviceAccount)
        {
            if (serviceUser == null) throw new ArgumentNullException("serviceUser cannot be null");
            if (serviceAccount == null) throw new ArgumentNullException("serviceAccount cannot be null");

            _serviceAccount = serviceAccount;
            _serviceUser = serviceUser;
        }
        /// <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;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Write the results of a test to the output console.
        /// </summary>
        /// <param name="method"></param>
        /// <param name="account"></param>
        /// <param name="results"></param>
        /// <param name="options"></param>
        private static void PrintResultsToConsole(MethodDefinition method, IServiceAccount account, ValidationResults output, CheckServiceOptions options)
        {
            // Only allow one thread at a time to write to the console so we don't interleave our results.
            lock (typeof(Program))
            {
                FancyConsole.WriteLine(
                    FancyConsole.ConsoleHeaderColor,
                    "Testing method {0} with account {1}",
                    method.Identifier,
                    account.Name);

                foreach (var scenario in output.Results)
                {
                    if (scenario.Errors.Count > 0)
                    {
                        FancyConsole.WriteLineIndented(
                            "  ",
                            FancyConsole.ConsoleSubheaderColor,
                            "Scenario: {0}",
                            scenario.Name);

                        foreach (var message in scenario.Errors)
                        {
                            if (options.EnableVerboseOutput || message.IsWarningOrError)
                            {
                                FancyConsole.WriteLineIndented(
                                    "    ",
                                    FancyConsole.ConsoleDefaultColor,
                                    message.ErrorText);
                            }
                        }

                        if (options.SilenceWarnings && scenario.Outcome == ValidationOutcome.Warning)
                        {
                            scenario.Outcome = ValidationOutcome.Passed;
                        }

                        FancyConsole.WriteLineIndented(
                            "    ",
                            scenario.Outcome.ConsoleColor(),
                            "Scenario finished with outcome: {0}. Duration: {1}",
                            scenario.Outcome,
                            scenario.Duration);
                    }
                }

                FancyConsole.WriteLineIndented(
                    "  ",
                    output.OverallOutcome.ConsoleColor(),
                    "Method testing finished with overall outcome: {0}",
                    output.OverallOutcome);
                FancyConsole.WriteLine();
            }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Breaks down the key/value string and adds to the request header
 /// </summary>
 /// <param name="headerKeyValueString"></param>
 /// <returns></returns>
 internal static void AddAdditionalHeadersToRequest(IServiceAccount account, HttpRequest request)
 {
     // parse the passed in addtional headers and add to request..format for headers should be <HeaderName>:<HeaderValue>
     if (account.AdditionalHeaders != null && account.AdditionalHeaders.Length > 0)
     {
         foreach (string nameValueHeader in account.AdditionalHeaders)
         {
             string[] split = nameValueHeader.Split(new Char[] { ':' }, 2);
             request.Headers.Add(split[0], split[1]);
         }
     }
 }
Ejemplo n.º 6
0
        /// <summary>
        ///  This method will adapt a request based on parameters for an account. It should be the last thing we do before sending
        ///  the request to the account.
        /// </summary>
        /// <param name="request"></param>
        /// <param name="account"></param>
        public void ModifyRequestForAccount(HttpRequest request, IServiceAccount account)
        {
            if (account.Transformations?.Request?.Actions?.Prefix == null)
            {
                return;
            }


            if (this.RequestMetadata.Target == TargetType.Action || this.RequestMetadata.Target == TargetType.Function)
            {
                // Add the ActionPrefix to the last path component of the URL
                AddPrefixToLastUrlComponent(request, account.Transformations.Request.Actions.Prefix);
            }
        }
        public static void Validate(IServiceAccount instance)
        {
            var userAccount = UserAccount.ParseAccountName(instance.ServiceAccount);

            if (!userAccount.CheckPassword(instance.ServiceAccountPwd))
            {
                throw new EngineValidationException("Password Invalid");
            }
            try
            {
                SetLogonAsAServicePrivilege(userAccount);
            }
            catch (Exception)
            {
                throw new Exception($"Failed to enable the LogonAsAService privilege on {instance.ServiceAccount}");
            }
        }
        public static void RewriteResponseBodyNamespaces(this HttpResponse response, IServiceAccount account, IssueLogger issues)
        {
            if (account.Transformations?.Response?.Properties == null)
            {
                return;
            }
            if (!response.IsMatchingContentType("application/json"))
            {
                return;
            }
            if (response.Body.Length == 0)
            {
                return;
            }

            var translatedBody = JsonRewriter.RewriteJsonProperties(response.Body, account.Transformations.Response.Properties, issues);

            response.Body = translatedBody;
        }
        /// <summary>
        /// Apply any namespace translations defined in the account to the parameters in the request body
        /// </summary>
        /// <param name="request"></param>
        /// <param name="account"></param>
        public static void RewriteRequestBodyNamespaces(this HttpRequest request, IServiceAccount account, IssueLogger issues)
        {
            if (account.Transformations?.Request?.Properties == null)
            {
                return;
            }

            if (request.IsMatchingContentType("application/json"))
            {
                var translatedBody = JsonRewriter.RewriteJsonProperties(request.Body, account.Transformations.Request.Properties, issues);
                request.Body = translatedBody;
            }
            else if (request.IsMatchingContentType("multipart/related"))
            {
                var parsedBody     = new MultipartMime.MultipartMimeContent(request.ContentType, request.Body);
                var partsToRewrite = parsedBody.PartsWithContentType("application/json");
                foreach (var part in partsToRewrite)
                {
                    part.Body = JsonRewriter.RewriteJsonProperties(part.Body, account.Transformations.Request.Properties, issues);
                }
                request.Body = parsedBody.ToString();
            }
        }
Ejemplo n.º 10
0
        public async Task <HttpResponse> GetResponseAsync(IServiceAccount account, int retryCount = 0)
        {
            var baseUrl = account.BaseUrl;

            this.RewriteRequestBodyNamespaces(account);

            var webRequest = this.PrepareHttpWebRequest(baseUrl);

            this.StartTime = DateTimeOffset.UtcNow;

            HttpResponse response = await HttpResponse.ResponseFromHttpWebResponseAsync(webRequest);

            TimeSpan duration = DateTimeOffset.UtcNow.Subtract(this.StartTime);

            response.RewriteResponseBodyNamespaces(account);

            var logger = HttpRequest.HttpLogSession;

            if (null != logger)
            {
                await logger.RecordSessionAsync(this, response, duration);
            }

            if (ShouldRetryRequest(response))
            {
                if (retryCount < ValidationConfig.RetryAttemptsOnServiceUnavailableResponse)
                {
                    // Do "full jitter" back off
                    await BackoffHelper.Default.FullJitterBackoffDelayAsync(retryCount);

                    // Try the request again
                    return(await this.GetResponseAsync(account, retryCount + 1));
                }
            }
            response.RetryCount = retryCount;
            return(response);
        }
Ejemplo n.º 11
0
        internal static async Task LogMethodTestResults(Validation.MethodDefinition method, IServiceAccount account, Validation.ValidationResults results)
        {
            foreach (var scenario in results.Results)
            {
                if (scenario.Outcome == ValidationOutcome.None)
                {
                    continue;
                }

                StringBuilder stdout = new StringBuilder();

                string message = null;
                if (scenario.Errors.Count > 0)
                {
                    stdout.AppendFormat("Scenario: {0}", scenario.Name);
                    foreach (var error in scenario.Errors)
                    {
                        stdout.AppendLine(error.ErrorText);

                        if (error.IsError && message == null)
                        {
                            message = error.ErrorText.FirstLineOnly();
                        }
                    }

                    stdout.AppendFormat(
                        "Scenario finished with outcome: {0}. Duration: {1}",
                        scenario.Outcome,
                        scenario.Duration);
                }

                string testName = string.Format(
                    "{0}: {1} [{2}]",
                    method.Identifier,
                    scenario.Name,
                    account.Name);

                string      filename = method.SourceFile.DisplayName;
                TestOutcome outcome  = ToTestOutcome(scenario.Outcome);

                await BuildWorkerApi.RecordTestAsync(
                    testName,
                    TestFrameworkName,
                    outcome : outcome,
                    durationInMilliseconds : (long)scenario.Duration.TotalMilliseconds,
                    errorMessage : message ?? scenario.Outcome.ToString(),
                    filename : filename,
                    stdOut : stdout.ToString());
            }
        }
Ejemplo n.º 12
0
        /// <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)
                    {
                        try
                        {
                            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));
                            }
                        }
                        catch (Exception ex)
                        {
                            return(new ValidationResult <HttpRequest>(null, new ValidationError(ValidationErrorCode.ConsolidatedError, null, "An exception occured while processing setup-requests: {0}", ex.Message)));
                        }
                    }
                }

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

            this.ModifyRequestForAccount(request, account);
            return(new ValidationResult <HttpRequest>(request, errors));
        }
Ejemplo n.º 13
0
        internal static async Task LogMethodTestResults(Validation.MethodDefinition method, IServiceAccount account, Validation.ValidationResults results)
        {
            foreach (var scenario in results.Results)
            {
                if (scenario.Outcome == ValidationOutcome.None)
                    continue;

                StringBuilder stdout = new StringBuilder();

                string message = null;
                if (scenario.Errors.Count > 0)
                {
                    stdout.AppendFormat("Scenario: {0}", scenario.Name);
                    foreach (var error in scenario.Errors)
                    {
                        stdout.AppendLine(error.ErrorText);

                        if (error.IsError && message == null)
                        {
                            message = error.ErrorText.FirstLineOnly();
                        }
                    }

                    stdout.AppendFormat(
                        "Scenario finished with outcome: {0}. Duration: {1}",
                        scenario.Outcome,
                        scenario.Duration);
                }

                string testName = string.Format(
                    "{0}: {1} [{2}]",
                    method.Identifier,
                    scenario.Name,
                    account.Name);
                
                string filename = method.SourceFile.DisplayName;
                TestOutcome outcome = ToTestOutcome(scenario.Outcome);

                await BuildWorkerApi.RecordTestAsync(
                        testName,
                        TestFrameworkName,
                        outcome: outcome,
                        durationInMilliseconds: (long)scenario.Duration.TotalMilliseconds,
                        errorMessage: message ?? scenario.Outcome.ToString(),
                        filename: filename,
                        stdOut: stdout.ToString());
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Make a call to the HttpRequest and populate the Value property of
        /// every PlaceholderValue in Values based on the result.
        /// </summary>
        /// <param name="storedValues"></param>
        /// <param name="documents"></param>
        /// <param name="scenario"></param>
        /// <param name="account"></param>
        /// <param name="parentOutputValues"></param>
        /// <returns></returns>
        public async Task <ValidationResult <bool> > MakeSetupRequestAsync(
            Dictionary <string, string> storedValues,
            DocSet documents,
            ScenarioDefinition scenario,
            IServiceAccount account,
            Dictionary <string, string> parentOutputValues = null)
        {
            // Copy the output values from parentOutputValues into our own
            if (null != parentOutputValues)
            {
                foreach (var key in parentOutputValues.Keys)
                {
                    this.OutputValues.Add(key, parentOutputValues[key]);
                }
            }

            var errors = new List <ValidationError>();

            if (!string.IsNullOrEmpty(this.CannedRequestName))
            {
                // We need to make a canned request setup request instead. Look up the canned request and then execute it, returning the results here.
                var cannedRequest =
                    (from cr in documents.CannedRequests where cr.Name == this.CannedRequestName select cr)
                    .FirstOrDefault();
                if (null == cannedRequest)
                {
                    errors.Add(new ValidationError(ValidationErrorCode.InvalidRequestFormat, null, "Couldn't locate the canned-request named: {0}", this.CannedRequestName));
                    return(new ValidationResult <bool>(false, errors));
                }


                // Need to make a copy of the canned request here so that our state doesn't continue to pile up
                var cannedRequestInstance = cannedRequest.CopyInstance();
                return(await cannedRequestInstance.MakeSetupRequestAsync(storedValues, documents, scenario, account, this.OutputValues));
            }

            // Get the HttpRequest, either from MethodName or by parsing HttpRequest
            HttpRequest request;
            var         issues = new IssueLogger();

            try
            {
                request = this.GetHttpRequest(documents, account, issues);
            }
            catch (Exception ex)
            {
                errors.Add(new ValidationError(ValidationErrorCode.InvalidRequestFormat, null, "An error occured creating the http request: {0}", ex.Message));
                return(new ValidationResult <bool>(false, errors));
            }
            MethodDefinition.AddTestHeaderToRequest(scenario, request);
            MethodDefinition.AddAdditionalHeadersToRequest(account, request);

            // If this is a canned request, we need to merge the parameters / placeholders here
            var placeholderValues = this.RequestParameters.ToPlaceholderValuesArray(storedValues);

            // Update the request with the parameters in request-parameters
            try
            {
                request.RewriteRequestWithParameters(placeholderValues);
            }
            catch (Exception ex)
            {
                errors.Add(new ValidationError(ValidationErrorCode.ParameterParserError, SourceName, "Error rewriting the request with parameters from the scenario: {0}", ex.Message));
                return(new ValidationResult <bool>(false, errors));
            }
            MethodDefinition.AddAccessTokenToRequest(account.CreateCredentials(), request);
            errors.Add(new ValidationMessage(null, "Test-setup request:\n{0}", request.FullHttpText()));

            try
            {
                var response = await request.GetResponseAsync(account, issues);

                errors.AddRange(issues.Issues);

                if (response.RetryCount > 0)
                {
                    errors.Add(new ValidationWarning(ValidationErrorCode.RequestWasRetried, null, "HTTP request was retried {0} times.", response.RetryCount));
                }
                errors.Add(new ValidationMessage(null, "HTTP Response:\n{0}\n\n", response.FullText()));

                // Check to see if this request is "successful" or not
                if ((this.AllowedStatusCodes == null && response.WasSuccessful) ||
                    (this.AllowedStatusCodes != null && this.AllowedStatusCodes.Contains(response.StatusCode)))
                {
                    string expectedContentType = (null != this.OutputValues) ? ExpectedResponseContentType(this.OutputValues.Values) : null;

                    // Check for content type mismatch
                    if (string.IsNullOrEmpty(response.ContentType) && expectedContentType != null)
                    {
                        return(new ValidationResult <bool>(false, new ValidationError(ValidationErrorCode.UnsupportedContentType, SourceName, "No Content-Type found for a non-204 response")));
                    }

                    // Load requested values into stored values
                    if (null != this.OutputValues)
                    {
                        foreach (var outputKey in this.OutputValues.Keys)
                        {
                            var source = this.OutputValues[outputKey];
                            storedValues[outputKey] = response.ValueForKeyedIdentifier(source);
                        }
                    }

                    return(new ValidationResult <bool>(!errors.Any(x => x.IsError), errors));
                }
                else
                {
                    if ((this.AllowedStatusCodes != null && !this.AllowedStatusCodes.Contains(response.StatusCode)) || !response.WasSuccessful)
                    {
                        string expectedCodes = "200-299";
                        if (this.AllowedStatusCodes != null)
                        {
                            expectedCodes = this.AllowedStatusCodes.ComponentsJoinedByString(",");
                        }
                        errors.Add(new ValidationError(ValidationErrorCode.HttpStatusCodeDifferent, SourceName, "Http response status code {0} didn't match expected values: {1}", response.StatusCode, expectedCodes));
                    }
                    else
                    {
                        errors.Add(new ValidationError(ValidationErrorCode.HttpStatusCodeDifferent, SourceName, "Http response content type was invalid: {0}", response.ContentType));
                    }

                    return(new ValidationResult <bool>(false, errors));
                }
            }
            catch (Exception ex)
            {
                errors.Add(new ValidationError(ValidationErrorCode.Unknown, SourceName, "Exception while making request: {0}", ex.Message));
                return(new ValidationResult <bool>(false, errors));
            }
        }
Ejemplo n.º 15
0
 public AppAccount(IAccount IAccount, IServiceAccount IServiceAccount)
 {
     _IAccount        = IAccount;
     _IServiceAccount = IServiceAccount;
 }
Ejemplo n.º 16
0
 private static void ConfigureAdditionalHeadersForAccount(CheckServiceOptions options, IServiceAccount account)
 {
     if (account.AdditionalHeaders != null && account.AdditionalHeaders.Length > 0)
     {
         // If the account needs additional headers, merge them in.
         List <string> headers = new List <string>(account.AdditionalHeaders);
         if (options.AdditionalHeaders != null)
         {
             headers.AddRange(options.AdditionalHeaders.Split('|'));
         }
         ValidationConfig.AdditionalHttpHeaders = headers.ToArray();
     }
     else if (options.AdditionalHeaders != null)
     {
         var headers = options.AdditionalHeaders.Split('|');
         ValidationConfig.AdditionalHttpHeaders = headers.ToArray();
     }
 }
Ejemplo n.º 17
0
 /// <summary>
 /// Breaks down the key/value string and adds to the request header
 /// </summary>
 /// <param name="headerKeyValueString"></param>
 /// <returns></returns>
 internal static void AddAdditionalHeadersToRequest(IServiceAccount account, HttpRequest request)
 {
     // parse the passed in addtional headers and add to request..format for headers should be <HeaderName>:<HeaderValue>
     if (account.AdditionalHeaders != null && account.AdditionalHeaders.Length > 0)
     {
         foreach (string nameValueHeader in account.AdditionalHeaders)
         {
             string[] split = nameValueHeader.Split(new Char[] { ':' }, 2);
             request.Headers.Add(split[0], split[1]);
         }
     }
 }    
Ejemplo n.º 18
0
        private static HttpRequest HttpRequestForCannedRequest(string requestName, DocSet docset, IServiceAccount account, IssueLogger issues)
        {
            var queryForRequest = from m in docset.CannedRequests
                                  where m.Name == requestName
                                  select m;
            var foundRequest = queryForRequest.FirstOrDefault();

            if (null == foundRequest)
            {
                throw new Exception(string.Format("Failed to find canned response {0} in the docset.", requestName));
            }

            return(GetHttpRequest(foundRequest, docset, account, issues));
        }
Ejemplo n.º 19
0
        private static HttpRequest LookupHttpRequestForMethod(string methodName, DocSet docset, IServiceAccount account, IssueLogger issues)
        {
            var queryForMethod = from m in docset.Methods
                                 where m.Identifier == methodName
                                 select m;

            var foundMethod = queryForMethod.FirstOrDefault();

            if (null == foundMethod)
            {
                throw new Exception(string.Format("Failed to locate method {0} in the docset.", methodName));
            }

            var request = ParseHttpRequest(foundMethod.Request, issues);

            foundMethod.ModifyRequestForAccount(request, account);

            return(request);
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Locate the Http.HttpRequest instance for this request definition either by
        /// parsing the RawHttpRequest or resolving MethodName into a request.
        /// </summary>
        /// <param name="definition"></param>
        /// <param name="documents"></param>
        /// <returns></returns>
        public static HttpRequest GetHttpRequest(this BasicRequestDefinition definition, DocSet documents, IServiceAccount account, IssueLogger issues)
        {
            HttpRequest foundRequest = null;

            if (!string.IsNullOrEmpty(definition.RawHttpRequest))
            {
                foundRequest = ParseHttpRequest(definition.RawHttpRequest, issues);
            }
            else if (!string.IsNullOrEmpty(definition.MethodName))
            {
                foundRequest = LookupHttpRequestForMethod(definition.MethodName, documents, account, issues);
            }
            else if (!string.IsNullOrEmpty(definition.CannedRequestName))
            {
                foundRequest = HttpRequestForCannedRequest(definition.CannedRequestName, documents, account, issues);
            }

            return(foundRequest);
        }
Ejemplo n.º 21
0
        /// <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);
        }
Ejemplo n.º 22
0
        private static async Task ValidateMethodWithScenarioAsync(
            MethodDefinition method,
            ScenarioDefinition scenario,
            IServiceAccount account,
            AuthenicationCredentials credentials,
            ValidationResults results,
            ValidationOptions options = null)
        {
            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;

            // Check to see if the account + scenario scopes are aligned

            string[] requiredScopes = method.RequiredScopes.Union(scenario.RequiredScopes).ToArray();

            if (!account.Scopes.ProvidesScopes(requiredScopes, options.IgnoreRequiredScopes))
            {
                var missingScopes = from scope in requiredScopes where !account.Scopes.Contains(scope) select scope;

                results.AddResult(actionName,
                                  new ValidationWarning(ValidationErrorCode.RequiredScopesMissing,
                                                        null,
                                                        "Scenario was not run. Scopes required were not available: {0}", missingScopes.ComponentsJoinedByString(",")));
                return;
            }

            // 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, options);

            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);
            }
        }
Ejemplo n.º 23
0
        public AccountController(IServiceUser serviceUser,  IServiceAccount serviceAccount)
        {
            if (serviceAccount == null) throw new ArgumentNullException("serviceAccount cannot be null");
            if (serviceUser == null) throw new ArgumentNullException("serviceUser cannot be null");

            _serviceUser = serviceUser;
            _serviceAccount = serviceAccount;
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Execute the provided methods on the given account.
        /// </summary>
        /// <param name="options"></param>
        /// <param name="account"></param>
        /// <param name="methods"></param>
        /// <param name="docset"></param>
        /// <returns>True if the methods all passed, false if there were failures.</returns>
        private static async Task <bool> CheckMethodsForAccountAsync(CheckServiceOptions options, IServiceAccount account, MethodDefinition[] methods, DocSet docset)
        {
            //CheckResults results = new CheckResults();

            ConfigureAdditionalHeadersForAccount(options, account);

            string testNamePrefix = account.Name.ToLower() + ": ";

            FancyConsole.WriteLine(FancyConsole.ConsoleHeaderColor, "Testing with account: {0}", account.Name);

            FancyConsole.WriteLine(FancyConsole.ConsoleCodeColor, "Preparing authentication for requests...", account.Name);
            try
            {
                await account.PrepareForRequestAsync();
            }
            catch (Exception ex)
            {
                RecordError(ex.Message);
                return(false);
            }

            AuthenicationCredentials credentials = account.CreateCredentials();
            int concurrentTasks = options.ParallelTests ? ParallelTaskCount : 1;

            CheckResults docSetResults = new CheckResults();

            await ForEachAsync(methods, concurrentTasks, async method =>
            {
                FancyConsole.WriteLine(
                    FancyConsole.ConsoleCodeColor,
                    "Running validation for method: {0}",
                    method.Identifier);
                ScenarioDefinition[] scenarios = docset.TestScenarios.ScenariosForMethod(method);
                ValidationResults results      = await method.ValidateServiceResponseAsync(scenarios, account, credentials);

                PrintResultsToConsole(method, account, results, options);
                await TestReport.LogMethodTestResults(method, account, results);
                docSetResults.RecordResults(results, options);

                if (concurrentTasks == 1)
                {
                    AddPause(options);
                }
            });

            if (options.IgnoreWarnings || options.SilenceWarnings)
            {
                // Remove the warning flag from the outcomes
                docSetResults.ConvertWarningsToSuccess();
            }

            docSetResults.PrintToConsole();

            bool hadWarnings = docSetResults.WarningCount > 0;
            bool hadErrors   = docSetResults.FailureCount > 0;

            return(!(hadErrors | hadWarnings));
        }
        /// <summary>
        /// Make a call to the HttpRequest and populate the Value property of 
        /// every PlaceholderValue in Values based on the result.
        /// </summary>
        /// <param name="storedValues"></param>
        /// <param name="documents"></param>
        /// <param name="scenario"></param>
        /// <param name="account"></param>
        /// <param name="parentOutputValues"></param>
        /// <returns></returns>
        public async Task<ValidationResult<bool>> MakeSetupRequestAsync(Dictionary<string, string> storedValues, DocSet documents, ScenarioDefinition scenario, IServiceAccount account, Dictionary<string, string> parentOutputValues = null)
        {  
            // Copy the output values from parentOutputValues into our own
            if (null != parentOutputValues)
            {
                foreach (var key in parentOutputValues.Keys)
                {
                    this.OutputValues.Add(key, parentOutputValues[key]);
                }
            }

            var errors = new List<ValidationError>();
            if (!string.IsNullOrEmpty(this.CannedRequestName))
            {
                // We need to make a canned request setup request instead. Look up the canned request and then execute it, returning the results here.
                var cannedRequest =
                    (from cr in documents.CannedRequests where cr.Name == this.CannedRequestName select cr)
                        .FirstOrDefault();
                if (null == cannedRequest)
                {
                    errors.Add(new ValidationError(ValidationErrorCode.InvalidRequestFormat, null, "Couldn't locate the canned-request named: {0}", this.CannedRequestName));
                    return new ValidationResult<bool>(false, errors);
                }


                // Need to make a copy of the canned request here so that our state doesn't continue to pile up
                var cannedRequestInstance = cannedRequest.CopyInstance();
                return await cannedRequestInstance.MakeSetupRequestAsync(storedValues, documents, scenario, account, this.OutputValues);
            }
            
            // Get the HttpRequest, either from MethodName or by parsing HttpRequest
            HttpRequest request;
            try
            {
                request = this.GetHttpRequest(documents);
            }
            catch (Exception ex)
            {
                errors.Add(new ValidationError(ValidationErrorCode.InvalidRequestFormat, null, "An error occured creating the http request: {0}", ex.Message));
                return new ValidationResult<bool>(false, errors);
            }

            MethodDefinition.AddTestHeaderToRequest(scenario, request);
            MethodDefinition.AddAdditionalHeadersToRequest(account, request);            

            // If this is a canned request, we need to merge the parameters / placeholders here
            var placeholderValues = this.RequestParameters.ToPlaceholderValuesArray(storedValues);

            // Update the request with the parameters in request-parameters
            try
            {
                request.RewriteRequestWithParameters(placeholderValues);
            }
            catch (Exception ex)
            {
                errors.Add(new ValidationError(ValidationErrorCode.ParameterParserError, SourceName, "Error rewriting the request with parameters from the scenario: {0}", ex.Message));
                return new ValidationResult<bool>(false, errors);
            }
            MethodDefinition.AddAccessTokenToRequest(account.CreateCredentials(), request);
            errors.Add(new ValidationMessage(null, "Test-setup request:\n{0}", request.FullHttpText()));

            try
            {
                var response = await request.GetResponseAsync(account.BaseUrl);
                if (response.RetryCount > 0)
                {
                    errors.Add(new ValidationWarning(ValidationErrorCode.RequestWasRetried, null, "HTTP request was retried {0} times.", response.RetryCount));
                }
                errors.Add(new ValidationMessage(null, "HTTP Response:\n{0}\n\n", response.FullText()));

                // Check to see if this request is "successful" or not
                if ( (this.AllowedStatusCodes == null && response.WasSuccessful) ||
                    (this.AllowedStatusCodes != null && this.AllowedStatusCodes.Contains(response.StatusCode)))
                {
                    string expectedContentType = (null != this.OutputValues) ? ExpectedResponseContentType(this.OutputValues.Values) : null;

                    // Check for content type mismatch
                    if (string.IsNullOrEmpty(response.ContentType) && expectedContentType != null)
                    {
                        return new ValidationResult<bool>(false, new ValidationError(ValidationErrorCode.UnsupportedContentType, SourceName, "No Content-Type found for a non-204 response"));
                    }

                    // Load requested values into stored values
                    if (null != this.OutputValues)
                    {
                        foreach (var outputKey in this.OutputValues.Keys)
                        {
                            var source = this.OutputValues[outputKey];
                            storedValues[outputKey] = response.ValueForKeyedIdentifier(source);
                        }
                    }

                    return new ValidationResult<bool>(!errors.Any(x => x.IsError), errors);
                }
                else
                {
                    if ((this.AllowedStatusCodes != null && !this.AllowedStatusCodes.Contains(response.StatusCode)) || !response.WasSuccessful)
                    {
                        string expectedCodes = "200-299";
                        if (this.AllowedStatusCodes != null)
                            expectedCodes = this.AllowedStatusCodes.ComponentsJoinedByString(",");
                        errors.Add(new ValidationError(ValidationErrorCode.HttpStatusCodeDifferent, SourceName, "Http response status code {0} didn't match expected values: {1}", response.StatusCode, expectedCodes));
                    }
                    else
                    {
                        errors.Add(new ValidationError(ValidationErrorCode.HttpStatusCodeDifferent, SourceName, "Http response content type was invalid: {0}", response.ContentType));
                    }
                    
                    return new ValidationResult<bool>(false, errors);
                }
            }
            catch (Exception ex)
            {
                errors.Add(new ValidationError(ValidationErrorCode.Unknown, SourceName, "Exception while making request: {0}", ex.Message));
                return new ValidationResult<bool>(false, errors);
            }
        }
Ejemplo n.º 26
0
 public TransactionController(IServiceTransaction services, IEventBus bus, IServiceAccount servicesAccount)
 {
     _services        = services;
     _bus             = bus;
     _servicesAccount = servicesAccount;
 }
        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);
        }
Ejemplo n.º 28
0
 public AccountController(IServiceAccount services)
 {
     _services = services;
 }