From a378fdbad68bae3ca4f0ab850e9fc12d64a7d9db Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Thu, 24 Aug 2023 16:03:49 -0600 Subject: [PATCH 1/5] Allow lowering input validation severity on examples --- docs/source-2.0/spec/documentation-traits.rst | 24 ++- .../smithy/model/traits/ExamplesTrait.java | 54 +++++- .../validation/NodeValidationVisitor.java | 36 +++- .../validation/node/BlobLengthPlugin.java | 17 +- .../validation/node/MapLengthPlugin.java | 11 +- .../validation/node/PatternTraitPlugin.java | 10 +- .../validation/node/RangeTraitPlugin.java | 33 ++-- .../validation/node/StringLengthPlugin.java | 11 +- .../validators/ExamplesTraitValidator.java | 58 +++++-- .../amazon/smithy/model/loader/prelude.smithy | 2 + .../model/traits/ExamplesTraitTest.java | 6 +- .../ExamplesTraitValidatorTest.java | 5 + .../examples-trait-validator.errors | 14 ++ .../validators/examples-trait-validator.json | 161 ++++++++++++++++++ 14 files changed, 394 insertions(+), 48 deletions(-) diff --git a/docs/source-2.0/spec/documentation-traits.rst b/docs/source-2.0/spec/documentation-traits.rst index ed254072f25..fe2f0206ccf 100644 --- a/docs/source-2.0/spec/documentation-traits.rst +++ b/docs/source-2.0/spec/documentation-traits.rst @@ -139,11 +139,22 @@ Each ``example`` trait value is a structure with the following members: - :ref:`examples-ErrorExample-structure` - Provides an error shape ID and example error parameters for the operation. - -The values provided for the ``input`` and ``output`` members MUST be -compatible with the shapes and constraints of the corresponding structure. -These values use the same semantics and format as -:ref:`custom trait values `. + * - lowerInputValidationSeverity + - ``[string]`` + - Lowers input validation events from ERROR to WARNING for specific + validation types. List can include: ``BLOB_LENGTH_WARNING``, + ``MAP_LENGTH_WARNING``, ``PATTERN_TRAIT_WARNING``, + ``RANGE_TRAIT_WARNING``, ``REQUIRED_TRAIT_WARNING``, + ``STRING_LENGTH_WARNING``. + + +When ``input`` and ``output`` members are present, both MUST be compatible +with the shapes and constraints of the corresponding structure. When ``input`` +and ``error`` members are present, input validation events will be emitted as +an ``ERROR`` by default. Specific validation events for the ``input`` can be +lowered to a ``WARNING`` by setting the appropriate +``lowerInputValidationSeverity`` value. ``input`` and ``output`` members use +the same semantics and format as :ref:`custom trait values `. A value for ``output`` or ``error`` SHOULD be provided. However, both MUST NOT be defined for the same example. @@ -186,7 +197,8 @@ MUST NOT be defined for the same example. content: { message: "Invalid 'foo'. Special character not allowed." } - } + }, + lowerInputValidationSeverity: ["PATTERN_TRAIT_WARNING"] } ]) diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java index 7ff28c07978..f53510fe79e 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java @@ -19,12 +19,15 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.validation.NodeValidationVisitor; import software.amazon.smithy.model.validation.validators.ExamplesTraitValidator; +import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -55,6 +58,24 @@ protected Node createNode() { return examples.stream().map(Example::toNode).collect(ArrayNode.collect(getSourceLocation())); } + @Override + public boolean equals(Object other) { + if (!(other instanceof ExamplesTrait)) { + return false; + } else if (other == this) { + return true; + } else { + ExamplesTrait trait = (ExamplesTrait) other; + return this.examples.size() == trait.examples.size() && this.examples.containsAll(trait.examples); + } + } + + @Override + public int hashCode() { + return Objects.hash(toShapeId(), examples); + } + + @Override public Builder toBuilder() { Builder builder = new Builder().sourceLocation(getSourceLocation()); @@ -70,7 +91,7 @@ public static Builder builder() { } /** - * Builds and examples trait. + * Builds an examples trait. */ public static final class Builder extends AbstractTraitBuilder { private final List examples = new ArrayList<>(); @@ -100,6 +121,7 @@ public static final class Example implements ToNode, ToSmithyBuilder { private final ObjectNode input; private final ObjectNode output; private final ErrorExample error; + private final List lowerInputValidationSeverity; private Example(Builder builder) { this.title = Objects.requireNonNull(builder.title, "Example title must not be null"); @@ -107,6 +129,7 @@ private Example(Builder builder) { this.input = builder.input; this.output = builder.output; this.error = builder.error; + this.lowerInputValidationSeverity = builder.lowerInputValidationSeverity.get(); } /** @@ -144,6 +167,13 @@ public Optional getError() { return Optional.ofNullable(error); } + /** + * @return Gets the list of lowered input validation severities. + */ + public Optional> getLowerInputValidationSeverity() { + return Optional.ofNullable(lowerInputValidationSeverity); + } + @Override public Node toNode() { ObjectNode.Builder builder = Node.objectNodeBuilder() @@ -157,13 +187,20 @@ public Node toNode() { if (this.getOutput().isPresent()) { builder.withMember("output", output); } + if (this.getLowerInputValidationSeverity().isPresent()) { + builder.withMember("lowerInputValidationSeverity", ArrayNode.fromNodes(lowerInputValidationSeverity + .stream() + .map(NodeValidationVisitor.Feature::toNode) + .collect(Collectors.toList()))); + } return builder.build(); } @Override public Builder toBuilder() { - return new Builder().documentation(documentation).title(title).input(input).output(output).error(error); + return new Builder().documentation(documentation).title(title).input(input).output(output).error(error) + .lowerInputValidationSeverity(lowerInputValidationSeverity); } public static Builder builder() { @@ -179,6 +216,7 @@ public static final class Builder implements SmithyBuilder { private ObjectNode input = Node.objectNode(); private ObjectNode output; private ErrorExample error; + private BuilderRef> lowerInputValidationSeverity = BuilderRef.forList(); @Override public Example build() { @@ -209,6 +247,14 @@ public Builder error(ErrorExample error) { this.error = error; return this; } + + public Builder lowerInputValidationSeverity( + List lowerInputValidationSeverity + ) { + this.lowerInputValidationSeverity.clear(); + this.lowerInputValidationSeverity.get().addAll(lowerInputValidationSeverity); + return this; + } } } @@ -302,7 +348,9 @@ private static Example exampleFromNode(ObjectNode node) { .getStringMember("documentation", builder::documentation) .getObjectMember("input", builder::input) .getObjectMember("output", builder::output) - .getMember("error", ErrorExample::fromNode, builder::error); + .getMember("error", ErrorExample::fromNode, builder::error) + .getArrayMember("lowerInputValidationSeverity", NodeValidationVisitor.Feature::fromNode, + builder::lowerInputValidationSeverity); return builder.build(); } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java index 733196c1dda..f0720a05fe6 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java @@ -104,10 +104,36 @@ public enum Feature { * Emit a warning when a range trait is incompatible with a default value of 0. * *

This was a common pattern in Smithy 1.0 and earlier. It implies that the value is effectively - * required. However, chaning the type of the value by un-boxing it or adjusting the range trait would - * be a lossy tranformation when migrating a model from 1.0 to 2.0. + * required. However, changing the type of the value by un-boxing it or adjusting the range trait would + * be a lossy transformation when migrating a model from 1.0 to 2.0. */ - RANGE_TRAIT_ZERO_VALUE_WARNING + RANGE_TRAIT_ZERO_VALUE_WARNING, + + // Lowers severity of Length Trait validations on blobs to a WARNING. + BLOB_LENGTH_WARNING, + + // Lowers severity of Length Trait validations on maps to a WARNING. + MAP_LENGTH_WARNING, + + // Lowers severity of Pattern Trait validations to a WARNING. + PATTERN_TRAIT_WARNING, + + // Lowers severity of Range Trait validations to a WARNING. + RANGE_TRAIT_WARNING, + + // Lowers severity of Required Trait validations to a WARNING. + REQUIRED_TRAIT_WARNING, + + // Lowers severity of Length Trait validations on strings to a WARNING. + STRING_LENGTH_WARNING,; + + public static Feature fromNode(Node node) { + return Feature.valueOf(node.expectStringNode().getValue()); + } + + public static Node toNode(Feature feature) { + return StringNode.from(feature.toString()); + } } public static Builder builder() { @@ -317,9 +343,11 @@ public List structureShape(StructureShape shape) { for (MemberShape member : members.values()) { if (member.isRequired() && !object.getMember(member.getMemberName()).isPresent()) { + Severity severity = this.validationContext.hasFeature(Feature.REQUIRED_TRAIT_WARNING) + ? Severity.WARNING : Severity.ERROR; events.add(event(String.format( "Missing required structure member `%s` for `%s`", - member.getMemberName(), shape.getId()))); + member.getMemberName(), shape.getId()), severity)); } } return events; diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java index 9b566083f60..f841e7ae27a 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java @@ -20,6 +20,8 @@ import software.amazon.smithy.model.shapes.BlobShape; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.traits.LengthTrait; +import software.amazon.smithy.model.validation.NodeValidationVisitor; +import software.amazon.smithy.model.validation.Severity; import software.amazon.smithy.utils.SmithyInternalApi; /** @@ -39,16 +41,23 @@ protected void check(Shape shape, LengthTrait trait, StringNode node, Context co trait.getMin().ifPresent(min -> { if (size < min) { - emitter.accept(node, "Value provided for `" + shape.getId() + "` must have at least " - + min + " bytes, but the provided value only has " + size + " bytes"); + emitter.accept(node, getSeverity(context), "Value provided for `" + shape.getId() + + "` must have at least " + min + " bytes, but the provided value only has " + size + + " bytes"); } }); trait.getMax().ifPresent(max -> { if (value.getBytes(StandardCharsets.UTF_8).length > max) { - emitter.accept(node, "Value provided for `" + shape.getId() + "` must have no more than " - + max + " bytes, but the provided value has " + size + " bytes"); + emitter.accept(node, getSeverity(context), "Value provided for `" + shape.getId() + + "` must have no more than " + max + " bytes, but the provided value has " + size + + " bytes"); } }); } + + private Severity getSeverity(Context context) { + return context.hasFeature(NodeValidationVisitor.Feature.BLOB_LENGTH_WARNING) + ? Severity.WARNING : Severity.ERROR; + } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java index ac06ed7653a..60f584d52dd 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java @@ -19,6 +19,8 @@ import software.amazon.smithy.model.shapes.MapShape; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.traits.LengthTrait; +import software.amazon.smithy.model.validation.NodeValidationVisitor; +import software.amazon.smithy.model.validation.Severity; import software.amazon.smithy.utils.SmithyInternalApi; /** @@ -35,7 +37,7 @@ final class MapLengthPlugin extends MemberAndShapeTraitPlugin { if (node.size() < min) { - emitter.accept(node, String.format( + emitter.accept(node, getSeverity(context), String.format( "Value provided for `%s` must have at least %d entries, but the provided value only " + "has %d entries", shape.getId(), min, node.size())); } @@ -43,10 +45,15 @@ protected void check(Shape shape, LengthTrait trait, ObjectNode node, Context co trait.getMax().ifPresent(max -> { if (node.size() > max) { - emitter.accept(node, String.format( + emitter.accept(node, getSeverity(context), String.format( "Value provided for `%s` must have no more than %d entries, but the provided value " + "has %d entries", shape.getId(), max, node.size())); } }); } + + private Severity getSeverity(Context context) { + return context.hasFeature(NodeValidationVisitor.Feature.MAP_LENGTH_WARNING) + ? Severity.WARNING : Severity.ERROR; + } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java index 987b3d00296..a3b630e7ba3 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java @@ -19,6 +19,8 @@ import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.traits.PatternTrait; +import software.amazon.smithy.model.validation.NodeValidationVisitor; +import software.amazon.smithy.model.validation.Severity; /** * Validates the pattern trait on string shapes or members that target them. @@ -32,9 +34,15 @@ final class PatternTraitPlugin extends MemberAndShapeTraitPlugin { if (value.equals(NonNumericFloat.NAN)) { - emitter.accept(node, Severity.ERROR, String.format( + emitter.accept(node, getSeverity(context), String.format( "Value provided for `%s` must be a number because the `smithy.api#range` trait is applied, " + "but found \"%s\"", shape.getId(), node.getValue())); } if (trait.getMin().isPresent() && value.equals(NonNumericFloat.NEGATIVE_INFINITY)) { - emitter.accept(node, Severity.ERROR, String.format( + emitter.accept(node, getSeverity(context), String.format( "Value provided for `%s` must be greater than or equal to %s, but found \"%s\"", shape.getId(), trait.getMin().get(), node.getValue()), shape.isMemberShape() ? MEMBER : TARGET); } if (trait.getMax().isPresent() && value.equals(NonNumericFloat.POSITIVE_INFINITY)) { - emitter.accept(node, Severity.ERROR, String.format( + emitter.accept(node, getSeverity(context), String.format( "Value provided for `%s` must be less than or equal to %s, but found \"%s\"", shape.getId(), trait.getMax().get(), node.getValue()), shape.isMemberShape() ? MEMBER : TARGET); @@ -70,7 +69,7 @@ private void checkNonNumeric(Shape shape, RangeTrait trait, StringNode node, Emi }); } - protected void check(Shape shape, boolean zeroValueWarning, RangeTrait trait, NumberNode node, Emitter emitter) { + protected void check(Shape shape, Context context, RangeTrait trait, NumberNode node, Emitter emitter) { Number number = node.getValue(); BigDecimal decimal = number instanceof BigDecimal ? (BigDecimal) number @@ -78,7 +77,7 @@ protected void check(Shape shape, boolean zeroValueWarning, RangeTrait trait, Nu trait.getMin().ifPresent(min -> { if (decimal.compareTo(new BigDecimal(min.toString())) < 0) { - emitter.accept(node, getSeverity(node, zeroValueWarning), String.format( + emitter.accept(node, getSeverity(node, context), String.format( "Value provided for `%s` must be greater than or equal to %s, but found %s", shape.getId(), min, number), shape.isMemberShape() ? MEMBER : TARGET); @@ -87,7 +86,7 @@ protected void check(Shape shape, boolean zeroValueWarning, RangeTrait trait, Nu trait.getMax().ifPresent(max -> { if (decimal.compareTo(new BigDecimal(max.toString())) > 0) { - emitter.accept(node, getSeverity(node, zeroValueWarning), String.format( + emitter.accept(node, getSeverity(node, context), String.format( "Value provided for `%s` must be less than or equal to %s, but found %s", shape.getId(), max, number), shape.isMemberShape() ? MEMBER : TARGET); @@ -95,7 +94,15 @@ protected void check(Shape shape, boolean zeroValueWarning, RangeTrait trait, Nu }); } - private Severity getSeverity(NumberNode node, boolean zeroValueWarning) { - return zeroValueWarning && node.isZero() ? Severity.WARNING : Severity.ERROR; + private Severity getSeverity(NumberNode node, Context context) { + boolean zeroValueWarning = context + .hasFeature(NodeValidationVisitor.Feature.RANGE_TRAIT_ZERO_VALUE_WARNING); + boolean rangeTraitWarning = context.hasFeature(NodeValidationVisitor.Feature.RANGE_TRAIT_WARNING); + return (zeroValueWarning && node.isZero()) || rangeTraitWarning ? Severity.WARNING : Severity.ERROR; + } + + private Severity getSeverity(Context context) { + return context.hasFeature(NodeValidationVisitor.Feature.RANGE_TRAIT_WARNING) + ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java index ee6c4ee2086..282c4ea5ad8 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java @@ -19,6 +19,8 @@ import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.traits.LengthTrait; +import software.amazon.smithy.model.validation.NodeValidationVisitor; +import software.amazon.smithy.model.validation.Severity; /** * Validates the length trait on string shapes or members that target them. @@ -33,7 +35,7 @@ final class StringLengthPlugin extends MemberAndShapeTraitPlugin { if (node.getValue().length() < min) { - emitter.accept(node, String.format( + emitter.accept(node, getSeverity(context), String.format( "String value provided for `%s` must be >= %d characters, but the provided value is " + "only %d characters.", shape.getId(), min, node.getValue().length())); } @@ -41,10 +43,15 @@ protected void check(Shape shape, LengthTrait trait, StringNode node, Context co trait.getMax().ifPresent(max -> { if (node.getValue().length() > max) { - emitter.accept(node, String.format( + emitter.accept(node, getSeverity(context), String.format( "String value provided for `%s` must be <= %d characters, but the provided value is " + "%d characters.", shape.getId(), max, node.getValue().length())); } }); } + + private Severity getSeverity(Context context) { + return context.hasFeature(NodeValidationVisitor.Feature.STRING_LENGTH_WARNING) + ? Severity.WARNING : Severity.ERROR; + } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java index 3535faa970e..3f70e414dba 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java @@ -15,9 +15,18 @@ package software.amazon.smithy.model.validation.validators; +import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.BLOB_LENGTH_WARNING; +import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.MAP_LENGTH_WARNING; +import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.PATTERN_TRAIT_WARNING; +import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.RANGE_TRAIT_WARNING; +import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.REQUIRED_TRAIT_WARNING; +import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.STRING_LENGTH_WARNING; + import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import java.util.Optional; +import java.util.Set; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.shapes.OperationShape; @@ -32,6 +41,14 @@ */ public final class ExamplesTraitValidator extends AbstractValidator { + private static final Set ALLOWED_FEATURES = EnumSet.of( + BLOB_LENGTH_WARNING, + MAP_LENGTH_WARNING, + PATTERN_TRAIT_WARNING, + RANGE_TRAIT_WARNING, + REQUIRED_TRAIT_WARNING, + STRING_LENGTH_WARNING); + @Override public List validate(Model model) { List events = new ArrayList<>(); @@ -47,15 +64,26 @@ private List validateExamples(Model model, OperationShape shape List examples = trait.getExamples(); for (ExamplesTrait.Example example : examples) { - model.getShape(shape.getInputShape()).ifPresent(input -> { - NodeValidationVisitor validator = createVisitor( - "input", example.getInput(), model, shape, example); - events.addAll(input.accept(validator)); - }); - boolean isOutputDefined = example.getOutput().isPresent(); boolean isErrorDefined = example.getError().isPresent(); + model.getShape(shape.getInputShape()).ifPresent(input -> { + NodeValidationVisitor validator; + if (example.getLowerInputValidationSeverity().isPresent() + && !example.getLowerInputValidationSeverity().get().isEmpty()) { + if (!isErrorDefined) { + events.add(error(shape, trait, String.format( + "Example: `%s` has lowerInputValidationSeverity defined, so error must also be defined.", + example.getTitle()))); + } + validator = createVisitor("input", example.getInput(), model, shape, example, true); + } else { + validator = createVisitor("input", example.getInput(), model, shape, example, false); + } + List inputValidationEvents = input.accept(validator); + events.addAll(inputValidationEvents); + }); + if (isOutputDefined && isErrorDefined) { events.add(error(shape, trait, String.format( "Example: `%s` has both output and error defined, only one should be present.", @@ -63,7 +91,7 @@ private List validateExamples(Model model, OperationShape shape } else if (isOutputDefined) { model.getShape(shape.getOutputShape()).ifPresent(output -> { NodeValidationVisitor validator = createVisitor( - "output", example.getOutput().get(), model, shape, example); + "output", example.getOutput().get(), model, shape, example, false); events.addAll(output.accept(validator)); }); } else if (isErrorDefined) { @@ -71,7 +99,7 @@ private List validateExamples(Model model, OperationShape shape Optional errorShape = model.getShape(errorExample.getShapeId()); if (errorShape.isPresent() && shape.getErrors().contains(errorExample.getShapeId())) { NodeValidationVisitor validator = createVisitor( - "error", errorExample.getContent(), model, shape, example); + "error", errorExample.getContent(), model, shape, example, false); events.addAll(errorShape.get().accept(validator)); } else { events.add(error(shape, trait, String.format( @@ -89,14 +117,20 @@ private NodeValidationVisitor createVisitor( ObjectNode value, Model model, Shape shape, - ExamplesTrait.Example example + ExamplesTrait.Example example, + boolean enableFeatures ) { - return NodeValidationVisitor.builder() + NodeValidationVisitor.Builder builder = NodeValidationVisitor.builder() .model(model) .eventShapeId(shape.getId()) .value(value) .startingContext("Example " + name + " of `" + example.getTitle() + "`") - .eventId(getName()) - .build(); + .eventId(getName()); + if (enableFeatures) { + example.getLowerInputValidationSeverity().ifPresent(features -> features.stream() + .filter(ALLOWED_FEATURES::contains) + .forEach(builder::addFeature)); + } + return builder.build(); } } diff --git a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy index 5235d6dcee9..b8487159ed5 100644 --- a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy +++ b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy @@ -363,6 +363,8 @@ structure Example { output: Document error: ExampleError + + lowerInputValidationSeverity: NonEmptyStringList } @private diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java index dfbcca76e92..e20bfe71545 100644 --- a/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java +++ b/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java @@ -25,11 +25,14 @@ import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.validation.NodeValidationVisitor; public class ExamplesTraitTest { @Test public void loadsTrait() { TraitFactory provider = TraitFactory.createServiceFactory(); + ArrayNode lowerInputValidationSeverity = Node.fromStrings( + NodeValidationVisitor.Feature.REQUIRED_TRAIT_WARNING.name() ); ArrayNode node = Node.arrayNode( Node.objectNode() .withMember("title", Node.from("foo")), @@ -40,7 +43,8 @@ public void loadsTrait() { .withMember("output", Node.objectNode().withMember("c", Node.from("d"))) .withMember("error", Node.objectNode() .withMember(Node.from("shapeId"), Node.from("smithy.example#FooError")) - .withMember(Node.from("content"), Node.objectNode().withMember("e", Node.from("f"))))); + .withMember(Node.from("content"), Node.objectNode().withMember("e", Node.from("f")))) + .withMember("lowerInputValidationSeverity", lowerInputValidationSeverity)); Optional trait = provider.createTrait( ShapeId.from("smithy.api#examples"), ShapeId.from("ns.qux#foo"), node); diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/validation/ExamplesTraitValidatorTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/validation/ExamplesTraitValidatorTest.java index 3971fe69642..daf056fe536 100644 --- a/smithy-model/src/test/java/software/amazon/smithy/model/validation/ExamplesTraitValidatorTest.java +++ b/smithy-model/src/test/java/software/amazon/smithy/model/validation/ExamplesTraitValidatorTest.java @@ -1,11 +1,16 @@ package software.amazon.smithy.model.validation; +import java.util.List; import org.junit.jupiter.api.Test; import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.shapes.MemberShape; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.StructureShape; import software.amazon.smithy.model.traits.ExamplesTrait; import software.amazon.smithy.model.validation.validators.ExamplesTraitValidator; +import software.amazon.smithy.utils.ListUtils; public class ExamplesTraitValidatorTest { // There was an NPE previously due to the input/output values diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors index 51d9f212894..5c8818b9d3c 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors @@ -6,3 +6,17 @@ [WARNING] ns.foo#Operation: Example output of `Testing 2`: Invalid structure member `additional` found for `ns.foo#OperationOutput` | ExamplesTrait [ERROR] ns.foo#Operation: Example output of `Testing 2`: Missing required structure member `bam` for `ns.foo#OperationOutput` | ExamplesTrait [WARNING] ns.foo#Operation: Example error of `Testing 1`: Invalid structure member `extra` found for `ns.foo#OperationError` | ExamplesTrait +[ERROR] ns.foo#Operation: Example: `Testing 4` has lowerInputValidationSeverity defined, so error must also be defined. | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.blobMin: Value provided for `ns.foo#OperationInput$blobMin` must have at least 3 bytes, but the provided value only has 1 bytes | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.blobMax: Value provided for `ns.foo#OperationInput$blobMax` must have no more than 3 bytes, but the provided value has 6 bytes | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`: Missing required structure member `foo` for `ns.foo#OperationInput` | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.mapMin: Value provided for `ns.foo#OperationInput$mapMin` must have at least 3 entries, but the provided value only has 1 entries | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.mapMax: Value provided for `ns.foo#OperationInput$mapMax` must have no more than 1 entries, but the provided value has 2 entries | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.pattern: String value provided for `ns.foo#OperationInput$pattern` must match regular expression: ^[a-z]$ | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.rangeMin: Value provided for `ns.foo#OperationInput$rangeMin` must be greater than or equal to 2, but found 1 | ExamplesTrait.Member +[WARNING] ns.foo#Operation: Example input of `Testing 5`.rangeMax: Value provided for `ns.foo#OperationInput$rangeMax` must be less than or equal to 8, but found 10 | ExamplesTrait.Member +[WARNING] ns.foo#Operation: Example input of `Testing 5`.rangeNaN: Value provided for `ns.foo#OperationInput$rangeNaN` must be a number because the `smithy.api#range` trait is applied, but found "NaN" | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.rangeNegativeInfinity: Value provided for `ns.foo#OperationInput$rangeNegativeInfinity` must be greater than or equal to 1, but found "-Infinity" | ExamplesTrait.Member +[WARNING] ns.foo#Operation: Example input of `Testing 5`.rangePositiveInfinity: Value provided for `ns.foo#OperationInput$rangePositiveInfinity` must be less than or equal to 2, but found "Infinity" | ExamplesTrait.Member +[WARNING] ns.foo#Operation: Example input of `Testing 5`.stringMin: String value provided for `ns.foo#OperationInput$stringMin` must be >= 3 characters, but the provided value is only 1 characters. | ExamplesTrait +[WARNING] ns.foo#Operation: Example input of `Testing 5`.stringMax: String value provided for `ns.foo#OperationInput$stringMax` must be <= 3 characters, but the provided value is 6 characters. | ExamplesTrait \ No newline at end of file diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json index 64583c973bf..b6603c17d3b 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json @@ -53,6 +53,54 @@ "bat": "baz" } } + }, + { + "title": "Testing 4", + "input": { + "foo": "baz" + }, + "output": { + "bam": "value3" + }, + "lowerInputValidationSeverity": [ + "REQUIRED_TRAIT_WARNING" + ] + }, + { + "title": "Testing 5", + "input": { + "blobMin": "a", + "blobMax": "abcdef", + "mapMin": { + "a": "b" + }, + "mapMax": { + "a": "b", + "b": "c" + }, + "pattern": "123", + "rangeMin": 1, + "rangeMax": 10, + "rangeNaN": "NaN", + "rangeNegativeInfinity": "-Infinity", + "rangePositiveInfinity": "Infinity", + "stringMin": "a", + "stringMax": "abcdef" + }, + "error": { + "shapeId": "ns.foo#OperationError", + "content": { + "bat": "baz" + } + }, + "lowerInputValidationSeverity": [ + "BLOB_LENGTH_WARNING", + "MAP_LENGTH_WARNING", + "PATTERN_TRAIT_WARNING", + "RANGE_TRAIT_WARNING", + "REQUIRED_TRAIT_WARNING", + "STRING_LENGTH_WARNING" + ] } ] } @@ -79,6 +127,101 @@ }, "baz": { "target": "ns.foo#String" + }, + "blobMin": { + "target": "ns.foo#Blob", + "traits": { + "smithy.api#length": { + "min": 3 + } + } + }, + "blobMax": { + "target": "ns.foo#Blob", + "traits": { + "smithy.api#length": { + "max": 3 + } + } + }, + "mapMin": { + "target": "ns.foo#Map", + "traits": { + "smithy.api#length": { + "min": 3 + } + } + }, + "mapMax": { + "target": "ns.foo#Map", + "traits": { + "smithy.api#length": { + "max": 1 + } + } + }, + "pattern": { + "target": "ns.foo#String", + "traits": { + "smithy.api#pattern": "^[a-z]$" + } + }, + "rangeMin": { + "target": "ns.foo#Integer", + "traits": { + "smithy.api#range": { + "min": 2 + } + } + }, + "rangeMax": { + "target": "ns.foo#Integer", + "traits": { + "smithy.api#range": { + "max": 8 + } + } + }, + "rangeNaN": { + "target": "ns.foo#Float", + "traits": { + "smithy.api#range": { + "min": 1, + "max": 2 + } + } + }, + "rangeNegativeInfinity": { + "target": "ns.foo#Float", + "traits": { + "smithy.api#range": { + "min": 1 + } + } + }, + "rangePositiveInfinity": { + "target": "ns.foo#Float", + "traits": { + "smithy.api#range": { + "max": 2 + } + } + }, + "stringMin": { + "target": "ns.foo#String", + "traits": { + "smithy.api#length": { + "min": 3 + } + } + }, + "stringMax": { + "target": "ns.foo#String", + "traits": { + "smithy.api#length": { + "max": 3 + } + } } }, "traits": { @@ -127,6 +270,24 @@ }, "ns.foo#String": { "type": "string" + }, + "ns.foo#Blob": { + "type": "blob" + }, + "ns.foo#Map": { + "type": "map", + "key": { + "target": "smithy.api#String" + }, + "value": { + "target": "smithy.api#String" + } + }, + "ns.foo#Integer": { + "type": "integer" + }, + "ns.foo#Float": { + "type": "float" } } } From 38beb19829312644e31208354669018a6929e3de Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Thu, 31 Aug 2023 10:22:19 -0600 Subject: [PATCH 2/5] Remove optional wrapping --- .../smithy/model/traits/ExamplesTrait.java | 16 +++++++--------- .../validators/ExamplesTraitValidator.java | 7 +++---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java index f53510fe79e..d153bb3783f 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java @@ -170,8 +170,8 @@ public Optional getError() { /** * @return Gets the list of lowered input validation severities. */ - public Optional> getLowerInputValidationSeverity() { - return Optional.ofNullable(lowerInputValidationSeverity); + public List getLowerInputValidationSeverity() { + return lowerInputValidationSeverity; } @Override @@ -179,7 +179,11 @@ public Node toNode() { ObjectNode.Builder builder = Node.objectNodeBuilder() .withMember("title", Node.from(title)) .withOptionalMember("documentation", getDocumentation().map(Node::from)) - .withOptionalMember("error", getError().map(ErrorExample::toNode)); + .withOptionalMember("error", getError().map(ErrorExample::toNode)) + .withMember("lowerInputValidationSeverity", ArrayNode.fromNodes(lowerInputValidationSeverity + .stream() + .map(NodeValidationVisitor.Feature::toNode) + .collect(Collectors.toList()))); if (!input.isEmpty()) { builder.withMember("input", input); @@ -187,12 +191,6 @@ public Node toNode() { if (this.getOutput().isPresent()) { builder.withMember("output", output); } - if (this.getLowerInputValidationSeverity().isPresent()) { - builder.withMember("lowerInputValidationSeverity", ArrayNode.fromNodes(lowerInputValidationSeverity - .stream() - .map(NodeValidationVisitor.Feature::toNode) - .collect(Collectors.toList()))); - } return builder.build(); } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java index 3f70e414dba..97959e5cdd6 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java @@ -69,8 +69,7 @@ private List validateExamples(Model model, OperationShape shape model.getShape(shape.getInputShape()).ifPresent(input -> { NodeValidationVisitor validator; - if (example.getLowerInputValidationSeverity().isPresent() - && !example.getLowerInputValidationSeverity().get().isEmpty()) { + if (!example.getLowerInputValidationSeverity().isEmpty()) { if (!isErrorDefined) { events.add(error(shape, trait, String.format( "Example: `%s` has lowerInputValidationSeverity defined, so error must also be defined.", @@ -127,9 +126,9 @@ private NodeValidationVisitor createVisitor( .startingContext("Example " + name + " of `" + example.getTitle() + "`") .eventId(getName()); if (enableFeatures) { - example.getLowerInputValidationSeverity().ifPresent(features -> features.stream() + example.getLowerInputValidationSeverity().stream() .filter(ALLOWED_FEATURES::contains) - .forEach(builder::addFeature)); + .forEach(builder::addFeature); } return builder.build(); } From 2655235aef288f3563711faaed80eb3d0dd9ee10 Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:27:57 -0600 Subject: [PATCH 3/5] Combine disabling constraint validations --- .../guides/building-models/build-config.rst | 2 +- docs/source-2.0/spec/documentation-traits.rst | 21 ++++------ .../smithy/model/traits/ExamplesTrait.java | 33 ++++++--------- .../validation/NodeValidationVisitor.java | 21 ++-------- .../validation/node/BlobLengthPlugin.java | 2 +- .../validation/node/MapLengthPlugin.java | 2 +- .../validation/node/PatternTraitPlugin.java | 2 +- .../validation/node/RangeTraitPlugin.java | 4 +- .../validation/node/StringLengthPlugin.java | 2 +- .../validators/ExamplesTraitValidator.java | 42 ++++--------------- .../amazon/smithy/model/loader/prelude.smithy | 2 +- .../model/traits/ExamplesTraitTest.java | 5 +-- .../examples-trait-validator.errors | 4 +- .../validators/examples-trait-validator.json | 13 +----- 14 files changed, 45 insertions(+), 110 deletions(-) diff --git a/docs/source-2.0/guides/building-models/build-config.rst b/docs/source-2.0/guides/building-models/build-config.rst index b713aeda58d..dd13aa32eea 100644 --- a/docs/source-2.0/guides/building-models/build-config.rst +++ b/docs/source-2.0/guides/building-models/build-config.rst @@ -61,7 +61,7 @@ The configuration file accepts the following properties: projection. Plugins are a mapping of :ref:`plugin IDs ` to plugin-specific configuration objects. * - ignoreMissingPlugins - - ``bool`` + - ``boolean`` - If a plugin can't be found, Smithy will by default fail the build. This setting can be set to ``true`` to allow the build to progress even if a plugin can't be found on the classpath. diff --git a/docs/source-2.0/spec/documentation-traits.rst b/docs/source-2.0/spec/documentation-traits.rst index fe2f0206ccf..1620614cac8 100644 --- a/docs/source-2.0/spec/documentation-traits.rst +++ b/docs/source-2.0/spec/documentation-traits.rst @@ -139,22 +139,17 @@ Each ``example`` trait value is a structure with the following members: - :ref:`examples-ErrorExample-structure` - Provides an error shape ID and example error parameters for the operation. - * - lowerInputValidationSeverity - - ``[string]`` - - Lowers input validation events from ERROR to WARNING for specific - validation types. List can include: ``BLOB_LENGTH_WARNING``, - ``MAP_LENGTH_WARNING``, ``PATTERN_TRAIT_WARNING``, - ``RANGE_TRAIT_WARNING``, ``REQUIRED_TRAIT_WARNING``, - ``STRING_LENGTH_WARNING``. - + * - disableConstraints + - ``boolean`` + - Set to true to lower input constraint trait validations to warnings. When ``input`` and ``output`` members are present, both MUST be compatible with the shapes and constraints of the corresponding structure. When ``input`` and ``error`` members are present, input validation events will be emitted as -an ``ERROR`` by default. Specific validation events for the ``input`` can be -lowered to a ``WARNING`` by setting the appropriate -``lowerInputValidationSeverity`` value. ``input`` and ``output`` members use -the same semantics and format as :ref:`custom trait values `. +an ``ERROR`` by default. Constraint trait validation events for the ``input`` +can be lowered to a ``WARNING`` by setting ``disableConstraints`` to true. +``input`` and ``output`` members use the same semantics and format as +:ref:`custom trait values `. A value for ``output`` or ``error`` SHOULD be provided. However, both MUST NOT be defined for the same example. @@ -198,7 +193,7 @@ MUST NOT be defined for the same example. message: "Invalid 'foo'. Special character not allowed." } }, - lowerInputValidationSeverity: ["PATTERN_TRAIT_WARNING"] + disableConstraints: true } ]) diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java index d153bb3783f..ff62ec24c90 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java @@ -19,15 +19,13 @@ import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; import software.amazon.smithy.model.node.ArrayNode; +import software.amazon.smithy.model.node.BooleanNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.ToNode; import software.amazon.smithy.model.shapes.ShapeId; -import software.amazon.smithy.model.validation.NodeValidationVisitor; import software.amazon.smithy.model.validation.validators.ExamplesTraitValidator; -import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; import software.amazon.smithy.utils.ToSmithyBuilder; @@ -121,7 +119,7 @@ public static final class Example implements ToNode, ToSmithyBuilder { private final ObjectNode input; private final ObjectNode output; private final ErrorExample error; - private final List lowerInputValidationSeverity; + private final boolean disableConstraints; private Example(Builder builder) { this.title = Objects.requireNonNull(builder.title, "Example title must not be null"); @@ -129,7 +127,7 @@ private Example(Builder builder) { this.input = builder.input; this.output = builder.output; this.error = builder.error; - this.lowerInputValidationSeverity = builder.lowerInputValidationSeverity.get(); + this.disableConstraints = builder.disableConstraints; } /** @@ -168,10 +166,10 @@ public Optional getError() { } /** - * @return Gets the list of lowered input validation severities. + * @return Returns true if input constraints validation has been disabled. */ - public List getLowerInputValidationSeverity() { - return lowerInputValidationSeverity; + public boolean getDisableConstraints() { + return disableConstraints; } @Override @@ -180,10 +178,7 @@ public Node toNode() { .withMember("title", Node.from(title)) .withOptionalMember("documentation", getDocumentation().map(Node::from)) .withOptionalMember("error", getError().map(ErrorExample::toNode)) - .withMember("lowerInputValidationSeverity", ArrayNode.fromNodes(lowerInputValidationSeverity - .stream() - .map(NodeValidationVisitor.Feature::toNode) - .collect(Collectors.toList()))); + .withOptionalMember("disableConstraints", BooleanNode.from(disableConstraints).asBooleanNode()); if (!input.isEmpty()) { builder.withMember("input", input); @@ -198,7 +193,7 @@ public Node toNode() { @Override public Builder toBuilder() { return new Builder().documentation(documentation).title(title).input(input).output(output).error(error) - .lowerInputValidationSeverity(lowerInputValidationSeverity); + .disableConstraints(disableConstraints); } public static Builder builder() { @@ -214,7 +209,7 @@ public static final class Builder implements SmithyBuilder { private ObjectNode input = Node.objectNode(); private ObjectNode output; private ErrorExample error; - private BuilderRef> lowerInputValidationSeverity = BuilderRef.forList(); + private boolean disableConstraints; @Override public Example build() { @@ -246,11 +241,8 @@ public Builder error(ErrorExample error) { return this; } - public Builder lowerInputValidationSeverity( - List lowerInputValidationSeverity - ) { - this.lowerInputValidationSeverity.clear(); - this.lowerInputValidationSeverity.get().addAll(lowerInputValidationSeverity); + public Builder disableConstraints(Boolean disableConstraints) { + this.disableConstraints = disableConstraints; return this; } } @@ -347,8 +339,7 @@ private static Example exampleFromNode(ObjectNode node) { .getObjectMember("input", builder::input) .getObjectMember("output", builder::output) .getMember("error", ErrorExample::fromNode, builder::error) - .getArrayMember("lowerInputValidationSeverity", NodeValidationVisitor.Feature::fromNode, - builder::lowerInputValidationSeverity); + .getBooleanMember("disableConstraints", builder::disableConstraints); return builder.build(); } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java index f0720a05fe6..b6969e7bc47 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java @@ -109,23 +109,8 @@ public enum Feature { */ RANGE_TRAIT_ZERO_VALUE_WARNING, - // Lowers severity of Length Trait validations on blobs to a WARNING. - BLOB_LENGTH_WARNING, - - // Lowers severity of Length Trait validations on maps to a WARNING. - MAP_LENGTH_WARNING, - - // Lowers severity of Pattern Trait validations to a WARNING. - PATTERN_TRAIT_WARNING, - - // Lowers severity of Range Trait validations to a WARNING. - RANGE_TRAIT_WARNING, - - // Lowers severity of Required Trait validations to a WARNING. - REQUIRED_TRAIT_WARNING, - - // Lowers severity of Length Trait validations on strings to a WARNING. - STRING_LENGTH_WARNING,; + // Lowers severity of constraint trait validations to WARNING. + DISABLE_CONSTRAINTS; public static Feature fromNode(Node node) { return Feature.valueOf(node.expectStringNode().getValue()); @@ -343,7 +328,7 @@ public List structureShape(StructureShape shape) { for (MemberShape member : members.values()) { if (member.isRequired() && !object.getMember(member.getMemberName()).isPresent()) { - Severity severity = this.validationContext.hasFeature(Feature.REQUIRED_TRAIT_WARNING) + Severity severity = this.validationContext.hasFeature(Feature.DISABLE_CONSTRAINTS) ? Severity.WARNING : Severity.ERROR; events.add(event(String.format( "Missing required structure member `%s` for `%s`", diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java index f841e7ae27a..8e15b6d2aa7 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java @@ -57,7 +57,7 @@ protected void check(Shape shape, LengthTrait trait, StringNode node, Context co } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.BLOB_LENGTH_WARNING) + return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java index 60f584d52dd..b04dfd11ad2 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java @@ -53,7 +53,7 @@ protected void check(Shape shape, LengthTrait trait, ObjectNode node, Context co } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.MAP_LENGTH_WARNING) + return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java index a3b630e7ba3..fc6d37a4dff 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java @@ -42,7 +42,7 @@ protected void check(Shape shape, PatternTrait trait, StringNode node, Context c private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.PATTERN_TRAIT_WARNING) + return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java index 8c999d12a18..7ba1e648ec3 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java @@ -97,12 +97,12 @@ protected void check(Shape shape, Context context, RangeTrait trait, NumberNode private Severity getSeverity(NumberNode node, Context context) { boolean zeroValueWarning = context .hasFeature(NodeValidationVisitor.Feature.RANGE_TRAIT_ZERO_VALUE_WARNING); - boolean rangeTraitWarning = context.hasFeature(NodeValidationVisitor.Feature.RANGE_TRAIT_WARNING); + boolean rangeTraitWarning = context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS); return (zeroValueWarning && node.isZero()) || rangeTraitWarning ? Severity.WARNING : Severity.ERROR; } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.RANGE_TRAIT_WARNING) + return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java index 282c4ea5ad8..13a1ffbebe1 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java @@ -51,7 +51,7 @@ protected void check(Shape shape, LengthTrait trait, StringNode node, Context co } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.STRING_LENGTH_WARNING) + return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java index 97959e5cdd6..5ebc7cebb5d 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java @@ -15,18 +15,9 @@ package software.amazon.smithy.model.validation.validators; -import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.BLOB_LENGTH_WARNING; -import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.MAP_LENGTH_WARNING; -import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.PATTERN_TRAIT_WARNING; -import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.RANGE_TRAIT_WARNING; -import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.REQUIRED_TRAIT_WARNING; -import static software.amazon.smithy.model.validation.NodeValidationVisitor.Feature.STRING_LENGTH_WARNING; - import java.util.ArrayList; -import java.util.EnumSet; import java.util.List; import java.util.Optional; -import java.util.Set; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.shapes.OperationShape; @@ -41,14 +32,6 @@ */ public final class ExamplesTraitValidator extends AbstractValidator { - private static final Set ALLOWED_FEATURES = EnumSet.of( - BLOB_LENGTH_WARNING, - MAP_LENGTH_WARNING, - PATTERN_TRAIT_WARNING, - RANGE_TRAIT_WARNING, - REQUIRED_TRAIT_WARNING, - STRING_LENGTH_WARNING); - @Override public List validate(Model model) { List events = new ArrayList<>(); @@ -69,16 +52,12 @@ private List validateExamples(Model model, OperationShape shape model.getShape(shape.getInputShape()).ifPresent(input -> { NodeValidationVisitor validator; - if (!example.getLowerInputValidationSeverity().isEmpty()) { - if (!isErrorDefined) { - events.add(error(shape, trait, String.format( - "Example: `%s` has lowerInputValidationSeverity defined, so error must also be defined.", + if (example.getDisableConstraints() && !isErrorDefined) { + events.add(error(shape, trait, String.format( + "Example: `%s` has disableConstraints enabled, so error must be defined.", example.getTitle()))); - } - validator = createVisitor("input", example.getInput(), model, shape, example, true); - } else { - validator = createVisitor("input", example.getInput(), model, shape, example, false); } + validator = createVisitor("input", example.getInput(), model, shape, example); List inputValidationEvents = input.accept(validator); events.addAll(inputValidationEvents); }); @@ -90,7 +69,7 @@ private List validateExamples(Model model, OperationShape shape } else if (isOutputDefined) { model.getShape(shape.getOutputShape()).ifPresent(output -> { NodeValidationVisitor validator = createVisitor( - "output", example.getOutput().get(), model, shape, example, false); + "output", example.getOutput().get(), model, shape, example); events.addAll(output.accept(validator)); }); } else if (isErrorDefined) { @@ -98,7 +77,7 @@ private List validateExamples(Model model, OperationShape shape Optional errorShape = model.getShape(errorExample.getShapeId()); if (errorShape.isPresent() && shape.getErrors().contains(errorExample.getShapeId())) { NodeValidationVisitor validator = createVisitor( - "error", errorExample.getContent(), model, shape, example, false); + "error", errorExample.getContent(), model, shape, example); events.addAll(errorShape.get().accept(validator)); } else { events.add(error(shape, trait, String.format( @@ -116,8 +95,7 @@ private NodeValidationVisitor createVisitor( ObjectNode value, Model model, Shape shape, - ExamplesTrait.Example example, - boolean enableFeatures + ExamplesTrait.Example example ) { NodeValidationVisitor.Builder builder = NodeValidationVisitor.builder() .model(model) @@ -125,10 +103,8 @@ private NodeValidationVisitor createVisitor( .value(value) .startingContext("Example " + name + " of `" + example.getTitle() + "`") .eventId(getName()); - if (enableFeatures) { - example.getLowerInputValidationSeverity().stream() - .filter(ALLOWED_FEATURES::contains) - .forEach(builder::addFeature); + if (example.getDisableConstraints()) { + builder.addFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS); } return builder.build(); } diff --git a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy index b8487159ed5..52b12034280 100644 --- a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy +++ b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy @@ -364,7 +364,7 @@ structure Example { error: ExampleError - lowerInputValidationSeverity: NonEmptyStringList + disableConstraints: Boolean } @private diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java index e20bfe71545..8a2710b9b2a 100644 --- a/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java +++ b/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java @@ -25,14 +25,11 @@ import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.shapes.ShapeId; -import software.amazon.smithy.model.validation.NodeValidationVisitor; public class ExamplesTraitTest { @Test public void loadsTrait() { TraitFactory provider = TraitFactory.createServiceFactory(); - ArrayNode lowerInputValidationSeverity = Node.fromStrings( - NodeValidationVisitor.Feature.REQUIRED_TRAIT_WARNING.name() ); ArrayNode node = Node.arrayNode( Node.objectNode() .withMember("title", Node.from("foo")), @@ -44,7 +41,7 @@ public void loadsTrait() { .withMember("error", Node.objectNode() .withMember(Node.from("shapeId"), Node.from("smithy.example#FooError")) .withMember(Node.from("content"), Node.objectNode().withMember("e", Node.from("f")))) - .withMember("lowerInputValidationSeverity", lowerInputValidationSeverity)); + .withMember("disableConstraints", Node.from(true))); Optional trait = provider.createTrait( ShapeId.from("smithy.api#examples"), ShapeId.from("ns.qux#foo"), node); diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors index 5c8818b9d3c..4c520c99b3c 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors @@ -6,7 +6,7 @@ [WARNING] ns.foo#Operation: Example output of `Testing 2`: Invalid structure member `additional` found for `ns.foo#OperationOutput` | ExamplesTrait [ERROR] ns.foo#Operation: Example output of `Testing 2`: Missing required structure member `bam` for `ns.foo#OperationOutput` | ExamplesTrait [WARNING] ns.foo#Operation: Example error of `Testing 1`: Invalid structure member `extra` found for `ns.foo#OperationError` | ExamplesTrait -[ERROR] ns.foo#Operation: Example: `Testing 4` has lowerInputValidationSeverity defined, so error must also be defined. | ExamplesTrait +[ERROR] ns.foo#Operation: Example: `Testing 4` has disableConstraints enabled, so error must be defined. | ExamplesTrait [WARNING] ns.foo#Operation: Example input of `Testing 5`.blobMin: Value provided for `ns.foo#OperationInput$blobMin` must have at least 3 bytes, but the provided value only has 1 bytes | ExamplesTrait [WARNING] ns.foo#Operation: Example input of `Testing 5`.blobMax: Value provided for `ns.foo#OperationInput$blobMax` must have no more than 3 bytes, but the provided value has 6 bytes | ExamplesTrait [WARNING] ns.foo#Operation: Example input of `Testing 5`: Missing required structure member `foo` for `ns.foo#OperationInput` | ExamplesTrait @@ -19,4 +19,4 @@ [WARNING] ns.foo#Operation: Example input of `Testing 5`.rangeNegativeInfinity: Value provided for `ns.foo#OperationInput$rangeNegativeInfinity` must be greater than or equal to 1, but found "-Infinity" | ExamplesTrait.Member [WARNING] ns.foo#Operation: Example input of `Testing 5`.rangePositiveInfinity: Value provided for `ns.foo#OperationInput$rangePositiveInfinity` must be less than or equal to 2, but found "Infinity" | ExamplesTrait.Member [WARNING] ns.foo#Operation: Example input of `Testing 5`.stringMin: String value provided for `ns.foo#OperationInput$stringMin` must be >= 3 characters, but the provided value is only 1 characters. | ExamplesTrait -[WARNING] ns.foo#Operation: Example input of `Testing 5`.stringMax: String value provided for `ns.foo#OperationInput$stringMax` must be <= 3 characters, but the provided value is 6 characters. | ExamplesTrait \ No newline at end of file +[WARNING] ns.foo#Operation: Example input of `Testing 5`.stringMax: String value provided for `ns.foo#OperationInput$stringMax` must be <= 3 characters, but the provided value is 6 characters. | ExamplesTrait diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json index b6603c17d3b..46e11a4fbbd 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json @@ -62,9 +62,7 @@ "output": { "bam": "value3" }, - "lowerInputValidationSeverity": [ - "REQUIRED_TRAIT_WARNING" - ] + "disableConstraints": true }, { "title": "Testing 5", @@ -93,14 +91,7 @@ "bat": "baz" } }, - "lowerInputValidationSeverity": [ - "BLOB_LENGTH_WARNING", - "MAP_LENGTH_WARNING", - "PATTERN_TRAIT_WARNING", - "RANGE_TRAIT_WARNING", - "REQUIRED_TRAIT_WARNING", - "STRING_LENGTH_WARNING" - ] + "disableConstraints": true } ] } From edef8b846ed022d5be5980cdd2c9a067cb2da3d7 Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:54:02 -0600 Subject: [PATCH 4/5] Document disableConstraints can only be set on error examples --- docs/source-2.0/spec/documentation-traits.rst | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/docs/source-2.0/spec/documentation-traits.rst b/docs/source-2.0/spec/documentation-traits.rst index 1620614cac8..338024379b7 100644 --- a/docs/source-2.0/spec/documentation-traits.rst +++ b/docs/source-2.0/spec/documentation-traits.rst @@ -142,14 +142,7 @@ Each ``example`` trait value is a structure with the following members: * - disableConstraints - ``boolean`` - Set to true to lower input constraint trait validations to warnings. - -When ``input`` and ``output`` members are present, both MUST be compatible -with the shapes and constraints of the corresponding structure. When ``input`` -and ``error`` members are present, input validation events will be emitted as -an ``ERROR`` by default. Constraint trait validation events for the ``input`` -can be lowered to a ``WARNING`` by setting ``disableConstraints`` to true. -``input`` and ``output`` members use the same semantics and format as -:ref:`custom trait values `. + This can only be set when ``error`` is provided. A value for ``output`` or ``error`` SHOULD be provided. However, both MUST NOT be defined for the same example. From e5bcfd3a19ef1b1de341c87160f6ea5bcf41eab0 Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Thu, 31 Aug 2023 12:15:51 -0600 Subject: [PATCH 5/5] Rename to allowConstraintErrors --- docs/source-2.0/spec/documentation-traits.rst | 4 ++-- .../smithy/model/traits/ExamplesTrait.java | 23 ++++++++++--------- .../validation/NodeValidationVisitor.java | 4 ++-- .../validation/node/BlobLengthPlugin.java | 2 +- .../validation/node/MapLengthPlugin.java | 2 +- .../validation/node/PatternTraitPlugin.java | 2 +- .../validation/node/RangeTraitPlugin.java | 4 ++-- .../validation/node/StringLengthPlugin.java | 2 +- .../validators/ExamplesTraitValidator.java | 8 +++---- .../amazon/smithy/model/loader/prelude.smithy | 2 +- .../model/traits/ExamplesTraitTest.java | 2 +- .../examples-trait-validator.errors | 2 +- .../validators/examples-trait-validator.json | 4 ++-- 13 files changed, 31 insertions(+), 30 deletions(-) diff --git a/docs/source-2.0/spec/documentation-traits.rst b/docs/source-2.0/spec/documentation-traits.rst index 338024379b7..f0748626a38 100644 --- a/docs/source-2.0/spec/documentation-traits.rst +++ b/docs/source-2.0/spec/documentation-traits.rst @@ -139,7 +139,7 @@ Each ``example`` trait value is a structure with the following members: - :ref:`examples-ErrorExample-structure` - Provides an error shape ID and example error parameters for the operation. - * - disableConstraints + * - allowConstraintErrors - ``boolean`` - Set to true to lower input constraint trait validations to warnings. This can only be set when ``error`` is provided. @@ -186,7 +186,7 @@ MUST NOT be defined for the same example. message: "Invalid 'foo'. Special character not allowed." } }, - disableConstraints: true + allowConstraintErrors: true } ]) diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java index ff62ec24c90..fe46e028fd7 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/traits/ExamplesTrait.java @@ -119,7 +119,7 @@ public static final class Example implements ToNode, ToSmithyBuilder { private final ObjectNode input; private final ObjectNode output; private final ErrorExample error; - private final boolean disableConstraints; + private final boolean allowConstraintErrors; private Example(Builder builder) { this.title = Objects.requireNonNull(builder.title, "Example title must not be null"); @@ -127,7 +127,7 @@ private Example(Builder builder) { this.input = builder.input; this.output = builder.output; this.error = builder.error; - this.disableConstraints = builder.disableConstraints; + this.allowConstraintErrors = builder.allowConstraintErrors; } /** @@ -166,10 +166,10 @@ public Optional getError() { } /** - * @return Returns true if input constraints validation has been disabled. + * @return Returns true if input constraints errors are allowed. */ - public boolean getDisableConstraints() { - return disableConstraints; + public boolean getAllowConstraintErrors() { + return allowConstraintErrors; } @Override @@ -178,7 +178,8 @@ public Node toNode() { .withMember("title", Node.from(title)) .withOptionalMember("documentation", getDocumentation().map(Node::from)) .withOptionalMember("error", getError().map(ErrorExample::toNode)) - .withOptionalMember("disableConstraints", BooleanNode.from(disableConstraints).asBooleanNode()); + .withOptionalMember("allowConstraintErrors", BooleanNode.from(allowConstraintErrors) + .asBooleanNode()); if (!input.isEmpty()) { builder.withMember("input", input); @@ -193,7 +194,7 @@ public Node toNode() { @Override public Builder toBuilder() { return new Builder().documentation(documentation).title(title).input(input).output(output).error(error) - .disableConstraints(disableConstraints); + .allowConstraintErrors(allowConstraintErrors); } public static Builder builder() { @@ -209,7 +210,7 @@ public static final class Builder implements SmithyBuilder { private ObjectNode input = Node.objectNode(); private ObjectNode output; private ErrorExample error; - private boolean disableConstraints; + private boolean allowConstraintErrors; @Override public Example build() { @@ -241,8 +242,8 @@ public Builder error(ErrorExample error) { return this; } - public Builder disableConstraints(Boolean disableConstraints) { - this.disableConstraints = disableConstraints; + public Builder allowConstraintErrors(Boolean allowConstraintErrors) { + this.allowConstraintErrors = allowConstraintErrors; return this; } } @@ -339,7 +340,7 @@ private static Example exampleFromNode(ObjectNode node) { .getObjectMember("input", builder::input) .getObjectMember("output", builder::output) .getMember("error", ErrorExample::fromNode, builder::error) - .getBooleanMember("disableConstraints", builder::disableConstraints); + .getBooleanMember("allowConstraintErrors", builder::allowConstraintErrors); return builder.build(); } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java index b6969e7bc47..330b377f7c2 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/NodeValidationVisitor.java @@ -110,7 +110,7 @@ public enum Feature { RANGE_TRAIT_ZERO_VALUE_WARNING, // Lowers severity of constraint trait validations to WARNING. - DISABLE_CONSTRAINTS; + ALLOW_CONSTRAINT_ERRORS; public static Feature fromNode(Node node) { return Feature.valueOf(node.expectStringNode().getValue()); @@ -328,7 +328,7 @@ public List structureShape(StructureShape shape) { for (MemberShape member : members.values()) { if (member.isRequired() && !object.getMember(member.getMemberName()).isPresent()) { - Severity severity = this.validationContext.hasFeature(Feature.DISABLE_CONSTRAINTS) + Severity severity = this.validationContext.hasFeature(Feature.ALLOW_CONSTRAINT_ERRORS) ? Severity.WARNING : Severity.ERROR; events.add(event(String.format( "Missing required structure member `%s` for `%s`", diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java index 8e15b6d2aa7..1b6047f408e 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/BlobLengthPlugin.java @@ -57,7 +57,7 @@ protected void check(Shape shape, LengthTrait trait, StringNode node, Context co } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) + return context.hasFeature(NodeValidationVisitor.Feature.ALLOW_CONSTRAINT_ERRORS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java index b04dfd11ad2..b7389552631 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/MapLengthPlugin.java @@ -53,7 +53,7 @@ protected void check(Shape shape, LengthTrait trait, ObjectNode node, Context co } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) + return context.hasFeature(NodeValidationVisitor.Feature.ALLOW_CONSTRAINT_ERRORS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java index fc6d37a4dff..7bb1d202435 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/PatternTraitPlugin.java @@ -42,7 +42,7 @@ protected void check(Shape shape, PatternTrait trait, StringNode node, Context c private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) + return context.hasFeature(NodeValidationVisitor.Feature.ALLOW_CONSTRAINT_ERRORS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java index 7ba1e648ec3..0dbfc5db9c2 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/RangeTraitPlugin.java @@ -97,12 +97,12 @@ protected void check(Shape shape, Context context, RangeTrait trait, NumberNode private Severity getSeverity(NumberNode node, Context context) { boolean zeroValueWarning = context .hasFeature(NodeValidationVisitor.Feature.RANGE_TRAIT_ZERO_VALUE_WARNING); - boolean rangeTraitWarning = context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS); + boolean rangeTraitWarning = context.hasFeature(NodeValidationVisitor.Feature.ALLOW_CONSTRAINT_ERRORS); return (zeroValueWarning && node.isZero()) || rangeTraitWarning ? Severity.WARNING : Severity.ERROR; } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) + return context.hasFeature(NodeValidationVisitor.Feature.ALLOW_CONSTRAINT_ERRORS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java index 13a1ffbebe1..cd358a1eb9d 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/node/StringLengthPlugin.java @@ -51,7 +51,7 @@ protected void check(Shape shape, LengthTrait trait, StringNode node, Context co } private Severity getSeverity(Context context) { - return context.hasFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS) + return context.hasFeature(NodeValidationVisitor.Feature.ALLOW_CONSTRAINT_ERRORS) ? Severity.WARNING : Severity.ERROR; } } diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java index 5ebc7cebb5d..5f4913e3b47 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/ExamplesTraitValidator.java @@ -52,9 +52,9 @@ private List validateExamples(Model model, OperationShape shape model.getShape(shape.getInputShape()).ifPresent(input -> { NodeValidationVisitor validator; - if (example.getDisableConstraints() && !isErrorDefined) { + if (example.getAllowConstraintErrors() && !isErrorDefined) { events.add(error(shape, trait, String.format( - "Example: `%s` has disableConstraints enabled, so error must be defined.", + "Example: `%s` has allowConstraintErrors enabled, so error must be defined.", example.getTitle()))); } validator = createVisitor("input", example.getInput(), model, shape, example); @@ -103,8 +103,8 @@ private NodeValidationVisitor createVisitor( .value(value) .startingContext("Example " + name + " of `" + example.getTitle() + "`") .eventId(getName()); - if (example.getDisableConstraints()) { - builder.addFeature(NodeValidationVisitor.Feature.DISABLE_CONSTRAINTS); + if (example.getAllowConstraintErrors()) { + builder.addFeature(NodeValidationVisitor.Feature.ALLOW_CONSTRAINT_ERRORS); } return builder.build(); } diff --git a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy index 52b12034280..007f60a90e0 100644 --- a/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy +++ b/smithy-model/src/main/resources/software/amazon/smithy/model/loader/prelude.smithy @@ -364,7 +364,7 @@ structure Example { error: ExampleError - disableConstraints: Boolean + allowConstraintErrors: Boolean } @private diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java index 8a2710b9b2a..19dc1ab68d4 100644 --- a/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java +++ b/smithy-model/src/test/java/software/amazon/smithy/model/traits/ExamplesTraitTest.java @@ -41,7 +41,7 @@ public void loadsTrait() { .withMember("error", Node.objectNode() .withMember(Node.from("shapeId"), Node.from("smithy.example#FooError")) .withMember(Node.from("content"), Node.objectNode().withMember("e", Node.from("f")))) - .withMember("disableConstraints", Node.from(true))); + .withMember("allowConstraintErrors", Node.from(true))); Optional trait = provider.createTrait( ShapeId.from("smithy.api#examples"), ShapeId.from("ns.qux#foo"), node); diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors index 4c520c99b3c..6d971e8b17a 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.errors @@ -6,7 +6,7 @@ [WARNING] ns.foo#Operation: Example output of `Testing 2`: Invalid structure member `additional` found for `ns.foo#OperationOutput` | ExamplesTrait [ERROR] ns.foo#Operation: Example output of `Testing 2`: Missing required structure member `bam` for `ns.foo#OperationOutput` | ExamplesTrait [WARNING] ns.foo#Operation: Example error of `Testing 1`: Invalid structure member `extra` found for `ns.foo#OperationError` | ExamplesTrait -[ERROR] ns.foo#Operation: Example: `Testing 4` has disableConstraints enabled, so error must be defined. | ExamplesTrait +[ERROR] ns.foo#Operation: Example: `Testing 4` has allowConstraintErrors enabled, so error must be defined. | ExamplesTrait [WARNING] ns.foo#Operation: Example input of `Testing 5`.blobMin: Value provided for `ns.foo#OperationInput$blobMin` must have at least 3 bytes, but the provided value only has 1 bytes | ExamplesTrait [WARNING] ns.foo#Operation: Example input of `Testing 5`.blobMax: Value provided for `ns.foo#OperationInput$blobMax` must have no more than 3 bytes, but the provided value has 6 bytes | ExamplesTrait [WARNING] ns.foo#Operation: Example input of `Testing 5`: Missing required structure member `foo` for `ns.foo#OperationInput` | ExamplesTrait diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json index 46e11a4fbbd..3c6623d1536 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/validators/examples-trait-validator.json @@ -62,7 +62,7 @@ "output": { "bam": "value3" }, - "disableConstraints": true + "allowConstraintErrors": true }, { "title": "Testing 5", @@ -91,7 +91,7 @@ "bat": "baz" } }, - "disableConstraints": true + "allowConstraintErrors": true } ] }