16
16
17
17
package org .springframework .web .filter ;
18
18
19
+ import java .io .IOException ;
20
+
19
21
import io .micrometer .observation .Observation ;
20
22
import io .micrometer .observation .ObservationRegistry ;
21
23
import io .micrometer .observation .tck .TestObservationRegistry ;
22
24
import io .micrometer .observation .tck .TestObservationRegistryAssert ;
25
+ import jakarta .servlet .AsyncEvent ;
26
+ import jakarta .servlet .AsyncListener ;
27
+ import jakarta .servlet .DispatcherType ;
23
28
import jakarta .servlet .RequestDispatcher ;
24
29
import jakarta .servlet .ServletException ;
30
+ import jakarta .servlet .http .HttpServlet ;
25
31
import jakarta .servlet .http .HttpServletRequest ;
26
32
import jakarta .servlet .http .HttpServletResponse ;
27
33
import org .junit .jupiter .api .Test ;
28
34
29
35
import org .springframework .http .HttpMethod ;
30
36
import org .springframework .http .server .observation .ServerRequestObservationContext ;
31
37
import org .springframework .util .Assert ;
38
+ import org .springframework .web .testfixture .servlet .MockAsyncContext ;
32
39
import org .springframework .web .testfixture .servlet .MockFilterChain ;
33
40
import org .springframework .web .testfixture .servlet .MockHttpServletRequest ;
34
41
import org .springframework .web .testfixture .servlet .MockHttpServletResponse ;
@@ -45,18 +52,18 @@ class ServerHttpObservationFilterTests {
45
52
46
53
private final TestObservationRegistry observationRegistry = TestObservationRegistry .create ();
47
54
48
- private final MockFilterChain mockFilterChain = new MockFilterChain ();
49
-
50
55
private final MockHttpServletRequest request = new MockHttpServletRequest (HttpMethod .GET .name (), "/resource/test" );
51
56
52
57
private final MockHttpServletResponse response = new MockHttpServletResponse ();
53
58
59
+ private MockFilterChain mockFilterChain = new MockFilterChain ();
60
+
54
61
private ServerHttpObservationFilter filter = new ServerHttpObservationFilter (this .observationRegistry );
55
62
56
63
57
64
@ Test
58
- void filterShouldNotProcessAsyncDispatch () {
59
- assertThat (this .filter .shouldNotFilterAsyncDispatch ()).isTrue ();
65
+ void filterShouldProcessAsyncDispatch () {
66
+ assertThat (this .filter .shouldNotFilterAsyncDispatch ()).isFalse ();
60
67
}
61
68
62
69
@ Test
@@ -72,6 +79,12 @@ void filterShouldFillObservationContext() throws Exception {
72
79
assertThatHttpObservation ().hasLowCardinalityKeyValue ("outcome" , "SUCCESS" ).hasBeenStopped ();
73
80
}
74
81
82
+ @ Test
83
+ void filterShouldOpenScope () throws Exception {
84
+ this .mockFilterChain = new MockFilterChain (new ScopeCheckingServlet (this .observationRegistry ));
85
+ filter .doFilter (this .request , this .response , this .mockFilterChain );
86
+ }
87
+
75
88
@ Test
76
89
void filterShouldAcceptNoOpObservationContext () throws Exception {
77
90
this .filter = new ServerHttpObservationFilter (ObservationRegistry .NOOP );
@@ -136,9 +149,52 @@ void shouldCloseObservationAfterAsyncCompletion() throws Exception {
136
149
assertThatHttpObservation ().hasLowCardinalityKeyValue ("outcome" , "SUCCESS" ).hasBeenStopped ();
137
150
}
138
151
152
+ @ Test
153
+ void shouldCloseObservationAfterAsyncError () throws Exception {
154
+ this .request .setAsyncSupported (true );
155
+ this .request .startAsync ();
156
+ this .filter .doFilter (this .request , this .response , this .mockFilterChain );
157
+ MockAsyncContext asyncContext = (MockAsyncContext ) this .request .getAsyncContext ();
158
+ for (AsyncListener listener : asyncContext .getListeners ()) {
159
+ listener .onError (new AsyncEvent (this .request .getAsyncContext (), new IllegalStateException ("test error" )));
160
+ }
161
+ asyncContext .complete ();
162
+ assertThatHttpObservation ().hasLowCardinalityKeyValue ("exception" , "IllegalStateException" ).hasBeenStopped ();
163
+ }
164
+
165
+ @ Test
166
+ void shouldNotCloseObservationDuringAsyncDispatch () throws Exception {
167
+ this .mockFilterChain = new MockFilterChain (new ScopeCheckingServlet (this .observationRegistry ));
168
+ this .request .setDispatcherType (DispatcherType .ASYNC );
169
+ this .filter .doFilter (this .request , this .response , this .mockFilterChain );
170
+ TestObservationRegistryAssert .assertThat (this .observationRegistry )
171
+ .hasObservationWithNameEqualTo ("http.server.requests" )
172
+ .that ().isNotStopped ();
173
+ }
174
+
139
175
private TestObservationRegistryAssert .TestObservationRegistryAssertReturningObservationContextAssert assertThatHttpObservation () {
176
+ TestObservationRegistryAssert .assertThat (this .observationRegistry )
177
+ .hasNumberOfObservationsWithNameEqualTo ("http.server.requests" , 1 );
178
+
140
179
return TestObservationRegistryAssert .assertThat (this .observationRegistry )
141
- .hasObservationWithNameEqualTo ("http.server.requests" ).that ();
180
+ .hasObservationWithNameEqualTo ("http.server.requests" )
181
+ .that ()
182
+ .hasBeenStopped ();
183
+ }
184
+
185
+ @ SuppressWarnings ("serial" )
186
+ static class ScopeCheckingServlet extends HttpServlet {
187
+
188
+ private final ObservationRegistry observationRegistry ;
189
+
190
+ public ScopeCheckingServlet (ObservationRegistry observationRegistry ) {
191
+ this .observationRegistry = observationRegistry ;
192
+ }
193
+
194
+ @ Override
195
+ protected void doGet (HttpServletRequest req , HttpServletResponse resp ) throws ServletException , IOException {
196
+ assertThat (this .observationRegistry .getCurrentObservation ()).isNotNull ();
197
+ }
142
198
}
143
199
144
200
static class CustomObservationFilter extends ServerHttpObservationFilter {
0 commit comments