public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Dictionary <string, Operation> > entity, RuleContext context)
        {
            // get all operation objects that are either of get or post type
            ServiceDefinition serviceDefinition = context.Root;
            var listOperations = entity.Values.SelectMany(opDict => opDict.Where(pair => pair.Key.ToLower().Equals("get") || pair.Key.ToLower().Equals("post")));

            foreach (var opPair in listOperations)
            {
                // if the operation id is not of type _list* or does not return an array type, skip
                if (!ListRegex.IsMatch(opPair.Value.OperationId) || !ValidationUtilities.IsXmsPageableResponseOperation(opPair.Value))
                {
                    continue;
                }

                string collType = opPair.Value.Responses.GetValueOrNull("200")?.Schema?.Reference?.StripDefinitionPath();
                // if no response type defined skip
                if (collType == null)
                {
                    continue;
                }

                var collTypeDef = serviceDefinition.Definitions[collType];
                // if collection object has 2 properties or less (x-ms-pageable objects can have the nextlink prop)
                // and the object does not have a property named "value", show the warning
                if ((collTypeDef.Properties?.Count <= 2) && collTypeDef.Properties.All(prop => !(prop.Key.ToLower().Equals("value") && prop.Value.Type == DataType.Array)))
                {
                    var violatingPath = ValidationUtilities.GetOperationIdPath(opPair.Value.OperationId, entity);
                    yield return(new ValidationMessage(new FileObjectPath(context.File,
                                                                          context.Path.AppendProperty(violatingPath.Key).AppendProperty(opPair.Key).AppendProperty("responses").AppendProperty("200").AppendProperty("schema")),
                                                       this, collType, opPair.Value.OperationId));
                }
            }
        }
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Dictionary <string, Operation> > entity, RuleContext context)
        {
            // get all operation objects that are either of get or post type
            var serviceDefinition = (ServiceDefinition)context.Root;
            var listOperations    = entity.Values.SelectMany(opDict => opDict.Where(pair => pair.Key.ToLower().Equals("get") || pair.Key.ToLower().Equals("post")));

            foreach (var opPair in listOperations)
            {
                // if the operation id is already of the type _list we can skip this check
                if (ListRegex.IsMatch(opPair.Value.OperationId))
                {
                    continue;
                }

                var violatingPath = ValidationUtilities.GetOperationIdPath(opPair.Value.OperationId, entity).Key;
                if (ValidationUtilities.IsXmsPageableResponseOperation(opPair.Value))
                {
                    yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(violatingPath).AppendProperty(opPair.Key).AppendProperty("operationId")), this, opPair.Value.OperationId, XmsPageableViolation));
                }
                else if (ValidationUtilities.IsArrayTypeResponseOperation(opPair.Value, serviceDefinition))
                {
                    yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(violatingPath).AppendProperty(opPair.Key).AppendProperty("operationId")), this, opPair.Value.OperationId, ArrayTypeViolation));
                }
            }
        }
Exemple #3
0
        // Verifies if a tracked resource has a corresponding PATCH operation
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Dictionary <string, Operation> > paths, RuleContext context)
        {
            var serviceDefinition = context.Root;
            var ops           = ValidationUtilities.GetOperationsByRequestMethod("put", serviceDefinition);
            var putRespModels = ops.Select(op => (op.Responses?.ContainsKey("200") != true) ? null : op.Responses["200"].Schema?.Reference?.StripDefinitionPath());

            putRespModels = putRespModels.Where(modelName => !string.IsNullOrEmpty(modelName));
            var xmsResModels    = ValidationUtilities.GetXmsAzureResourceModels(serviceDefinition.Definitions);
            var violatingModels = putRespModels.Where(respModel => !ValidationUtilities.EnumerateModelHierarchy(respModel, serviceDefinition.Definitions).Intersect(xmsResModels).Any());

            foreach (var model in violatingModels)
            {
                var violatingOp     = ops.Where(op => (op.Responses?.ContainsKey("200") == true) && op.Responses["200"]?.Schema?.Reference?.StripDefinitionPath() == model).First();
                var violatingPath   = ValidationUtilities.GetOperationIdPath(violatingOp.OperationId, paths);
                var violatingOpVerb = ValidationUtilities.GetOperationIdVerb(violatingOp.OperationId, violatingPath);
                yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(violatingPath.Key).AppendProperty(violatingOpVerb)), this, violatingOp.OperationId, model));
            }
        }
Exemple #4
0
        /// Verifies if a PUT operation request and response schemas match
        public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Dictionary <string, Operation> > paths, RuleContext context)
        {
            var serviceDefinition = (ServiceDefinition)context.Root;
            var ops = ValidationUtilities.GetOperationsByRequestMethod("put", serviceDefinition);

            foreach (var op in ops)
            {
                // if PUT operation does not have any request parameters, skip, let some other validation rule handle it
                // if no 200 response exists, skip, let some other validation rule handle empty PUT response operations
                if (op.Parameters?.Any() != true || op.Responses?.ContainsKey("200") != true || serviceDefinition.Definitions?.Any() != true)
                {
                    continue;
                }

                // look for the request body schema in the operation parameters section as well as the global parameters section
                string reqBodySchema = null;
                if (op.Parameters.Any(p => p.In == ParameterLocation.Body))
                {
                    reqBodySchema = op.Parameters.First(p => p.In == ParameterLocation.Body).Schema?.Reference?.StripDefinitionPath();
                }
                else
                {
                    var opGlobalParams = op.Parameters.Where(p => serviceDefinition.Parameters.ContainsKey(p.Reference?.StripParameterPath() ?? ""));
                    if (opGlobalParams.Any())
                    {
                        reqBodySchema = opGlobalParams.FirstOrDefault(p => p.In == ParameterLocation.Body)?.Schema?.Reference?.StripDefinitionPath();
                    }
                }

                // if no body parameters were found, skip, let some other validation handle an empty body put operation
                if (string.IsNullOrEmpty(reqBodySchema) || !serviceDefinition.Definitions.ContainsKey(reqBodySchema))
                {
                    continue;
                }
                var respModel = op.Responses["200"]?.Schema?.Reference?.StripDefinitionPath() ?? string.Empty;
                // if the 200 response schema does not match the request body parameter schema, flag violation
                if (respModel != reqBodySchema)
                {
                    var violatingPath   = ValidationUtilities.GetOperationIdPath(op.OperationId, paths);
                    var violatingOpVerb = ValidationUtilities.GetOperationIdVerb(op.OperationId, violatingPath);
                    yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(violatingPath.Key).AppendProperty(violatingOpVerb)), this, op.OperationId, reqBodySchema, respModel));
                }
            }
        }