3838import io .micrometer .core .annotation .Timed ;
3939import io .micrometer .core .instrument .Clock ;
4040import io .micrometer .core .instrument .Meter ;
41+ import io .micrometer .core .instrument .Meter .Id ;
4142import io .micrometer .core .instrument .MeterRegistry ;
4243import io .micrometer .core .instrument .MockClock ;
4344import io .micrometer .core .instrument .Tag ;
@@ -126,8 +127,8 @@ class WebMvcMetricsFilterTests {
126127
127128 @ BeforeEach
128129 void setupMockMvc () {
129- this .mvc = MockMvcBuilders .webAppContextSetup (this .context )
130- .addFilters ( this . filter , new RedirectAndNotFoundFilter ()). build ();
130+ this .mvc = MockMvcBuilders .webAppContextSetup (this .context ). addFilters ( this . filter , new CustomBehaviorFilter ())
131+ .build ();
131132 }
132133
133134 @ Test
@@ -164,15 +165,15 @@ void badClientRequest() throws Exception {
164165
165166 @ Test
166167 void redirectRequest () throws Exception {
167- this .mvc .perform (get ("/api/redirect" ).header (RedirectAndNotFoundFilter . TEST_MISBEHAVE_HEADER , "302" ))
168+ this .mvc .perform (get ("/api/redirect" ).header (CustomBehaviorFilter . TEST_STATUS_HEADER , "302" ))
168169 .andExpect (status ().is3xxRedirection ());
169170 assertThat (this .registry .get ("http.server.requests" ).tags ("uri" , "REDIRECTION" ).tags ("status" , "302" ).timer ())
170171 .isNotNull ();
171172 }
172173
173174 @ Test
174175 void notFoundRequest () throws Exception {
175- this .mvc .perform (get ("/api/not/found" ).header (RedirectAndNotFoundFilter . TEST_MISBEHAVE_HEADER , "404" ))
176+ this .mvc .perform (get ("/api/not/found" ).header (CustomBehaviorFilter . TEST_STATUS_HEADER , "404" ))
176177 .andExpect (status ().is4xxClientError ());
177178 assertThat (this .registry .get ("http.server.requests" ).tags ("uri" , "NOT_FOUND" ).tags ("status" , "404" ).timer ())
178179 .isNotNull ();
@@ -186,13 +187,23 @@ void unhandledError() {
186187 .isEqualTo (1L );
187188 }
188189
190+ @ Test
191+ void unhandledServletException () {
192+ assertThatCode (() -> this .mvc
193+ .perform (get ("/api/filterError" ).header (CustomBehaviorFilter .TEST_SERVLET_EXCEPTION_HEADER , "throw" ))
194+ .andExpect (status ().isOk ())).isInstanceOf (ServletException .class );
195+ Id meterId = this .registry .get ("http.server.requests" ).tags ("exception" , "ServletException" ).timer ().getId ();
196+ assertThat (meterId .getTag ("status" )).isEqualTo ("500" );
197+ }
198+
189199 @ Test
190200 void streamingError () throws Exception {
191201 MvcResult result = this .mvc .perform (get ("/api/c1/streamingError" )).andExpect (request ().asyncStarted ())
192202 .andReturn ();
193203 assertThatIOException ().isThrownBy (() -> this .mvc .perform (asyncDispatch (result )).andReturn ());
194- assertThat (this .registry .get ("http.server.requests" ).tags ("exception" , "IOException" ).timer ().count ())
195- .isEqualTo (1L );
204+ Id meterId = this .registry .get ("http.server.requests" ).tags ("exception" , "IOException" ).timer ().getId ();
205+ // Response is committed before error occurs so status is 200 (OK)
206+ assertThat (meterId .getTag ("status" )).isEqualTo ("200" );
196207 }
197208
198209 @ Test
@@ -208,8 +219,10 @@ void anonymousError() {
208219 }
209220 catch (Throwable ignore ) {
210221 }
211- assertThat (this .registry .get ("http.server.requests" ).tag ("uri" , "/api/c1/anonymousError/{id}" ).timer ().getId ()
212- .getTag ("exception" )).endsWith ("$1" );
222+ Id meterId = this .registry .get ("http.server.requests" ).tag ("uri" , "/api/c1/anonymousError/{id}" ).timer ()
223+ .getId ();
224+ assertThat (meterId .getTag ("exception" )).endsWith ("$1" );
225+ assertThat (meterId .getTag ("status" )).isEqualTo ("500" );
213226 }
214227
215228 @ Test
@@ -357,8 +370,8 @@ public MeterFilterReply accept(@NonNull Meter.Id id) {
357370 }
358371
359372 @ Bean
360- RedirectAndNotFoundFilter redirectAndNotFoundFilter () {
361- return new RedirectAndNotFoundFilter ();
373+ CustomBehaviorFilter redirectAndNotFoundFilter () {
374+ return new CustomBehaviorFilter ();
362375 }
363376
364377 @ Bean (name = "callableBarrier" )
@@ -472,8 +485,10 @@ String alwaysThrowsUnhandledException(@PathVariable Long id) {
472485 }
473486
474487 @ GetMapping ("/streamingError" )
475- ResponseBodyEmitter streamingError () {
488+ ResponseBodyEmitter streamingError () throws IOException {
476489 ResponseBodyEmitter emitter = new ResponseBodyEmitter ();
490+ emitter .send ("some data" );
491+ emitter .send ("some more data" );
477492 emitter .completeWithError (new IOException ("error while writing to the response" ));
478493 return emitter ;
479494 }
@@ -522,20 +537,24 @@ String successful(@PathVariable Long id) {
522537
523538 }
524539
525- static class RedirectAndNotFoundFilter extends OncePerRequestFilter {
540+ static class CustomBehaviorFilter extends OncePerRequestFilter {
541+
542+ static final String TEST_STATUS_HEADER = "x-test-status" ;
526543
527- static final String TEST_MISBEHAVE_HEADER = "x-test-misbehave-status " ;
544+ static final String TEST_SERVLET_EXCEPTION_HEADER = "x-test-servlet-exception " ;
528545
529546 @ Override
530547 protected void doFilterInternal (HttpServletRequest request , HttpServletResponse response ,
531548 FilterChain filterChain ) throws ServletException , IOException {
532- String misbehave = request .getHeader (TEST_MISBEHAVE_HEADER );
533- if (misbehave != null ) {
534- response .setStatus (Integer .parseInt (misbehave ));
549+ String misbehaveStatus = request .getHeader (TEST_STATUS_HEADER );
550+ if (misbehaveStatus != null ) {
551+ response .setStatus (Integer .parseInt (misbehaveStatus ));
552+ return ;
535553 }
536- else {
537- filterChain . doFilter ( request , response );
554+ if ( request . getHeader ( TEST_SERVLET_EXCEPTION_HEADER ) != null ) {
555+ throw new ServletException ( );
538556 }
557+ filterChain .doFilter (request , response );
539558 }
540559
541560 }
0 commit comments