From 6dfd56d67f9a4e4abd63ff25d96fb99c33afd9d8 Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Wed, 9 Aug 2017 16:26:47 -0700 Subject: [PATCH] Cloudconfig editor: verify 'at least one of' constraints in schema --- .../ide/vscode/bosh/BoshCloudConfigSchema.java | 8 ++++---- .../ide/vscode/bosh/BoshEditorTest.java | 16 ++++++++++++++++ .../vscode/commons/yaml/schema/YTypeFactory.java | 13 +++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshCloudConfigSchema.java b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshCloudConfigSchema.java index 13f882eaf..c1b9c90d5 100644 --- a/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshCloudConfigSchema.java +++ b/headless-services/bosh-language-server/src/main/java/org/springframework/ide/vscode/bosh/BoshCloudConfigSchema.java @@ -110,11 +110,11 @@ public class BoshCloudConfigSchema extends SchemaSupport implements YamlSchema { addProp(t_disk_type, "cloud_properties", t_params); this.toplevelType = f.ybean("CloudConfig"); - addProp(toplevelType, "azs", f.yseq(t_az)).isRequired(true); - addProp(toplevelType, "networks", f.yseq(t_network)).isRequired(true); - addProp(toplevelType, "vm_types", f.yseq(t_vm_type)).isRequired(true); + addProp(toplevelType, "azs", f.yseq(t_az).notEmpty()).isRequired(true); + addProp(toplevelType, "networks", f.yseq(t_network).notEmpty()).isRequired(true); + addProp(toplevelType, "vm_types", f.yseq(t_vm_type).notEmpty()).isRequired(true); addProp(toplevelType, "vm_extensions", f.yseq(t_any)); - addProp(toplevelType, "disk_types", f.yseq(t_disk_type)).isRequired(true); + addProp(toplevelType, "disk_types", f.yseq(t_disk_type).notEmpty()).isRequired(true); addProp(toplevelType, "compilation", t_compilation).isRequired(true); ASTTypeCache astTypes = models.astTypes; diff --git a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java index a7e38cfd3..eabf5422e 100644 --- a/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java +++ b/headless-services/bosh-language-server/src/test/java/org/springframework/ide/vscode/bosh/BoshEditorTest.java @@ -2422,4 +2422,20 @@ public class BoshEditorTest { editor.assertHoverContains("cloud_properties", "Describes any IaaS-specific properties needed to create disks"); } + @Test public void cloudconfig_at_least_one_required() throws Exception { + Editor editor = harness.newEditor(LanguageId.BOSH_CLOUD_CONFIG, + "azs: []\n" + + "vm_types: []\n" + + "networks: []\n" + + "disk_types: []\n" + + "vm_extensions: []" //This one should be okay! + ); + editor.ignoreProblem(YamlSchemaProblems.MISSING_PROPERTY); + editor.assertProblems( + "[]|At least one 'AZ' is required", + "[]|At least one 'VMType' is required", + "[]|At least one 'Network' is required", + "[]|At least one 'DiskType' is required" + ); + } } diff --git a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java index 7a937cae5..c9f287ab6 100644 --- a/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java +++ b/headless-services/commons/commons-yaml/src/main/java/org/springframework/ide/vscode/commons/yaml/schema/YTypeFactory.java @@ -25,6 +25,7 @@ import java.util.concurrent.Callable; import java.util.function.BiFunction; import java.util.stream.Collectors; +import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector; import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileException; import org.springframework.ide.vscode.commons.languageserver.reconcile.ReplacementQuickfix; import org.springframework.ide.vscode.commons.util.Assert; @@ -38,6 +39,8 @@ import org.springframework.ide.vscode.commons.yaml.reconcile.YamlSchemaProblems; import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraint; import org.springframework.ide.vscode.commons.yaml.schema.constraints.Constraints; import org.springframework.ide.vscode.commons.yaml.snippet.TypeBasedSnippetProvider; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.SequenceNode; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; @@ -601,6 +604,16 @@ public class YTypeFactory { public YType getDomainType() { return el; } + + public YSeqType notEmpty() { + require((DynamicSchemaContext dc, Node parent, Node node, YType type, IProblemCollector problems) -> { + SequenceNode seq = (SequenceNode) node; + if (seq.getValue().size()==0) { + problems.accept(YamlSchemaProblems.schemaProblem("At least one '"+el+"' is required", node)); + } + }); + return this; + } } public static class YBeanType extends AbstractType {