Skip to content

Commit 351f916

Browse files
committed
Add dynamic client test for http bindings
1 parent 50aabc7 commit 351f916

1 file changed

Lines changed: 158 additions & 0 deletions

File tree

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package software.amazon.smithy.java.dynamicclient;
7+
8+
import static org.hamcrest.MatcherAssert.assertThat;
9+
import static org.hamcrest.Matchers.equalTo;
10+
11+
import java.util.Map;
12+
import java.util.concurrent.atomic.AtomicReference;
13+
import org.junit.jupiter.api.BeforeAll;
14+
import org.junit.jupiter.api.Test;
15+
import software.amazon.smithy.java.aws.client.restjson.RestJsonClientProtocol;
16+
import software.amazon.smithy.java.client.core.ClientTransport;
17+
import software.amazon.smithy.java.client.core.MessageExchange;
18+
import software.amazon.smithy.java.client.core.auth.scheme.AuthSchemeResolver;
19+
import software.amazon.smithy.java.client.http.HttpMessageExchange;
20+
import software.amazon.smithy.java.context.Context;
21+
import software.amazon.smithy.java.core.serde.document.Document;
22+
import software.amazon.smithy.java.endpoints.EndpointResolver;
23+
import software.amazon.smithy.java.http.api.HttpRequest;
24+
import software.amazon.smithy.java.http.api.HttpResponse;
25+
import software.amazon.smithy.java.http.api.HttpVersion;
26+
import software.amazon.smithy.java.io.datastream.DataStream;
27+
import software.amazon.smithy.model.Model;
28+
import software.amazon.smithy.model.shapes.ShapeId;
29+
30+
/**
31+
* Verifies that HTTP header, query, and label bindings serialize correctly when the input is a document-backed
32+
* struct (the DynamicClient path), including enum-typed members. This is the sibling of the path-label coverage in
33+
* {@code PathSerializerTest}: the header/query serializer is push-based (it dispatches typed {@code writeX} calls
34+
* via {@code serializeMembers}), so it should never see a raw {@code Document}/{@code SmithyEnum}, but we assert it
35+
* end-to-end to be sure.
36+
*/
37+
public class DynamicClientHttpBindingTest {
38+
39+
private static final ShapeId SERVICE = ShapeId.from("smithy.example#Widgets");
40+
41+
private static Model model;
42+
43+
@BeforeAll
44+
public static void setup() {
45+
model = Model.assembler()
46+
.addUnparsedModel("test.smithy", """
47+
$version: "2"
48+
namespace smithy.example
49+
50+
use aws.protocols#restJson1
51+
52+
@restJson1
53+
@smithy.rules#endpointRuleSet(
54+
version: "1.0",
55+
serviceId: "widgets",
56+
parameters: {},
57+
rules: [
58+
{
59+
"documentation": "Static endpoint",
60+
"type": "endpoint",
61+
"conditions": [],
62+
"endpoint": {"url": "https://example.com"}
63+
}
64+
]
65+
)
66+
service Widgets {
67+
operations: [GetWidget]
68+
}
69+
70+
enum Color {
71+
RED
72+
GREEN
73+
}
74+
75+
@http(method: "GET", uri: "/widgets/{id}")
76+
operation GetWidget {
77+
input := {
78+
@required
79+
@httpLabel
80+
id: String
81+
82+
@httpHeader("x-color")
83+
headerColor: Color
84+
85+
@httpHeader("x-name")
86+
headerName: String
87+
88+
@httpQuery("color")
89+
queryColor: Color
90+
91+
@httpQuery("count")
92+
queryCount: Integer
93+
}
94+
output := {}
95+
}
96+
""")
97+
.discoverModels()
98+
.assemble()
99+
.unwrap();
100+
}
101+
102+
@Test
103+
public void serializesHeaderAndQueryBindingsFromDocument() {
104+
var captured = new AtomicReference<HttpRequest>();
105+
var client = DynamicClient.builder()
106+
.serviceId(SERVICE)
107+
.model(model)
108+
.protocol(new RestJsonClientProtocol(SERVICE))
109+
.authSchemeResolver(AuthSchemeResolver.NO_AUTH)
110+
.transport(capturingTransport(captured))
111+
.endpointResolver(EndpointResolver.staticEndpoint("https://example.com"))
112+
.build();
113+
114+
client.call("GetWidget",
115+
Document.ofObject(Map.of(
116+
"id",
117+
"abc",
118+
"headerColor",
119+
"RED",
120+
"headerName",
121+
"gizmo",
122+
"queryColor",
123+
"GREEN",
124+
"queryCount",
125+
7)));
126+
127+
var request = captured.get();
128+
// Enum and string headers serialize as their wire values, not toString() of a wrapper.
129+
assertThat(request.headers().firstValue("x-color"), equalTo("RED"));
130+
assertThat(request.headers().firstValue("x-name"), equalTo("gizmo"));
131+
132+
// Path label.
133+
assertThat(request.uri().getPath(), equalTo("/widgets/abc"));
134+
135+
// Query params (enum + integer).
136+
var query = request.uri().getQuery();
137+
assertThat(query, equalTo("color=GREEN&count=7"));
138+
}
139+
140+
private static ClientTransport<HttpRequest, HttpResponse> capturingTransport(AtomicReference<HttpRequest> sink) {
141+
return new ClientTransport<>() {
142+
@Override
143+
public MessageExchange<HttpRequest, HttpResponse> messageExchange() {
144+
return HttpMessageExchange.INSTANCE;
145+
}
146+
147+
@Override
148+
public HttpResponse send(Context context, HttpRequest request) {
149+
sink.set(request);
150+
return HttpResponse.create()
151+
.setHttpVersion(HttpVersion.HTTP_1_1)
152+
.setStatusCode(200)
153+
.setBody(DataStream.ofString("{}"))
154+
.toUnmodifiable();
155+
}
156+
};
157+
}
158+
}

0 commit comments

Comments
 (0)