From a96157d57b9d254875f5fa3473db9b39e13c2ee0 Mon Sep 17 00:00:00 2001 From: Richard Chen Date: Wed, 4 Feb 2026 10:48:59 -0500 Subject: [PATCH 1/6] Add EndpointTestCasesParamsValidator which currently checks for inconsistent params and builtInParams within a testcase --- .../EndpointTestCasesParamsValidator.java | 82 +++++++++++++++++ ...e.amazon.smithy.model.validation.Validator | 1 + .../invalid/inconsistent-test-params.errors | 5 + .../invalid/inconsistent-test-params.smithy | 92 +++++++++++++++++++ .../validators/RuleSetParameterValidator.java | 2 +- 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java create mode 100644 smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors create mode 100644 smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy diff --git a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java new file mode 100644 index 00000000000..8d90b9cf5b1 --- /dev/null +++ b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java @@ -0,0 +1,82 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package software.amazon.smithy.rulesengine.aws.validators; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; +import java.util.Optional; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.node.StringNode; +import software.amazon.smithy.model.shapes.ServiceShape; +import software.amazon.smithy.model.validation.AbstractValidator; +import software.amazon.smithy.model.validation.ValidationEvent; +import software.amazon.smithy.rulesengine.language.EndpointRuleSet; +import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait; +import software.amazon.smithy.rulesengine.traits.EndpointTestCase; +import software.amazon.smithy.rulesengine.traits.EndpointTestOperationInput; +import software.amazon.smithy.rulesengine.traits.EndpointTestsTrait; + +/** + * Validator that the params used in endpoint test cases are valid. + */ +public class EndpointTestCasesParamsValidator extends AbstractValidator { + + @Override + public List validate(Model model) { + List events = new ArrayList<>(); + for (ServiceShape serviceShape : model.getServiceShapesWithTrait(EndpointTestsTrait.class)) { + events.addAll(validateTestParamsAreConsistent(serviceShape, + serviceShape.expectTrait(EndpointTestsTrait.class), + serviceShape.expectTrait(EndpointRuleSetTrait.class).getEndpointRuleSet())); + } + return events; + } + + private List validateTestParamsAreConsistent( + ServiceShape serviceShape, + EndpointTestsTrait testsTrait, + EndpointRuleSet ruleSet + ) { + List events = new ArrayList<>(); + + HashMap builtInParameters = new HashMap<>(); + ruleSet.getParameters().forEach(parameter -> { + if (parameter.getBuiltIn().isPresent()) { + builtInParameters.put(parameter.getName().getName().getValue(), parameter.getBuiltIn().get()); + } + }); + + for (EndpointTestCase testCase : testsTrait.getTestCases()) { + if (testCase.getOperationInputs() == null + || testCase.getOperationInputs() + .stream() + .allMatch(opInputs -> opInputs.getBuiltInParams() == null)) { + continue; + } + for (Entry testCaseParam : testCase.getParams().getMembers().entrySet()) { + if (builtInParameters.containsKey(testCaseParam.getKey().getValue())) { + testCase.getOperationInputs() + .stream() + .map(EndpointTestOperationInput::getBuiltInParams) + .filter(builtInParams -> builtInParams + .containsMember(builtInParameters.get(testCaseParam.getKey().getValue()))) + .map(builtInParams -> builtInParams + .getMember(builtInParameters.get(testCaseParam.getKey().getValue()))) + .filter(Optional::isPresent) + .map(Optional::get) + .filter(value -> !value.equals(testCaseParam.getValue())) + .forEach(inconsistentValue -> events.add(error( + serviceShape, + "Inconsistent testcase parameters: " + testCaseParam.getValue() + " and " + + inconsistentValue))); + } + } + } + return events; + } +} diff --git a/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator b/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator index b87e2e46445..eb9e3d6560c 100644 --- a/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator +++ b/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator @@ -1,2 +1,3 @@ software.amazon.smithy.rulesengine.aws.validators.RuleSetAwsBuiltInValidator software.amazon.smithy.rulesengine.aws.validators.AwsSpecialCaseEndpointValidator +software.amazon.smithy.rulesengine.aws.validators.EndpointTestCasesParamsValidator diff --git a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors new file mode 100644 index 00000000000..4794fd05fd2 --- /dev/null +++ b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors @@ -0,0 +1,5 @@ +[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointRuleSet | UnstableTrait.smithy.rules#endpointRuleSet +[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointTests | UnstableTrait.smithy.rules#endpointTests +[DANGER] example#FizzBuzz: The `AWS::Auth::AccountId` built-in used requires additional consideration of the rules that use it. | RuleSetAwsBuiltIn.AWS::Auth::AccountId +[ERROR] example#FizzBuzz: Inconsistent testcase parameters: 123 and 012345678901 | EndpointTestCasesParams +[ERROR] example#FizzBuzz: Inconsistent testcase parameters: us-west-2 and us-west-1 | EndpointTestCasesParams diff --git a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy new file mode 100644 index 00000000000..fc21291d136 --- /dev/null +++ b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy @@ -0,0 +1,92 @@ +$version: "1.0" + +namespace example + +use smithy.rules#endpointRuleSet +use smithy.rules#endpointTests + +@endpointRuleSet({ + "version": "1.3", + "parameters": { + "Region": { + "required": true, + "builtIn": "AWS::Region", + "type": "String", + "documentation": "region", + }, + "AccountId": { + "builtIn": "AWS::Auth::AccountId", + "type": "String", + "documentation": "accountid", + } + }, + "rules": [ + { + "conditions": [], + "documentation": "base rule", + "endpoint": { + "url": "https://{Region}.fizzbuzz.amazonaws.com", + "headers": {} + }, + "type": "endpoint" + } + ] +}) +@endpointTests( + version: "1.3", + testCases: [ + { + "documentation": "Inconsistent Region and AccountId", + "params": { + "Region": "us-west-2", + "AccountId": "123", + }, + "expect": { + "endpoint": { + "url": "https://us-west-2.fizzbuzz.amazonaws.com" + } + }, + "operationInputs": [ + { + "operationName": "ListShards", + "builtInParams": { + "AWS::Region": "us-west-1", + "AWS::Auth::AccountId": "012345678901", + } + } + ] + } + { + "documentation": "Consistent Region and AccountId", + "params": { + "Region": "us-west-2", + "AccountId": "012345678901", + }, + "expect": { + "endpoint": { + "url": "https://us-west-2.fizzbuzz.amazonaws.com" + } + }, + "operationInputs": [ + { + "operationName": "ListShards", + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::Auth::AccountId": "012345678901", + } + } + ] + } + ] +) +service FizzBuzz { + operations: [ + ListShards + ] +} + +operation ListShards { + input: Struct +} + +structure Struct {} diff --git a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/RuleSetParameterValidator.java b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/RuleSetParameterValidator.java index 55ae194170f..68d1ac95a27 100644 --- a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/RuleSetParameterValidator.java +++ b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/RuleSetParameterValidator.java @@ -271,7 +271,7 @@ private void validateTestsParameters( // All required params from a ruleset must be present in all test cases. if (parameter.isRequired() && !parameter.getDefault().isPresent() - && (!testSuiteHasParam || testSuiteParams.get(name).size() != trait.getTestCases().size())) { + && (!testSuiteHasParam || testSuiteParams.get(name).size() < trait.getTestCases().size())) { errors.add(parameterError(serviceShape, parameter, "TestCase.RequiredMissing", From 2e40d119e7c7b5a4934463a40046d07dba56956d Mon Sep 17 00:00:00 2001 From: rchache <105247787+rchache@users.noreply.github.com> Date: Mon, 9 Feb 2026 13:29:33 -0500 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Manuel Sugawara --- .../aws/validators/EndpointTestCasesParamsValidator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java index 8d90b9cf5b1..499a6e4281f 100644 --- a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java +++ b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java @@ -24,7 +24,7 @@ /** * Validator that the params used in endpoint test cases are valid. */ -public class EndpointTestCasesParamsValidator extends AbstractValidator { +public final class EndpointTestCasesParamsValidator extends AbstractValidator { @Override public List validate(Model model) { @@ -44,7 +44,7 @@ private List validateTestParamsAreConsistent( ) { List events = new ArrayList<>(); - HashMap builtInParameters = new HashMap<>(); + Map builtInParameters = new HashMap<>(); ruleSet.getParameters().forEach(parameter -> { if (parameter.getBuiltIn().isPresent()) { builtInParameters.put(parameter.getName().getName().getValue(), parameter.getBuiltIn().get()); From a979556db238b0340fc80aacee2f548e6c6534d9 Mon Sep 17 00:00:00 2001 From: Richard Chen Date: Mon, 9 Feb 2026 15:42:20 -0500 Subject: [PATCH 3/6] unroll streams to loops --- .../EndpointTestCasesParamsValidator.java | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java index 499a6e4281f..9c1ce5e4aee 100644 --- a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java +++ b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java @@ -7,10 +7,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.shapes.ServiceShape; import software.amazon.smithy.model.validation.AbstractValidator; @@ -52,28 +54,36 @@ private List validateTestParamsAreConsistent( }); for (EndpointTestCase testCase : testsTrait.getTestCases()) { - if (testCase.getOperationInputs() == null - || testCase.getOperationInputs() - .stream() - .allMatch(opInputs -> opInputs.getBuiltInParams() == null)) { + if (testCase.getOperationInputs() == null || testCase.getOperationInputs().isEmpty()) { continue; } for (Entry testCaseParam : testCase.getParams().getMembers().entrySet()) { - if (builtInParameters.containsKey(testCaseParam.getKey().getValue())) { - testCase.getOperationInputs() - .stream() - .map(EndpointTestOperationInput::getBuiltInParams) - .filter(builtInParams -> builtInParams - .containsMember(builtInParameters.get(testCaseParam.getKey().getValue()))) - .map(builtInParams -> builtInParams - .getMember(builtInParameters.get(testCaseParam.getKey().getValue()))) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(value -> !value.equals(testCaseParam.getValue())) - .forEach(inconsistentValue -> events.add(error( - serviceShape, - "Inconsistent testcase parameters: " + testCaseParam.getValue() + " and " - + inconsistentValue))); + if (!builtInParameters.containsKey(testCaseParam.getKey().getValue())) { + continue; + } + + for (EndpointTestOperationInput opInput : testCase.getOperationInputs()) { + ObjectNode operationInputBuiltInParams = opInput.getBuiltInParams(); + if (operationInputBuiltInParams == null) { + continue; + } + + String builtInName = builtInParameters.get(testCaseParam.getKey().getValue()); + if (!operationInputBuiltInParams.containsMember(builtInName)) { + continue; + } + + Optional paramValue = operationInputBuiltInParams.getMember(builtInName); + if (!paramValue.isPresent()) { + continue; + } + + if (!paramValue.get().equals(testCaseParam.getValue())) { + events.add(error( + serviceShape, + "Inconsistent testcase parameters: " + testCaseParam.getValue() + + " and " + paramValue.get())); + } } } } From 0c00229f84aba63233251f4d06151f0e0ceb1d31 Mon Sep 17 00:00:00 2001 From: Richard Chen Date: Mon, 9 Feb 2026 21:02:00 -0500 Subject: [PATCH 4/6] move validations to EndpointTestsTraitValidator --- .../EndpointTestCasesParamsValidator.java | 92 ------------------- ...e.amazon.smithy.model.validation.Validator | 1 - .../invalid/inconsistent-test-params.errors | 5 - .../invalid/inconsistent-test-params.smithy | 92 ------------------- .../EndpointTestsTraitValidator.java | 58 ++++++++++-- .../inconsistent-builtin-params.errors | 3 + .../inconsistent-builtin-params.smithy | 82 +++++++++++++++++ .../non-default-builtin-values.errors | 2 +- 8 files changed, 138 insertions(+), 197 deletions(-) delete mode 100644 smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java delete mode 100644 smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors delete mode 100644 smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy create mode 100644 smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.errors create mode 100644 smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.smithy diff --git a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java deleted file mode 100644 index 9c1ce5e4aee..00000000000 --- a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/validators/EndpointTestCasesParamsValidator.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -package software.amazon.smithy.rulesengine.aws.validators; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import software.amazon.smithy.model.Model; -import software.amazon.smithy.model.node.Node; -import software.amazon.smithy.model.node.ObjectNode; -import software.amazon.smithy.model.node.StringNode; -import software.amazon.smithy.model.shapes.ServiceShape; -import software.amazon.smithy.model.validation.AbstractValidator; -import software.amazon.smithy.model.validation.ValidationEvent; -import software.amazon.smithy.rulesengine.language.EndpointRuleSet; -import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait; -import software.amazon.smithy.rulesengine.traits.EndpointTestCase; -import software.amazon.smithy.rulesengine.traits.EndpointTestOperationInput; -import software.amazon.smithy.rulesengine.traits.EndpointTestsTrait; - -/** - * Validator that the params used in endpoint test cases are valid. - */ -public final class EndpointTestCasesParamsValidator extends AbstractValidator { - - @Override - public List validate(Model model) { - List events = new ArrayList<>(); - for (ServiceShape serviceShape : model.getServiceShapesWithTrait(EndpointTestsTrait.class)) { - events.addAll(validateTestParamsAreConsistent(serviceShape, - serviceShape.expectTrait(EndpointTestsTrait.class), - serviceShape.expectTrait(EndpointRuleSetTrait.class).getEndpointRuleSet())); - } - return events; - } - - private List validateTestParamsAreConsistent( - ServiceShape serviceShape, - EndpointTestsTrait testsTrait, - EndpointRuleSet ruleSet - ) { - List events = new ArrayList<>(); - - Map builtInParameters = new HashMap<>(); - ruleSet.getParameters().forEach(parameter -> { - if (parameter.getBuiltIn().isPresent()) { - builtInParameters.put(parameter.getName().getName().getValue(), parameter.getBuiltIn().get()); - } - }); - - for (EndpointTestCase testCase : testsTrait.getTestCases()) { - if (testCase.getOperationInputs() == null || testCase.getOperationInputs().isEmpty()) { - continue; - } - for (Entry testCaseParam : testCase.getParams().getMembers().entrySet()) { - if (!builtInParameters.containsKey(testCaseParam.getKey().getValue())) { - continue; - } - - for (EndpointTestOperationInput opInput : testCase.getOperationInputs()) { - ObjectNode operationInputBuiltInParams = opInput.getBuiltInParams(); - if (operationInputBuiltInParams == null) { - continue; - } - - String builtInName = builtInParameters.get(testCaseParam.getKey().getValue()); - if (!operationInputBuiltInParams.containsMember(builtInName)) { - continue; - } - - Optional paramValue = operationInputBuiltInParams.getMember(builtInName); - if (!paramValue.isPresent()) { - continue; - } - - if (!paramValue.get().equals(testCaseParam.getValue())) { - events.add(error( - serviceShape, - "Inconsistent testcase parameters: " + testCaseParam.getValue() - + " and " + paramValue.get())); - } - } - } - } - return events; - } -} diff --git a/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator b/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator index eb9e3d6560c..b87e2e46445 100644 --- a/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator +++ b/smithy-aws-endpoints/src/main/resources/META-INF/services/software.amazon.smithy.model.validation.Validator @@ -1,3 +1,2 @@ software.amazon.smithy.rulesengine.aws.validators.RuleSetAwsBuiltInValidator software.amazon.smithy.rulesengine.aws.validators.AwsSpecialCaseEndpointValidator -software.amazon.smithy.rulesengine.aws.validators.EndpointTestCasesParamsValidator diff --git a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors deleted file mode 100644 index 4794fd05fd2..00000000000 --- a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.errors +++ /dev/null @@ -1,5 +0,0 @@ -[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointRuleSet | UnstableTrait.smithy.rules#endpointRuleSet -[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointTests | UnstableTrait.smithy.rules#endpointTests -[DANGER] example#FizzBuzz: The `AWS::Auth::AccountId` built-in used requires additional consideration of the rules that use it. | RuleSetAwsBuiltIn.AWS::Auth::AccountId -[ERROR] example#FizzBuzz: Inconsistent testcase parameters: 123 and 012345678901 | EndpointTestCasesParams -[ERROR] example#FizzBuzz: Inconsistent testcase parameters: us-west-2 and us-west-1 | EndpointTestCasesParams diff --git a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy deleted file mode 100644 index fc21291d136..00000000000 --- a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/invalid/inconsistent-test-params.smithy +++ /dev/null @@ -1,92 +0,0 @@ -$version: "1.0" - -namespace example - -use smithy.rules#endpointRuleSet -use smithy.rules#endpointTests - -@endpointRuleSet({ - "version": "1.3", - "parameters": { - "Region": { - "required": true, - "builtIn": "AWS::Region", - "type": "String", - "documentation": "region", - }, - "AccountId": { - "builtIn": "AWS::Auth::AccountId", - "type": "String", - "documentation": "accountid", - } - }, - "rules": [ - { - "conditions": [], - "documentation": "base rule", - "endpoint": { - "url": "https://{Region}.fizzbuzz.amazonaws.com", - "headers": {} - }, - "type": "endpoint" - } - ] -}) -@endpointTests( - version: "1.3", - testCases: [ - { - "documentation": "Inconsistent Region and AccountId", - "params": { - "Region": "us-west-2", - "AccountId": "123", - }, - "expect": { - "endpoint": { - "url": "https://us-west-2.fizzbuzz.amazonaws.com" - } - }, - "operationInputs": [ - { - "operationName": "ListShards", - "builtInParams": { - "AWS::Region": "us-west-1", - "AWS::Auth::AccountId": "012345678901", - } - } - ] - } - { - "documentation": "Consistent Region and AccountId", - "params": { - "Region": "us-west-2", - "AccountId": "012345678901", - }, - "expect": { - "endpoint": { - "url": "https://us-west-2.fizzbuzz.amazonaws.com" - } - }, - "operationInputs": [ - { - "operationName": "ListShards", - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::Auth::AccountId": "012345678901", - } - } - ] - } - ] -) -service FizzBuzz { - operations: [ - ListShards - ] -} - -operation ListShards { - input: Struct -} - -structure Struct {} diff --git a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java index c2d3f0de3b2..c3e5a7f9487 100644 --- a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java +++ b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java @@ -8,9 +8,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.knowledge.TopDownIndex; import software.amazon.smithy.model.node.Node; +import software.amazon.smithy.model.node.ObjectNode; +import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.ServiceShape; import software.amazon.smithy.model.shapes.StructureShape; @@ -71,6 +75,7 @@ private void validateEndpointRuleSet( // be used frequently in downstream validation. List builtInParamsWithDefaults = new ArrayList<>(); List builtInParamsWithoutDefaults = new ArrayList<>(); + Map builtInParameters = new HashMap<>(); for (Parameter parameter : parameters) { if (parameter.isBuiltIn()) { @@ -79,6 +84,7 @@ private void validateEndpointRuleSet( } else { builtInParamsWithoutDefaults.add(parameter); } + builtInParameters.put(parameter.getName().getName().getValue(), parameter.getBuiltIn().get()); } } @@ -112,6 +118,11 @@ private void validateEndpointRuleSet( testCase, testOperationInput, events); + validateBuiltInsUseInconsistentValues(serviceShape, + builtInParameters, + testCase, + testOperationInput, + events); StructureShape inputShape = model.expectShape( operationNameMap.get(operationName).getInputShape(), @@ -149,12 +160,8 @@ private void validateConfiguredBuiltInValues( for (Map.Entry builtInParasWithNonDefaultValue : builtInParamsWithNonDefaultValues .entrySet()) { String builtInName = builtInParasWithNonDefaultValue.getKey().getBuiltIn().get(); - // Emit if either the built-in with a non-matching value isn't - // specified or the value set for it doesn't match. - if (!testOperationInput.getBuiltInParams().containsMember(builtInName) - || !testOperationInput.getBuiltInParams() - .expectMember(builtInName) - .equals(builtInParasWithNonDefaultValue.getValue())) { + // Emit if the built-in with a non-matching value isn't specified. + if (!testOperationInput.getBuiltInParams().containsMember(builtInName)) { events.add(error(serviceShape, testOperationInput, String.format("Test case does not supply the `%s` value for the `%s` parameter's " @@ -186,6 +193,45 @@ private void validateBuiltInsWithoutDefaultsHaveValues( } } + private void validateBuiltInsUseInconsistentValues( + ServiceShape serviceShape, + Map builtInParameters, + EndpointTestCase testCase, + EndpointTestOperationInput testOperationInput, + List events + ) { + if (testOperationInput == null) { + return; + } + for (Entry testCaseParam : testCase.getParams().getMembers().entrySet()) { + if (!builtInParameters.containsKey(testCaseParam.getKey().getValue())) { + continue; + } + + ObjectNode operationInputBuiltInParams = testOperationInput.getBuiltInParams(); + if (operationInputBuiltInParams == null) { + continue; + } + + String builtInName = builtInParameters.get(testCaseParam.getKey().getValue()); + if (!operationInputBuiltInParams.containsMember(builtInName)) { + continue; + } + + Optional paramValue = operationInputBuiltInParams.getMember(builtInName); + if (!paramValue.isPresent()) { + continue; + } + + if (!paramValue.get().equals(testCaseParam.getValue())) { + events.add(error( + serviceShape, + "Inconsistent testcase parameters: " + testCaseParam.getValue() + + " and " + paramValue.get())); + } + } + } + private void validateOperationInput( Model model, ServiceShape serviceShape, diff --git a/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.errors b/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.errors new file mode 100644 index 00000000000..0e205f04b58 --- /dev/null +++ b/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.errors @@ -0,0 +1,3 @@ +[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointRuleSet | UnstableTrait.smithy.rules#endpointRuleSet +[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointTests | UnstableTrait.smithy.rules#endpointTests +[ERROR] example#FizzBuzz: Inconsistent testcase parameters: https://another.example.com and https://custom.example.com | EndpointTestsTrait diff --git a/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.smithy b/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.smithy new file mode 100644 index 00000000000..d1cb85f6e9c --- /dev/null +++ b/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/inconsistent-builtin-params.smithy @@ -0,0 +1,82 @@ +$version: "1.0" + +namespace example + +use smithy.rules#endpointRuleSet +use smithy.rules#endpointTests + +@endpointRuleSet({ + "version": "1.3", + parameters: { + endpoint: { + type: "string" + builtIn: "SDK::Endpoint" + documentation: "docs" + } + }, + "rules": [ + { + "conditions": [], + "documentation": "base rule", + "endpoint": { + "url": "https://fizzbuzz.amazonaws.com", + "headers": {} + }, + "type": "endpoint" + } + ] +}) +@endpointTests( + version: "1.3", + testCases: [ + { + "documentation": "Inconsistent", + "params": { + endpoint: "https://another.example.com" + }, + "expect": { + "endpoint": { + "url": "https://fizzbuzz.amazonaws.com" + } + }, + "operationInputs": [ + { + "operationName": "ListShards", + "builtInParams": { + "SDK::Endpoint": "https://custom.example.com", + } + } + ] + } + { + "documentation": "Consistent", + "params": { + endpoint: "https://another.example.com" + }, + "expect": { + "endpoint": { + "url": "https://fizzbuzz.amazonaws.com" + } + }, + "operationInputs": [ + { + "operationName": "ListShards", + "builtInParams": { + "SDK::Endpoint": "https://another.example.com", + } + } + ] + } + ] +) +service FizzBuzz { + operations: [ + ListShards + ] +} + +operation ListShards { + input: Struct +} + +structure Struct {} diff --git a/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/non-default-builtin-values.errors b/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/non-default-builtin-values.errors index 9428e400a6b..88eea9cdeb7 100644 --- a/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/non-default-builtin-values.errors +++ b/smithy-rules-engine/src/test/resources/software/amazon/smithy/rulesengine/traits/errorfiles/non-default-builtin-values.errors @@ -1,4 +1,4 @@ [WARNING] smithy.example#ExampleService: This shape applies a trait that is unstable: smithy.rules#endpointRuleSet | UnstableTrait [WARNING] smithy.example#ExampleService: This shape applies a trait that is unstable: smithy.rules#endpointTests | UnstableTrait -[ERROR] smithy.example#ExampleService: Test case does not supply the `"https://another.example.com"` value for the `endpoint` parameter's `SDK::Endpoint` built-in. | EndpointTestsTrait +[ERROR] smithy.example#ExampleService: Inconsistent testcase parameters: https://another.example.com and https://custom.example.com | EndpointTestsTrait [ERROR] smithy.example#ExampleService: Test case does not supply the `"https://some.example.com"` value for the `endpoint` parameter's `SDK::Endpoint` built-in. | EndpointTestsTrait From 611fbde84d599fe1b598368e88da21c7a80ba680 Mon Sep 17 00:00:00 2001 From: Richard Chen Date: Tue, 10 Feb 2026 13:00:43 -0500 Subject: [PATCH 5/6] remove unnecessary null checks --- .../validators/EndpointTestsTraitValidator.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java index c3e5a7f9487..2cf43710bed 100644 --- a/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java +++ b/smithy-rules-engine/src/main/java/software/amazon/smithy/rulesengine/validators/EndpointTestsTraitValidator.java @@ -200,19 +200,12 @@ private void validateBuiltInsUseInconsistentValues( EndpointTestOperationInput testOperationInput, List events ) { - if (testOperationInput == null) { - return; - } for (Entry testCaseParam : testCase.getParams().getMembers().entrySet()) { if (!builtInParameters.containsKey(testCaseParam.getKey().getValue())) { continue; } ObjectNode operationInputBuiltInParams = testOperationInput.getBuiltInParams(); - if (operationInputBuiltInParams == null) { - continue; - } - String builtInName = builtInParameters.get(testCaseParam.getKey().getValue()); if (!operationInputBuiltInParams.containsMember(builtInName)) { continue; From 509a91bd70451b0382d8212fbabc3395b47c0c17 Mon Sep 17 00:00:00 2001 From: Richard Chen Date: Tue, 10 Feb 2026 13:49:26 -0500 Subject: [PATCH 6/6] added changelog entry --- .../feature-c6ca466b9d6f375fd8c739fce3768c560bcc4dbd.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changes/next-release/feature-c6ca466b9d6f375fd8c739fce3768c560bcc4dbd.json diff --git a/.changes/next-release/feature-c6ca466b9d6f375fd8c739fce3768c560bcc4dbd.json b/.changes/next-release/feature-c6ca466b9d6f375fd8c739fce3768c560bcc4dbd.json new file mode 100644 index 00000000000..2bfe093b5f5 --- /dev/null +++ b/.changes/next-release/feature-c6ca466b9d6f375fd8c739fce3768c560bcc4dbd.json @@ -0,0 +1,7 @@ +{ + "type": "feature", + "description": "Added new ERROR event to EndpointTestsTraitValidator when builtin params are inconsistent", + "pull_requests": [ + "[#2955](https://github.com/smithy-lang/smithy/pull/2955)" + ] +}