Skip to content

Commit 7a3d44a

Browse files
committed
Add CustomClientTest
1 parent 6ba37e3 commit 7a3d44a

File tree

4 files changed

+178
-33
lines changed

4 files changed

+178
-33
lines changed

Diff for: src/main/java/com/vonage/client/CustomClient.java

+22-29
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.vonage.client.common.HttpMethod;
2424
import org.apache.http.HttpResponse;
2525
import java.util.Map;
26-
import java.util.Objects;
2726

2827
/**
2928
* Client for making custom requests to Vonage APIs unsupported by this SDK.
@@ -73,40 +72,34 @@ public CustomClient(HttpWrapper httpWrapper) {
7372
* @param <R> The response body type.
7473
*/
7574
public <T, R> R makeRequest(HttpMethod requestMethod, String url, T requestBody, R... responseType) {
76-
return DynamicEndpoint.<T, R> builder(
77-
Objects.requireNonNull(responseType, "Do not pass anything for responseType, omit it instead.")
78-
).wrapper(httpWrapper).requestMethod(requestMethod)
75+
return DynamicEndpoint.<T, R> builder(fixResponseType(responseType))
76+
.wrapper(httpWrapper).requestMethod(requestMethod)
7977
.authMethod(JWTAuthMethod.class, ApiKeyAuthMethod.class, NoAuthMethod.class)
8078
.pathGetter((de, req) -> url)
8179
.build().execute(requestBody);
8280
}
8381

82+
private <R> R[] fixResponseType(R... responseType) {
83+
return responseType == null || Object.class.equals(responseType.getClass().getComponentType()) ?
84+
(R[]) new Void[0] : responseType;
85+
}
86+
8487
/**
8588
* Convenience method for making DELETE requests.
89+
* In most cases, you should assign the return value to Void.
8690
*
8791
* @param url URL to send the request to as a string.
8892
* @param responseType Hack for type inference. Do not provide this field (especially, DO NOT pass {@code null}).
8993
*
9094
* @return The parsed response object, or {@code null} if absent / not applicable.
9195
* @throws VonageApiResponseException If the HTTP response code is >= 400.
9296
*
93-
* @param <R> The response body type.
97+
* @param <R> The response body type, most likely {@linkplain Void}.
9498
*/
9599
public <R> R delete(String url, R... responseType) {
96100
return makeRequest(HttpMethod.DELETE, url, null, responseType);
97101
}
98102

99-
/**
100-
* Convenience method for making DELETE requests.
101-
*
102-
* @param url URL to send the request to as a string.
103-
*
104-
* @throws VonageApiResponseException If the HTTP response code is >= 400.
105-
*/
106-
public void delete(String url) {
107-
delete(url, new Void[0]);
108-
}
109-
110103
/**
111104
* Convenience method for making GET requests.
112105
*
@@ -168,31 +161,31 @@ public <R> R patch(String url, Jsonable requestBody, R... responseType) {
168161
}
169162

170163
/**
171-
* Convenience method for making JSON-based POST requests.
164+
* Convenience method for making JSON-based GET requests.
172165
*
173166
* @param url URL to send the request to as a string.
174-
* @param requestBody The payload to convert to JSON and send in the request body.
175167
*
176168
* @return The response body converted from JSON into a Map.
177169
* @throws VonageApiResponseException If the HTTP response code is >= 400.
178170
*/
179-
public Map<String, ?> postJson(String url, Map<String, Object> requestBody) {
180-
JsonableMap map = new JsonableMap();
181-
map.body = requestBody;
182-
map = post(url, map);
171+
public Map<String, ?> getJson(String url) {
172+
JsonableMap map = get(url);
183173
return map.body;
184174
}
185175

186176
/**
187-
* Convenience method for making JSON-based GET requests.
177+
* Convenience method for making JSON-based POST requests.
188178
*
189179
* @param url URL to send the request to as a string.
180+
* @param requestBody The payload to convert to JSON and send in the request body.
190181
*
191182
* @return The response body converted from JSON into a Map.
192183
* @throws VonageApiResponseException If the HTTP response code is >= 400.
193184
*/
194-
public Map<String, ?> getJson(String url) {
195-
JsonableMap map = get(url);
185+
public Map<String, ?> postJson(String url, Map<String, ?> requestBody) {
186+
JsonableMap map = new JsonableMap();
187+
map.body = (Map<String, Object>) requestBody;
188+
map = post(url, map);
196189
return map.body;
197190
}
198191

@@ -205,9 +198,9 @@ public <R> R patch(String url, Jsonable requestBody, R... responseType) {
205198
* @return The response body converted from JSON into a Map.
206199
* @throws VonageApiResponseException If the HTTP response code is >= 400.
207200
*/
208-
public Map<String, ?> putJson(String url, Map<String, Object> requestBody) {
201+
public Map<String, ?> putJson(String url, Map<String, ?> requestBody) {
209202
JsonableMap map = new JsonableMap();
210-
map.body = requestBody;
203+
map.body = (Map<String, Object>) requestBody;
211204
map = put(url, map);
212205
return map.body;
213206
}
@@ -221,9 +214,9 @@ public <R> R patch(String url, Jsonable requestBody, R... responseType) {
221214
* @return The response body converted from JSON into a Map.
222215
* @throws VonageApiResponseException If the HTTP response code is >= 400.
223216
*/
224-
public Map<String, ?> patchJson(String url, Map<String, Object> requestBody) {
217+
public Map<String, ?> patchJson(String url, Map<String, ?> requestBody) {
225218
JsonableMap map = new JsonableMap();
226-
map.body = requestBody;
219+
map.body = (Map<String, Object>) requestBody;
227220
map = patch(url, map);
228221
return map.body;
229222
}
+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
* Copyright 2025 Vonage
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.vonage.client;
17+
18+
import com.fasterxml.jackson.annotation.JsonProperty;
19+
import org.junit.jupiter.api.*;
20+
import static org.junit.jupiter.api.Assertions.*;
21+
import java.util.List;
22+
import java.util.Map;
23+
24+
@SuppressWarnings("unchecked")
25+
public class CustomClientTest extends AbstractClientTest<CustomClient> {
26+
private static final String URL = "https://api.example.com/endpoint";
27+
private static final Map<String, ?> PAYLOAD_MAP = Map.of(
28+
"Key 1", "value1",
29+
"K2", 2,
30+
"Key3", true,
31+
"4th_Key", Map.of(
32+
"Nested Key 1", "nestedValue1",
33+
"Nested Key 2", List.of("nestedLevel2Val1", 3.1459),
34+
"NK3", false,
35+
"Nested Key 4", Map.of(
36+
"Deeply Nested Key 1", "deeplyNestedValue1",
37+
"Deeply Nested Key 2", Map.of("singleton", List.of()),
38+
"Deeply Nested Key 3", 0.000000001
39+
)
40+
),
41+
"k5", List.of(Map.of("k5l1", List.of(7, 8, 9)))
42+
);
43+
private static final String PAYLOAD_STR = new OrderedMap(PAYLOAD_MAP.entrySet().toArray(Map.Entry[]::new)).toJson();
44+
private static final TestResponse TEST_JSONABLE = Jsonable.fromJson(PAYLOAD_STR);
45+
46+
static class TestResponse extends JsonableBaseObject {
47+
private String key1;
48+
private Integer k2;
49+
private Boolean key3;
50+
private Map<String, Object> nestedKey4;
51+
52+
@JsonProperty("Key 1")
53+
public String getKey1() {
54+
return key1;
55+
}
56+
57+
@JsonProperty("K2")
58+
public Integer getK2() {
59+
return k2;
60+
}
61+
62+
@JsonProperty("Key3")
63+
public Boolean isKey3() {
64+
return key3;
65+
}
66+
67+
@JsonProperty("4th_Key")
68+
public Map<String, ?> getNestedKey4() {
69+
return nestedKey4;
70+
}
71+
}
72+
73+
public CustomClientTest() {
74+
client = new CustomClient(wrapper);
75+
}
76+
77+
@Test
78+
public void testJsonMethods() throws Exception {
79+
stubResponse(PAYLOAD_STR);
80+
assertEquals(PAYLOAD_MAP, client.getJson(URL));
81+
assertEquals(PAYLOAD_MAP, client.postJson(URL, PAYLOAD_MAP));
82+
assertEquals(PAYLOAD_MAP, client.putJson(URL, PAYLOAD_MAP));
83+
assertEquals(PAYLOAD_MAP, client.patchJson(URL, PAYLOAD_MAP));
84+
}
85+
86+
@Test
87+
public void testDelete() throws Exception {
88+
stubResponse(204);
89+
client.delete(URL);
90+
assertNull(client.delete(URL, (Object) null));
91+
assertNull(client.delete(URL, (Object[]) null));
92+
stubResponse(204, PAYLOAD_STR);
93+
TestResponse responseBody = client.delete(URL);
94+
assertEquals(TEST_JSONABLE, responseBody);
95+
stubResponse(401);
96+
assertThrows(VonageApiResponseException.class, () -> client.delete(URL));
97+
}
98+
99+
@Test
100+
public void testGet() throws Exception {
101+
stubResponse(PAYLOAD_STR);
102+
TestResponse responseBody = client.get(URL);
103+
assertEquals(TEST_JSONABLE, responseBody);
104+
stubResponse(404);
105+
assertThrows(VonageApiResponseException.class, () -> client.get(URL));
106+
}
107+
108+
@Test
109+
public void testPost() throws Exception {
110+
stubResponse(PAYLOAD_STR);
111+
TestResponse responseBody = client.post(URL, new OrderedMap());
112+
assertEquals(TEST_JSONABLE, responseBody);
113+
stubResponse(201);
114+
client.post(URL, TEST_JSONABLE);
115+
assertNull(client.post(URL, TEST_JSONABLE, (Object) null));
116+
assertNull(client.post(URL, TEST_JSONABLE, (Object[]) null));
117+
stubResponse(400);
118+
assertThrows(VonageApiResponseException.class, () -> client.post(URL, TEST_JSONABLE));
119+
}
120+
121+
@Test
122+
public void testPut() throws Exception {
123+
stubResponse(PAYLOAD_STR);
124+
TestResponse responseBody = client.put(URL, new OrderedMap());
125+
assertEquals(TEST_JSONABLE, responseBody);
126+
stubResponse(202);
127+
client.put(URL, TEST_JSONABLE);
128+
assertNull(client.put(URL, TEST_JSONABLE, (Object) null));
129+
assertNull(client.put(URL, TEST_JSONABLE, (Object[]) null));
130+
stubResponse(409);
131+
assertThrows(VonageApiResponseException.class, () -> client.put(URL, TEST_JSONABLE));
132+
}
133+
134+
@Test
135+
public void testPatch() throws Exception {
136+
stubResponse(PAYLOAD_STR);
137+
TestResponse responseBody = client.patch(URL, new OrderedMap());
138+
assertEquals(TEST_JSONABLE, responseBody);
139+
stubResponse(204);
140+
client.patch(URL, TEST_JSONABLE);
141+
assertNull(client.patch(URL, TEST_JSONABLE, (Object) null));
142+
assertNull(client.patch(URL, TEST_JSONABLE, (Object[]) null));
143+
stubResponse(406);
144+
assertThrows(VonageApiResponseException.class, () -> client.patch(URL, TEST_JSONABLE));
145+
}
146+
}

Diff for: src/test/java/com/vonage/client/DynamicEndpointTest.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ static <T, R> DynamicEndpoint<T, R> newEndpoint(R... responseType) {
4646
return endpoint;
4747
}
4848

49+
50+
@Test
51+
public void testUntypedEndpoint() {
52+
assertThrows(IllegalStateException.class, DynamicEndpointTest::newEndpoint);
53+
}
54+
4955
@Test
5056
public void testRedirectHandling() throws Exception {
5157
DynamicEndpoint<byte[], URI> uriEndpoint = newEndpoint();
@@ -56,14 +62,14 @@ public void testRedirectHandling() throws Exception {
5662
stubResponse(WRAPPER, 302, TEST_REDIRECT_URI);
5763
assertEquals(TEST_REDIRECT_URI, stringEndpoint.execute("bar"));
5864

59-
DynamicEndpoint<String, Object> objectEndpoint = newEndpoint();
65+
DynamicEndpoint<String, DynamicEndpointTest> unsupportedReturnEndpoint = newEndpoint();
6066
stubResponse(WRAPPER, 302, TEST_REDIRECT_URI);
61-
assertThrows(IllegalStateException.class, () -> objectEndpoint.execute("foo"));
67+
assertThrows(IllegalStateException.class, () -> unsupportedReturnEndpoint.execute("foo"));
6268
}
6369

6470
@Test
6571
public void testInformationalResponse() throws Exception {
66-
var endpoint = newEndpoint();
72+
DynamicEndpoint<byte[], Void> endpoint = newEndpoint();
6773
stubResponse(WRAPPER, 100, "Continue");
6874
assertNull(endpoint.execute(new byte[0]));
6975
}

Diff for: src/test/java/com/vonage/client/OrderedMap.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import java.util.Map;
2121
import java.util.Map.Entry;
2222

23-
public class OrderedMap extends LinkedHashMap<String, Object> {
23+
public class OrderedMap extends LinkedHashMap<String, Object> implements Jsonable {
2424

2525
public OrderedMap() {
2626
super();

0 commit comments

Comments
 (0)