19
19
import java .io .ByteArrayInputStream ;
20
20
import java .io .IOException ;
21
21
import java .net .URI ;
22
+ import java .nio .charset .StandardCharsets ;
22
23
import java .util .Map ;
23
24
import java .util .UUID ;
24
25
40
41
import org .springframework .http .client .observation .ClientRequestObservationConvention ;
41
42
import org .springframework .http .client .observation .DefaultClientRequestObservationConvention ;
42
43
import org .springframework .http .converter .HttpMessageConverter ;
44
+ import org .springframework .util .StreamUtils ;
43
45
44
46
import static org .assertj .core .api .Assertions .assertThat ;
45
47
import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
@@ -84,7 +86,7 @@ void setupEach() {
84
86
}
85
87
86
88
@ Test
87
- void executeVarArgsAddsUriTemplateAsKeyValue () throws Exception {
89
+ void shouldContributeTemplateWhenUriVariables () throws Exception {
88
90
mockSentRequest (GET , "https://example.com/hotels/42/bookings/21" );
89
91
mockResponseStatus (HttpStatus .OK );
90
92
@@ -95,7 +97,7 @@ void executeVarArgsAddsUriTemplateAsKeyValue() throws Exception {
95
97
}
96
98
97
99
@ Test
98
- void executeArgsMapAddsUriTemplateAsKeyValue () throws Exception {
100
+ void shouldContributeTemplateWhenMap () throws Exception {
99
101
mockSentRequest (GET , "https://example.com/hotels/42/bookings/21" );
100
102
mockResponseStatus (HttpStatus .OK );
101
103
@@ -107,9 +109,8 @@ void executeArgsMapAddsUriTemplateAsKeyValue() throws Exception {
107
109
assertThatHttpObservation ().hasLowCardinalityKeyValue ("uri" , "/hotels/{hotel}/bookings/{booking}" );
108
110
}
109
111
110
-
111
112
@ Test
112
- void executeAddsSuccessAsOutcome () throws Exception {
113
+ void shouldContributeSuccessOutcome () throws Exception {
113
114
mockSentRequest (GET , "https://example.org" );
114
115
mockResponseStatus (HttpStatus .OK );
115
116
mockResponseBody ("Hello World" , MediaType .TEXT_PLAIN );
@@ -120,7 +121,7 @@ void executeAddsSuccessAsOutcome() throws Exception {
120
121
}
121
122
122
123
@ Test
123
- void executeAddsServerErrorAsOutcome () throws Exception {
124
+ void shouldContributeServerErrorOutcome () throws Exception {
124
125
String url = "https://example.org" ;
125
126
mockSentRequest (GET , url );
126
127
mockResponseStatus (HttpStatus .INTERNAL_SERVER_ERROR );
@@ -134,7 +135,7 @@ void executeAddsServerErrorAsOutcome() throws Exception {
134
135
}
135
136
136
137
@ Test
137
- void executeAddsExceptionAsKeyValue () throws Exception {
138
+ void shouldContributeDecodingError () throws Exception {
138
139
mockSentRequest (POST , "https://example.org/resource" );
139
140
mockResponseStatus (HttpStatus .OK );
140
141
@@ -150,7 +151,7 @@ void executeAddsExceptionAsKeyValue() throws Exception {
150
151
}
151
152
152
153
@ Test
153
- void executeWithIoExceptionAddsUnknownOutcome () throws Exception {
154
+ void shouldContributeIOError () throws Exception {
154
155
String url = "https://example.org/resource" ;
155
156
mockSentRequest (GET , url );
156
157
given (request .execute ()).willThrow (new IOException ("Socket failure" ));
@@ -161,7 +162,7 @@ void executeWithIoExceptionAddsUnknownOutcome() throws Exception {
161
162
}
162
163
163
164
@ Test
164
- void executeWithCustomConventionUsesCustomObservationName () throws Exception {
165
+ void shouldUseCustomConvention () throws Exception {
165
166
ClientRequestObservationConvention observationConvention =
166
167
new DefaultClientRequestObservationConvention ("custom.requests" );
167
168
RestClient restClient = this .client .mutate ().observationConvention (observationConvention ).build ();
@@ -174,6 +175,56 @@ void executeWithCustomConventionUsesCustomObservationName() throws Exception {
174
175
.hasObservationWithNameEqualTo ("custom.requests" );
175
176
}
176
177
178
+ @ Test
179
+ void shouldAddClientDecodingErrorAsException () throws Exception {
180
+ String url = "https://example.org" ;
181
+ mockSentRequest (GET , url );
182
+ mockResponseStatus (HttpStatus .OK );
183
+ mockResponseBody ("INVALID" , MediaType .APPLICATION_JSON );
184
+
185
+ assertThatExceptionOfType (RestClientException .class ).isThrownBy (() ->
186
+ client .get ().uri (url ).retrieve ().body (User .class ));
187
+
188
+ assertThatHttpObservation ().hasLowCardinalityKeyValue ("exception" , "RestClientException" );
189
+ }
190
+
191
+ @ Test
192
+ void shouldAddUnknownContentTypeErrorAsException () throws Exception {
193
+ String url = "https://example.org" ;
194
+ mockSentRequest (GET , url );
195
+ mockResponseStatus (HttpStatus .OK );
196
+ mockResponseBody ("Not Found" , MediaType .TEXT_HTML );
197
+
198
+ assertThatExceptionOfType (RestClientException .class ).isThrownBy (() ->
199
+ client .get ().uri (url ).retrieve ().body (User .class ));
200
+
201
+ assertThatHttpObservation ().hasLowCardinalityKeyValue ("exception" , "UnknownContentTypeException" );
202
+ }
203
+
204
+ @ Test
205
+ void registerObservationWhenReadingBody () throws Exception {
206
+ mockSentRequest (GET , "https://example.org" );
207
+ mockResponseStatus (HttpStatus .OK );
208
+ mockResponseBody ("Hello World" , MediaType .TEXT_PLAIN );
209
+
210
+ client .get ().uri ("https://example.org" ).exchange ((request , response ) -> response .bodyTo (String .class ));
211
+ assertThatHttpObservation ().hasLowCardinalityKeyValue ("outcome" , "SUCCESS" );
212
+ }
213
+
214
+ @ Test
215
+ void registerObservationWhenReadingStream () throws Exception {
216
+ mockSentRequest (GET , "https://example.org" );
217
+ mockResponseStatus (HttpStatus .OK );
218
+ mockResponseBody ("Hello World" , MediaType .TEXT_PLAIN );
219
+
220
+ client .get ().uri ("https://example.org" ).exchange ((request , response ) -> {
221
+ String result = StreamUtils .copyToString (response .getBody (), StandardCharsets .UTF_8 );
222
+ response .close ();
223
+ return result ;
224
+ }, false );
225
+ assertThatHttpObservation ().hasLowCardinalityKeyValue ("outcome" , "SUCCESS" );
226
+ }
227
+
177
228
178
229
private void mockSentRequest (HttpMethod method , String uri ) throws Exception {
179
230
mockSentRequest (method , uri , new HttpHeaders ());
@@ -220,4 +271,8 @@ public void onStart(ClientRequestObservationContext context) {
220
271
}
221
272
}
222
273
274
+ record User (String name ) {
275
+
276
+ }
277
+
223
278
}
0 commit comments