Skip to content

Commit ea7cffc

Browse files
authored
Reduce query error uniqueness validation severity (#2682)
* Reduce query error uniqueness validation severity Also, fix some issues with the query compatibility protocol tests * Remove extra configuration added by mistake
1 parent 401f36e commit ea7cffc

File tree

6 files changed

+78
-63
lines changed

6 files changed

+78
-63
lines changed

smithy-aws-protocol-tests/model/awsJson1_0/main.smithy

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ use aws.api#service
66
use aws.auth#sigv4
77
use aws.protocols#awsJson1_0
88
use aws.protocols#awsQueryCompatible
9-
use smithy.test#httpRequestTests
10-
use smithy.test#httpResponseTests
119

1210
@service(sdkId: "JSON RPC 10")
1311
@sigv4(name: "jsonrpc10")
@@ -50,7 +48,7 @@ service JsonRpc10 {
5048

5149

5250
@service(sdkId: "Query Compatible JSON RPC 10")
53-
@sigv4(name: "query-compatible-jsonrpc10")
51+
@sigv4(name: "querycompatiblejsonrpc10")
5452
@awsJson1_0
5553
@title("Query Compatible Json 1.0 Protocol Service")
5654
@awsQueryCompatible

smithy-aws-protocol-tests/model/rpcv2Cbor/main.smithy

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
$version: "2"
2+
3+
namespace aws.protocoltests.rpcv2cbor
4+
5+
use aws.api#service
6+
use aws.auth#sigv4
7+
use smithy.protocols#rpcv2Cbor
8+
use smithy.test#httpRequestTests
9+
10+
@service(sdkId: "Non Query Compatible RpcV2 Protocol")
11+
@sigv4(name: "nonquerycompatiblerpcv2protocol")
12+
@rpcv2Cbor
13+
@title("Non Query Compatible RpcV2 Protocol Service")
14+
service NonQueryCompatibleRpcV2Protocol {
15+
version: "2025-06-20"
16+
operations: [
17+
NonQueryCompatibleOperation
18+
]
19+
}
20+
21+
@httpRequestTests([
22+
{
23+
id: "NonQueryCompatibleRpcV2CborForbidsQueryModeHeader"
24+
documentation: "The query mode header MUST NOT be set on non-query-compatible services."
25+
protocol: rpcv2Cbor
26+
method: "POST"
27+
headers: { "smithy-protocol": "rpc-v2-cbor", Accept: "application/cbor" }
28+
forbidHeaders: ["x-amzn-query-mode"]
29+
uri: "/service/NonQueryCompatibleRpcV2Protocol/operation/QueryIncompatibleOperation"
30+
body: ""
31+
}
32+
])
33+
@idempotent
34+
operation NonQueryCompatibleOperation {}

smithy-aws-protocol-tests/model/rpcv2Cbor/query-compatible.smithy

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,28 @@ $version: "2"
22

33
namespace aws.protocoltests.rpcv2cbor
44

5+
use aws.api#service
6+
use aws.auth#sigv4
7+
use aws.protocols#awsQueryCompatible
58
use aws.protocols#awsQueryError
69
use aws.protocoltests.config#ErrorCodeParams
710
use smithy.protocols#rpcv2Cbor
811
use smithy.test#httpRequestTests
912
use smithy.test#httpResponseTests
1013

11-
@httpRequestTests([
12-
{
13-
id: "NonQueryCompatibleRpcV2CborForbidsQueryModeHeader"
14-
documentation: "The query mode header MUST NOT be set on non-query-compatible services."
15-
protocol: rpcv2Cbor
16-
method: "POST"
17-
headers: { "smithy-protocol": "rpc-v2-cbor", Accept: "application/cbor" }
18-
forbidHeaders: ["x-amzn-query-mode"]
19-
uri: "/service/NonQueryCompatibleRpcV2Protocol/operation/QueryIncompatibleOperation"
20-
body: ""
21-
}
22-
])
23-
@idempotent
24-
operation QueryIncompatibleOperation {}
14+
15+
@service(sdkId: "Query Compatible RpcV2 Protocol")
16+
@sigv4(name: "querycompatiblerpcv2protocol")
17+
@rpcv2Cbor
18+
@title("Query Compatible RpcV2 Protocol Service")
19+
@awsQueryCompatible
20+
service QueryCompatibleRpcV2Protocol {
21+
version: "2025-06-20"
22+
operations: [
23+
QueryCompatibleOperation
24+
]
25+
}
26+
2527

2628
@idempotent
2729
operation QueryCompatibleOperation {

smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/protocols/QueryErrorCodeValidator.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
package software.amazon.smithy.aws.traits.protocols;
66

77
import java.util.ArrayList;
8+
import java.util.Collections;
89
import java.util.HashMap;
10+
import java.util.HashSet;
911
import java.util.List;
1012
import java.util.Map;
11-
import java.util.Objects;
1213
import java.util.Set;
1314
import java.util.TreeSet;
14-
import java.util.stream.Collectors;
1515
import software.amazon.smithy.model.Model;
1616
import software.amazon.smithy.model.knowledge.TopDownIndex;
17+
import software.amazon.smithy.model.shapes.OperationShape;
1718
import software.amazon.smithy.model.shapes.ServiceShape;
1819
import software.amazon.smithy.model.shapes.Shape;
1920
import software.amazon.smithy.model.shapes.ShapeId;
@@ -26,42 +27,53 @@
2627
*/
2728
@SmithyInternalApi
2829
public class QueryErrorCodeValidator extends AbstractValidator {
30+
2931
@Override
3032
public List<ValidationEvent> validate(Model model) {
31-
List<ValidationEvent> events = new ArrayList<>();
33+
List<ValidationEvent> events = Collections.emptyList();
3234
for (ServiceShape service : model.getServiceShapes()) {
3335
if (service.hasTrait(AwsQueryCompatibleTrait.class) || service.hasTrait(AwsQueryTrait.class)
3436
|| service.hasTrait(Ec2QueryTrait.class)) {
35-
events.addAll(validateService(model, service));
37+
List<ValidationEvent> serviceEvents = validateService(model, service);
38+
if (!serviceEvents.isEmpty()) {
39+
if (events.isEmpty()) {
40+
events = new ArrayList<>();
41+
}
42+
events.addAll(serviceEvents);
43+
}
3644
}
3745
}
3846
return events;
3947
}
4048

4149
private List<ValidationEvent> validateService(Model model, ServiceShape service) {
42-
List<ValidationEvent> events = new ArrayList<>();
4350
TopDownIndex index = TopDownIndex.of(model);
44-
List<ShapeId> errors = new ArrayList<>(service.getErrors());
45-
index.getContainedOperations(service).forEach(operation -> errors.addAll(operation.getErrors()));
51+
Set<ShapeId> errors = new HashSet<>(service.getErrors());
52+
for (OperationShape operation : index.getContainedOperations(service)) {
53+
errors.addAll(operation.getErrors());
54+
}
4655

47-
Map<String, Set<ShapeId>> errorCodeBindings = new HashMap<>();
56+
Map<String, Set<String>> errorCodeBindings = new HashMap<>();
4857
for (ShapeId errorId : errors) {
4958
String errorCode = errorId.getName();
5059
Shape errorShape = model.expectShape(errorId);
5160
if (errorShape.hasTrait(AwsQueryErrorTrait.class)) {
5261
AwsQueryErrorTrait trait = errorShape.expectTrait(AwsQueryErrorTrait.class);
5362
errorCode = trait.getCode();
5463
}
55-
errorCodeBindings.computeIfAbsent(errorCode, k -> new TreeSet<>()).add(errorId);
64+
errorCodeBindings.computeIfAbsent(errorCode, k -> new TreeSet<>()).add(errorId.toString());
5665
}
57-
58-
for (Map.Entry<String, Set<ShapeId>> entry : errorCodeBindings.entrySet()) {
66+
List<ValidationEvent> events = Collections.emptyList();
67+
for (Map.Entry<String, Set<String>> entry : errorCodeBindings.entrySet()) {
5968
if (entry.getValue().size() == 1) {
6069
continue;
6170
}
6271
String errorCode = entry.getKey();
63-
String shapes = entry.getValue().stream().map(Objects::toString).collect(Collectors.joining(", "));
64-
events.add(danger(service,
72+
String shapes = String.join(", ", entry.getValue());
73+
if (events.isEmpty()) {
74+
events = new ArrayList<>();
75+
}
76+
events.add(warning(service,
6577
String.format("Multiple error shapes with the error code `%s` found: [%s]. This error code "
6678
+ "ambiguity will result in the wrong error shape being deserialized when running the "
6779
+ "query protocol. This pain will be carried forward when migrating to a new protocol "
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
[DANGER] smithy.example#QueryCompatibleService: Multiple error shapes with the error code `ResourceNotFound` found: [smithy.example#DocumentNotFound, smithy.example#ResourceNotFound]. This error code ambiguity will result in the wrong error shape being deserialized when running the query protocol. This pain will be carried forward when migrating to a new protocol when using the awsQueryCompatible trait. | QueryErrorCode
2-
[DANGER] smithy.example#QueryService: Multiple error shapes with the error code `ResourceNotFound` found: [smithy.example#DocumentNotFound, smithy.example#ResourceNotFound]. This error code ambiguity will result in the wrong error shape being deserialized when running the query protocol. This pain will be carried forward when migrating to a new protocol when using the awsQueryCompatible trait. | QueryErrorCode
1+
[WARNING] smithy.example#QueryCompatibleService: Multiple error shapes with the error code `ResourceNotFound` found: [smithy.example#DocumentNotFound, smithy.example#ResourceNotFound]. This error code ambiguity will result in the wrong error shape being deserialized when running the query protocol. This pain will be carried forward when migrating to a new protocol when using the awsQueryCompatible trait. | QueryErrorCode
2+
[WARNING] smithy.example#QueryService: Multiple error shapes with the error code `ResourceNotFound` found: [smithy.example#DocumentNotFound, smithy.example#ResourceNotFound]. This error code ambiguity will result in the wrong error shape being deserialized when running the query protocol. This pain will be carried forward when migrating to a new protocol when using the awsQueryCompatible trait. | QueryErrorCode

0 commit comments

Comments
 (0)