// Verifies if a tracked resource has a corresponding PATCH operation public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Schema> definitions, RuleContext context) { ServiceDefinition serviceDefinition = (ServiceDefinition)context.Root; // enumerate all the PATCH operations IEnumerable <Operation> patchOperations = ValidationUtilities.GetOperationsByRequestMethod("patch", serviceDefinition); foreach (var op in patchOperations) { var reqModels = op.Parameters.Where(p => p.In == ParameterLocation.Body).Select(p => p.Schema?.Reference?.StripDefinitionPath()).Where(p => !string.IsNullOrEmpty(p)); foreach (var reqModel in reqModels) { // select all models that have properties set to required var reqProps = ValidationUtilities.EnumerateRequiredProperties(reqModel, definitions); // select all models that have properties with default values var defValProps = ValidationUtilities.EnumerateDefaultValuedProperties(reqModel, definitions); var modelHierarchy = ValidationUtilities.EnumerateModelHierarchy(reqModel, definitions); foreach (var reqProp in reqProps) { var modelContainingReqProp = modelHierarchy.First(model => definitions[model].Required?.Contains(reqProp) == true); yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(modelContainingReqProp).AppendProperty("required")), this, "required", op.OperationId, modelContainingReqProp, reqProp)); } foreach (var defValProp in defValProps) { var modelContainingDefValProp = modelHierarchy.First(model => definitions[model].Properties?.Contains(defValProp) == true); yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty(modelContainingDefValProp).AppendProperty("properties").AppendProperty(defValProp.Key)), this, "default-valued", op.OperationId, modelContainingDefValProp, defValProp.Key)); } } } }
/// <summary> /// Verifies whether the location property for a tracked resource has the x-ms-mutability extension set correctly /// </summary> /// <param name="definitions"></param> /// <param name="context"></param> /// <returns></returns> public override IEnumerable <ValidationMessage> GetValidationMessages(Dictionary <string, Schema> definitions, RuleContext context) { var trackedResources = context.TrackedResourceModels; foreach (var resource in trackedResources) { var modelHierarchy = ValidationUtilities.EnumerateModelHierarchy(resource, definitions); var modelsWithLocationProp = modelHierarchy.Where(model => (definitions[model].Required?.Contains("location") == true) && (definitions[model].Properties?.ContainsKey("location") == true)); if (modelsWithLocationProp.Any()) { var modelWithLocationProp = modelsWithLocationProp.First(); if (definitions[modelWithLocationProp].Properties["location"].Extensions?.ContainsKey("x-ms-mutability") != true) { yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty("properties").AppendProperty("location")), this, modelWithLocationProp)); } else { var jObject = JsonConvert.DeserializeObject <object[]>(definitions[modelWithLocationProp].Properties["location"].Extensions["x-ms-mutability"].ToString()); // make sure jObject and the expected mutability properties have exact same elements if (jObject.Except(LocationPropertyMutability).Any() || LocationPropertyMutability.Except(jObject).Any()) { yield return(new ValidationMessage(new FileObjectPath(context.File, context.Path.AppendProperty("properties").AppendProperty("location").AppendProperty("x-ms-mutability")), this, resource)); } } } } }
// 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)); } }