public void Validate_MissingDescriptions_ThrowsException() { var mainArmTemplateFile = MainArmTemplateFile.ReadFromFileSystem(this.fileSystem); var mainArmTemplateFileElement = JsonElementFactory.CreateElement(mainArmTemplateFile.Content); var patchedElement = mainArmTemplateFileElement.Patch( JsonPatchOperations.Remove("/parameters/sshRSAPublicKey/metadata/description"), JsonPatchOperations.Remove("/parameters/clusterName/metadata/description"), JsonPatchOperations.Remove("/parameters/osDiskSizeGB/metadata/description"), JsonPatchOperations.Remove("/outputs/controlPlaneFQDN/metadata/description")); fileSystem.AddFile(mainArmTemplateFile.Path, patchedElement.ToJsonString()); var latestArmTemplateFile = MainArmTemplateFile.ReadFromFileSystem(this.fileSystem); var sut = this.CreateDescriptionsValidator(latestArmTemplateFile); FluentActions.Invoking(() => sut.Validate(this.fileToValidate)).Should() .Throw <InvalidModuleFileException>() .WithMessage( $@"The file ""{this.fileToValidate.Path}"" is invalid. Descriptions for the following parameters are missing: - sshRSAPublicKey - clusterName - osDiskSizeGB The file ""{this.fileToValidate.Path}"" is invalid. Descriptions for the following outputs are missing: - controlPlaneFQDN ".ReplaceLineEndings()); }
public override JsonElement Execute(JsonElement input) { input = Expression.Execute(input); bool result = input.IsTruthy(); return(JsonElementFactory.CreateBool(result)); }
public override JsonElement Execute(JsonElement input) { input = ExecutedOn.Execute(input); if (input.ValueKind != JsonValueKind.Array) { return(JsonElementFactory.CreateNull()); } List <JsonElement> array = input.EnumerateArray().ToList(); if (IsAllArrayElemets) { return(input); } if (ExactElementsAccess != null && ExactElementsAccess.Any()) { IEnumerable <JsonElement> res = array.GetByIndexes(ExactElementsAccess); return(JsonElementFactory.CreateArray(res)); } List <JsonElement> result = array.GetSlice(SliceStart, SliceEnd, SliceStep); return(JsonElementFactory.CreateArray(result)); }
public void PropertyFilterSubExpression_DeeplyNestedProperty_ReturnsCorrectValue() { string json = @" { `a`: { `b`: { `c`: { `d`: { `e`: 4 } } } } }" .Replace("`", "\""); JsonElement data = JsonDocument.Parse(json).RootElement; FilterSubExpression exp = FilterParser.Parse(FilterExpressionTokenizer.Tokenize("@.a.b.c.d.e == @.b")); exp = (exp as ComparisonFilterSubExpression)?.LeftSide as PropertyFilterSubExpression; Assert.NotNull(exp); JsonElement expected = JsonElementFactory.CreateNumber(4); JsonElement result = exp.Execute(data); Assert.Equal(expected, result, JsonElementEqualityComparer.Default); }
public void Validate(MainBicepTestFile file) { var tempFilePath = this.fileSystem.Path.GetTempFileName(); try { bicepCliProxy.Build(file.Path, tempFilePath); } catch (Exception exception) { this.fileSystem.File.Delete(tempFilePath); if (exception is BicepException) { // Failed to build the test file. Convert it to InvalidModuleException so that // the validate command can continue validating other files. throw new InvalidModuleException(exception.Message, exception); } throw; } this.logger.LogInformation("Making sure the test file contains at least one test..."); using var tempFileStream = fileSystem.FileStream.CreateDeleteOnCloseStream(tempFilePath); var testTemplateElement = JsonElementFactory.CreateElement(tempFileStream); var testDeployments = testTemplateElement.Select($@"$.resources[?(@.type == ""Microsoft.Resources/deployments"" && @.properties.template.metadata._generator.templateHash == ""{this.latestMainArmTemplateFile.TemplateHash}"")]"); if (testDeployments.IsEmpty()) { throw new InvalidModuleException($"The file \"{file.Path}\" is invalid. Could not find tests in the file. Please make sure to add at least one module referencing the main Bicep file."); } }
public override JsonElement Execute(JsonElement input) { JsonElement left = LeftSide.Execute(input); JsonElement right = RightSide.Execute(input); bool result = false; if ((IsEqual || IsGreaterOrEqual || IsLessOrEqual) && JsonElementEqualityComparer.Default.Equals(left, right)) { result = true; } else if (IsNotEqual && !JsonElementEqualityComparer.Default.Equals(left, right)) { result = true; } else if (left.ValueKind == right.ValueKind) { int r = JsonElementComparer.Default.Compare(left, right); if ((IsGreater || IsGreaterOrEqual) && r > 0) { result = true; } else if ((IsLess || IsLessOrEqual) && r < 0) { result = true; } } return(JsonElementFactory.CreateBool(result)); }
public void DifferentStrings_ReturnsFalse() { JsonElement n1 = JsonElementFactory.CreateString("a"); JsonElement n2 = JsonElementFactory.CreateString(" a"); bool result = JsonElementEqualityComparer.Default.Equals(n1, n2); Assert.False(result); }
public void SameStrings_ReturnsTrue() { JsonElement n1 = JsonElementFactory.CreateString("abc"); JsonElement n2 = JsonElementFactory.CreateString("abc"); bool result = JsonElementEqualityComparer.Default.Equals(n1, n2); Assert.True(result); }
public void DifferentNumbers_ReturnsFalse() { JsonElement n1 = JsonElementFactory.CreateNumber(1.123); JsonElement n2 = JsonElementFactory.CreateNumber(1.121); bool result = JsonElementEqualityComparer.Default.Equals(n1, n2); Assert.False(result); }
public void SameNumbers_ReturnsTrue() { JsonElement n1 = JsonElementFactory.CreateNumber(1.123); JsonElement n2 = JsonElementFactory.CreateNumber(1.123); bool result = JsonElementEqualityComparer.Default.Equals(n1, n2); Assert.True(result); }
public void DifferentBools_ReturnsTrue() { JsonElement n1 = JsonElementFactory.CreateBool(true); JsonElement n2 = JsonElementFactory.CreateBool(false); bool result = JsonElementEqualityComparer.Default.Equals(n1, n2); Assert.False(result); }
public void DifferentTypes_ReturnsFalse() { JsonElement n1 = JsonElementFactory.CreateBool(true); JsonElement n2 = JsonElementFactory.CreateArray(new List <object> { 1, "abc", 3 }); bool result = JsonElementEqualityComparer.Default.Equals(n1, n2); Assert.False(result); }
public void SameArrays_ReturnsTrue() { JsonElement n1 = JsonElementFactory.CreateArray(new List <object> { 1, "abc", false }); JsonElement n2 = JsonElementFactory.CreateArray(new List <object> { 1, "abc", false }); bool result = JsonElementEqualityComparer.Default.Equals(n1, n2); Assert.True(result); }
public MainArmTemplateFile(string path, string content) : base(path) { this.Content = content; this.lazyRootElement = new(() => JsonElementFactory.CreateElement(content)); this.lazyParameters = new(() => !lazyRootElement.Value.TryGetProperty("parameters", out var parametersElement) ? Enumerable.Empty <MainArmTemplateParameter>() : parametersElement.EnumerateObject().Select(ToParameter)); this.lazyOutputs = new(() => !lazyRootElement.Value.TryGetProperty("outputs", out var outputsElement) ? Enumerable.Empty <MainArmTemplateOutput>() : outputsElement.EnumerateObject().Select(ToOutput)); }
public void PropertyFilterSubExpression_LengthOnArray_ReturnsCorrectValue() { string json = "{ \"a\": [ \"abc\" ] }"; JsonElement data = JsonDocument.Parse(json).RootElement; FilterSubExpression exp = FilterParser.Parse(FilterExpressionTokenizer.Tokenize("@.a.length == @.b")); exp = (exp as ComparisonFilterSubExpression)?.LeftSide as PropertyFilterSubExpression; Assert.NotNull(exp); JsonElement expected = JsonElementFactory.CreateNumber(1); JsonElement result = exp.Execute(data); Assert.Equal(expected, result, JsonElementEqualityComparer.Default); }
public override JsonElement Execute(JsonElement input) { JsonElement result = JsonElementFactory.CreateNull(); if (PropertyChain.Length == 0) { result = input; } foreach (string p in PropertyChain) { if (p == "length" && input.TryGetArrayOrStringLength(out int length)) { result = JsonElementFactory.CreateNumber(length); } else if (input.ValueKind == JsonValueKind.Object && input.TryGetProperty(p, out JsonElement t)) { result = t; input = t; } else { return(JsonElementFactory.CreateNull()); } } if (IsWhildcard) { JsonElement[] resultArray = new JsonElement[0]; if (result.ValueKind == JsonValueKind.Object) { resultArray = result.EnumerateObject().Select(x => x.Value).ToArray(); } else if (result.ValueKind == JsonValueKind.Array) { return(result); } return(JsonElementFactory.CreateArray(resultArray)); } if (IsRecursive) { return(JsonElementFactory.CreateArray(result.EnumerateRecursively())); } return(result); }
public static MainArmTemplateParametersFile ReadFromFileSystem(IFileSystem fileSystem) { var path = fileSystem.Path.GetFullPath(FileName); try { var content = fileSystem.File.ReadAllText(path); var jsonElement = JsonElementFactory.CreateElement(content); return(new(path, content, jsonElement)); } catch (JsonException jsonException) { throw new BicepException($"The ARM template parameters file \"{path}\" is not a valid JSON file. {jsonException.Message}"); } }
public static MetadataFile ReadFromFileSystem(IFileSystem fileSystem) { var path = fileSystem.Path.GetFullPath(FileName); try { using var stream = fileSystem.FileStream.Create(path, FileMode.Open, FileAccess.Read); var jsonElement = JsonElementFactory.CreateElement(stream); return(new(path, jsonElement)); } catch (JsonException jsonException) { throw new BicepException($"The metadata file \"{path}\" is not a valid JSON file. {jsonException.Message}"); } }
public static MainArmTemplateParametersFile Generate(IFileSystem fileSystem, MainArmTemplateFile mainArmTemplateFile) { var bufferWriter = new ArrayBufferWriter <byte>(); using (var writer = new Utf8JsonWriter(bufferWriter, new JsonWriterOptions { Indented = true })) { writer.WriteStartObject(); writer.WriteString("$schema", "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"); writer.WriteString("contentVersion", "1.0.0.0"); writer.WritePropertyName("parameters"); writer.WriteStartObject(); var parameterInstances = GenerateParameterInstances(fileSystem, mainArmTemplateFile); foreach (var(parameterName, parameterValue) in parameterInstances) { writer.WritePropertyName(parameterName); writer.WriteStartObject(); if (parameterValue is not null) { writer.WritePropertyName("value"); JsonElementFactory.CreateElement(parameterValue).WriteTo(writer); } writer.WriteEndObject(); } writer.WriteEndObject(); writer.WriteEndObject(); } var path = fileSystem.Path.GetFullPath(FileName); var content = Encoding.UTF8.GetString(bufferWriter.WrittenSpan); var rootElement = JsonElementFactory.CreateElement(bufferWriter.WrittenMemory); return(new(path, content, rootElement)); }
private static JsonElement GetParameters(string parameterFilePath) { if (string.IsNullOrWhiteSpace(parameterFilePath)) { return(JsonElementFactory.CreateElement("{}")); } else { try { string text = File.ReadAllText(parameterFilePath); return(JsonElementFactory.CreateElement(text)); } catch (Exception e) { throw new Exception(string.Format(LangServerResources.InvalidParameterFileDeploymentFailedMessage, e.Message)); } } }
public static VersionFile ReadFromFileSystem(IFileSystem fileSystem) { var path = fileSystem.Path.GetFullPath(FileName); try { var content = fileSystem.File.ReadAllText(FileName); var rootElement = JsonElementFactory.CreateElement(content); if (rootElement.ValueKind != JsonValueKind.Object) { throw new BicepException($"The version file \"{path}\" must contain a JSON object at the root level."); } return(new(path, content, rootElement)); } catch (JsonException jsonException) { throw new BicepException($"The version file \"{path}\" is not a valid JSON file. {jsonException.Message}"); } }
public override JsonElement Execute(JsonElement input) { if (input.IsNullOrUndefined()) { return(JsonElementFactory.CreateNull()); } List <JsonElement> args = Arguments.Select(x => x.Execute(input)).ToList(); input = CalledOnExpression.Execute(input); if (input.ValueKind == JsonValueKind.String && input.TryExecuteStringMethod(MethodName, args, out JsonElement result1)) { return(result1); } if (input.ValueKind == JsonValueKind.Array && input.TryExecuteArrayMethod(MethodName, args, out JsonElement result2)) { return(result2); } return(JsonElementFactory.CreateNull()); }
public override JsonElement Execute(JsonElement input) { bool left = LeftSide.Execute(input).IsTruthy(); if (left && IsOr) { return(JsonElementFactory.CreateBool(true)); } bool right = RightSide.Execute(input).IsTruthy(); bool result; if (IsAnd) { result = left && right; } else { result = left || right; } return(JsonElementFactory.CreateBool(result)); }
private void Validate(string filePath, JsonSchema schema, JsonElement element) { this.logger.LogInformation("Validating \"{FilePath}\" against JSON schema...", filePath); var results = schema.Validate(element, new ValidationOptions { OutputFormat = OutputFormat.Basic, // Indicates that all nodes will be listed as children of the top node. ValidateAs = Draft.Draft7 }); if (!results.IsValid) { var errorMessageBuilder = new StringBuilder(); errorMessageBuilder.AppendLine($"The file \"{filePath}\" is invalid:"); // TODO: enumerable. var invalidResults = results.NestedResults.Count == 0 ? new[] { results } : results.NestedResults; var shouldSkipAdditionalPropertyError = invalidResults.Any(x => !IsAdditionalPropertyError(x)); foreach (var result in invalidResults) { var isAdditionalPropertyError = IsAdditionalPropertyError(result); if (isAdditionalPropertyError && shouldSkipAdditionalPropertyError) { // According to the JSON schema spec, if any non-additional property is not valid, "properties" doesn't // generate any annotaion. As a result, "additionalProperties": false applies to all properties, which // creates additional property errors even for non-additional properties. To make it less confusing, // we skip additional property errors if there are other error types. // See https://github.com/gregsdennis/json-everything/issues/39#issuecomment-730116851 for details. continue; } errorMessageBuilder.Append(" "); errorMessageBuilder.Append(result.InstanceLocation.Source); errorMessageBuilder.Append(": "); if (isAdditionalPropertyError) { // The built-in error message is "All values fail against the false schema" which is not very intuitive. errorMessageBuilder.AppendLine("The property is not allowed"); // All errors are additional property errors. Only keep the first one as the others could be on the parent // properties which are triggered by the child property, e.g., an additional property /properties/foo/bar // can make /properties/foo fail against the "additionalProperties": false check if it is also declared on // the property foo. Technically this complies with what the spec defines and is what Json.Schema implements, // but it may confuse users. break; } else if (IsRegexError(result)) { // The built-in error message does not include the regex pattern. var schemaElement = JsonElementFactory.CreateElement(JsonSerializer.Serialize(schema)); var regex = result.SchemaLocation.Evaluate(schemaElement); errorMessageBuilder.AppendLine($"Value does not match the pattern of \"{regex}\""); } else { errorMessageBuilder.AppendLine(result.Message); } } throw new InvalidModuleException(errorMessageBuilder.ToString()); } }
public virtual void WriteTo(Utf8JsonWriter writer) => JsonElementFactory.CreateElement(this.Data).WriteTo(writer);
/// <summary> /// Starts a deployment at provided target scope and returns <see cref="BicepDeploymentStartResponse"/>. /// </summary> /// <param name="deploymentCollectionProvider">deployment collection provider</param> /// <param name="armClient">arm client</param> /// <param name="documentPath">path to bicep file used in deployment</param> /// <param name="template">template used in deployment</param> /// <param name="parametersFilePath">path to parameter file used in deployment</param> /// <param name="id">id string to create the ResourceIdentifier from</param> /// <param name="scope">target scope</param> /// <param name="location">location to store the deployment data</param> /// <param name="deploymentId">deployment id</param> /// <param name="parametersFileName">parameters file name</param> /// <param name="parametersFileUpdateOption"><see cref="ParametersFileUpdateOption"/>update, create or overwrite parameters file</param> /// <param name="updatedDeploymentParameters">parameters that were updated during deployment flow</param> /// <param name="portalUrl">azure management portal URL</param> /// <param name="deploymentName">deployment name</param> /// <param name="deploymentOperationsCache">deployment operations cache that needs to be updated</param> /// <returns><see cref="BicepDeploymentStartResponse"/></returns> public static async Task <BicepDeploymentStartResponse> StartDeploymentAsync( IDeploymentCollectionProvider deploymentCollectionProvider, ArmClient armClient, string documentPath, string template, string parametersFilePath, string id, string scope, string location, string deploymentId, string parametersFileName, ParametersFileUpdateOption parametersFileUpdateOption, List <BicepUpdatedDeploymentParameter> updatedDeploymentParameters, string portalUrl, string deploymentName, IDeploymentOperationsCache deploymentOperationsCache) { if ((scope == LanguageConstants.TargetScopeTypeSubscription || scope == LanguageConstants.TargetScopeTypeManagementGroup) && string.IsNullOrWhiteSpace(location)) { return(new BicepDeploymentStartResponse(false, string.Format(LangServerResources.MissingLocationDeploymentFailedMessage, documentPath), null)); } ArmDeploymentCollection?deploymentCollection; var resourceIdentifier = new ResourceIdentifier(id); try { deploymentCollection = deploymentCollectionProvider.GetDeploymentCollection(armClient, resourceIdentifier, scope); } catch (Exception e) { return(new BicepDeploymentStartResponse(false, string.Format(LangServerResources.DeploymentFailedWithExceptionMessage, documentPath, e.Message), null)); } if (deploymentCollection is not null) { JsonElement parameters; try { var updatedParametersFileContents = DeploymentParametersHelper.GetUpdatedParametersFileContents(documentPath, parametersFileName, parametersFilePath, parametersFileUpdateOption, updatedDeploymentParameters); parameters = JsonElementFactory.CreateElement(updatedParametersFileContents); } catch (Exception e) { return(new BicepDeploymentStartResponse(false, e.Message, null)); } var deploymentProperties = new ArmDeploymentProperties(ArmDeploymentMode.Incremental) { Template = new BinaryData(JsonDocument.Parse(template).RootElement), Parameters = new BinaryData(parameters) }; var armDeploymentContent = new ArmDeploymentContent(deploymentProperties) { Location = location, }; try { var deploymentOperation = await deploymentCollection.CreateOrUpdateAsync(WaitUntil.Started, deploymentName, armDeploymentContent); if (deploymentOperation is null) { return(new BicepDeploymentStartResponse(false, string.Format(LangServerResources.DeploymentFailedMessage, documentPath), null)); } deploymentOperationsCache.CacheDeploymentOperation(deploymentId, deploymentOperation); var linkToDeploymentInAzurePortal = GetLinkToDeploymentInAzurePortal(portalUrl, id, deploymentName); return(new BicepDeploymentStartResponse( true, string.Format(LangServerResources.DeploymentStartedMessage, documentPath), string.Format(LangServerResources.ViewDeploymentInPortalMessage, linkToDeploymentInAzurePortal))); } catch (Exception e) { return(new BicepDeploymentStartResponse(false, string.Format(LangServerResources.DeploymentFailedWithExceptionMessage, documentPath, e.Message), null)); } } return(new BicepDeploymentStartResponse(false, string.Format(LangServerResources.DeploymentFailedMessage, documentPath), null)); }
public StringConstantFilterSubExpression(string value) { Value = value ?? throw new ArgumentNullException(nameof(value)); _element = JsonElementFactory.CreateString(value); }
public BooleanConstantFilterSubExpression(bool value) { Value = value; _element = JsonElementFactory.CreateBool(value); }
public NumberConstantFilterSubExpression(double value) { Value = value; _element = JsonElementFactory.CreateNumber(value); }