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