/// <summary> /// Verifies whether an LRO PUT operation returns response models for /// 200/201 status codes /// </summary> /// <param name="definitions"></param> /// <param name="context"></param> /// <returns></returns> public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Dictionary <string, Operation> > paths, RuleContext context) { var serviceDefinition = (ServiceDefinition)context.Root; foreach (var path in paths) { var lroPutOps = path.Value.Where(val => val.Key.ToLower().Equals("put")).Select(val => val.Value); foreach (var op in lroPutOps) { if (op.Responses == null) { // if put operation has no response model, let some other validation rule handle the violation continue; } foreach (var resp in op.Responses) { if (resp.Key == "200" || resp.Key == "201") { var modelRef = resp.Value?.Schema?.Reference ?? string.Empty; if (!serviceDefinition.Definitions.ContainsKey(modelRef.StripDefinitionPath())) { var violatingVerb = ValidationUtilities.GetOperationIdVerb(op.OperationId, path); yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(path.Key).AppendProperty(violatingVerb).AppendProperty("responses").AppendProperty(resp.Key)), this, op.OperationId, resp.Key)); } } } } } }
// 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)); } }
/// 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)); } } }