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 );
@@ -126,9 +141,52 @@ void shouldCloseObservationAfterAsyncCompletion() throws Exception {
126
141
assertThatHttpObservation ().hasLowCardinalityKeyValue ("outcome" , "SUCCESS" ).hasBeenStopped ();
127
142
}
128
143
144
+ @ Test
145
+ void shouldCloseObservationAfterAsyncError () throws Exception {
146
+ this .request .setAsyncSupported (true );
147
+ this .request .startAsync ();
148
+ this .filter .doFilter (this .request , this .response , this .mockFilterChain );
149
+ MockAsyncContext asyncContext = (MockAsyncContext ) this .request .getAsyncContext ();
150
+ for (AsyncListener listener : asyncContext .getListeners ()) {
151
+ listener .onError (new AsyncEvent (this .request .getAsyncContext (), new IllegalStateException ("test error" )));
152
+ }
153
+ asyncContext .complete ();
154
+ assertThatHttpObservation ().hasLowCardinalityKeyValue ("exception" , "IllegalStateException" ).hasBeenStopped ();
155
+ }
156
+
157
+ @ Test
158
+ void shouldNotCloseObservationDuringAsyncDispatch () throws Exception {
159
+ this .mockFilterChain = new MockFilterChain (new ScopeCheckingServlet (this .observationRegistry ));
160
+ this .request .setDispatcherType (DispatcherType .ASYNC );
161
+ this .filter .doFilter (this .request , this .response , this .mockFilterChain );
162
+ TestObservationRegistryAssert .assertThat (this .observationRegistry )
163
+ .hasObservationWithNameEqualTo ("http.server.requests" )
164
+ .that ().isNotStopped ();
165
+ }
166
+
129
167
private TestObservationRegistryAssert .TestObservationRegistryAssertReturningObservationContextAssert assertThatHttpObservation () {
168
+ TestObservationRegistryAssert .assertThat (this .observationRegistry )
169
+ .hasNumberOfObservationsWithNameEqualTo ("http.server.requests" , 1 );
170
+
130
171
return TestObservationRegistryAssert .assertThat (this .observationRegistry )
131
- .hasObservationWithNameEqualTo ("http.server.requests" ).that ();
172
+ .hasObservationWithNameEqualTo ("http.server.requests" )
173
+ .that ()
174
+ .hasBeenStopped ();
175
+ }
176
+
177
+ @ SuppressWarnings ("serial" )
178
+ static class ScopeCheckingServlet extends HttpServlet {
179
+
180
+ private final ObservationRegistry observationRegistry ;
181
+
182
+ public ScopeCheckingServlet (ObservationRegistry observationRegistry ) {
183
+ this .observationRegistry = observationRegistry ;
184
+ }
185
+
186
+ @ Override
187
+ protected void doGet (HttpServletRequest req , HttpServletResponse resp ) throws ServletException , IOException {
188
+ assertThat (this .observationRegistry .getCurrentObservation ()).isNotNull ();
189
+ }
132
190
}
133
191
134
192
}
0 commit comments