Skip to content

Commit 50483e0

Browse files
committed
Test for gh-12610
Signed-off-by: Nikita Konev <[email protected]>
1 parent 33594ec commit 50483e0

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

web/src/main/java/org/springframework/security/web/ObservationFilterChainDecorator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public final class ObservationFilterChainDecorator implements FilterChainProxy.F
5353

5454
private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
5555

56-
private static final String ATTRIBUTE = ObservationFilterChainDecorator.class + ".observation";
56+
static final String ATTRIBUTE = ObservationFilterChainDecorator.class + ".observation";
5757

5858
static final String UNSECURED_OBSERVATION_NAME = "spring.security.http.unsecured.requests";
5959

web/src/test/java/org/springframework/security/web/FilterChainProxyTests.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,61 @@ public void doFilterWhenMatchesThenObservationRegistryObserves() throws Exceptio
310310
assertFilterChainObservation(contexts.next(), "after", 1);
311311
}
312312

313+
// gh-12610
314+
@Test
315+
void parentObservationIsTakenIntoAccountDuringDispatchError() throws Exception {
316+
ObservationHandler<Observation.Context> handler = mock(ObservationHandler.class);
317+
given(handler.supportsContext(any())).willReturn(true);
318+
ObservationRegistry registry = ObservationRegistry.create();
319+
registry.observationConfig().observationHandler(handler);
320+
321+
given(this.matcher.matches(any())).willReturn(true);
322+
SecurityFilterChain sec = new DefaultSecurityFilterChain(this.matcher, Arrays.asList(this.filter));
323+
FilterChainProxy fcp = new FilterChainProxy(sec);
324+
fcp.setFilterChainDecorator(new ObservationFilterChainDecorator(registry));
325+
Filter initialFilter = ObservationFilterChainDecorator.FilterObservation
326+
.create(Observation.createNotStarted("wrap", registry))
327+
.wrap(fcp);
328+
329+
ServletRequest initialRequest = new MockHttpServletRequest("GET", "/");
330+
initialFilter.doFilter(initialRequest, new MockHttpServletResponse(), this.chain);
331+
332+
// simulate request attribute copying in case dispatching to ERROR
333+
ObservationFilterChainDecorator.AroundFilterObservation parentObservation = (ObservationFilterChainDecorator.AroundFilterObservation) initialRequest.getAttribute(ObservationFilterChainDecorator.ATTRIBUTE);
334+
assertThat(parentObservation).isNotNull();
335+
336+
// simulate dispatching error-related request
337+
Filter errorRelatedFilter = ObservationFilterChainDecorator.FilterObservation
338+
.create(Observation.createNotStarted("wrap", registry))
339+
.wrap(fcp);
340+
ServletRequest errorRelatedRequest = new MockHttpServletRequest("GET", "/error");
341+
errorRelatedRequest.setAttribute(ObservationFilterChainDecorator.ATTRIBUTE, parentObservation);
342+
errorRelatedFilter.doFilter(errorRelatedRequest, new MockHttpServletResponse(), this.chain);
343+
344+
ArgumentCaptor<Observation.Context> captor = ArgumentCaptor.forClass(Observation.Context.class);
345+
verify(handler, times(8)).onStart(captor.capture());
346+
verify(handler, times(8)).onStop(any());
347+
List<Observation.Context> contexts = captor.getAllValues();
348+
349+
Observation.Context initialRequestObservationContextBefore = contexts.get(1);
350+
Observation.Context initialRequestObservationContextAfter = contexts.get(3);
351+
assertFilterChainObservation(initialRequestObservationContextBefore, "before", 1);
352+
assertFilterChainObservation(initialRequestObservationContextAfter, "after", 1);
353+
354+
assertThat(initialRequestObservationContextBefore.getParentObservation()).isNotNull();
355+
assertThat(initialRequestObservationContextBefore.getParentObservation()).isSameAs(initialRequestObservationContextAfter.getParentObservation());
356+
357+
Observation.Context errorRelatedRequestObservationContextBefore = contexts.get(5);
358+
Observation.Context errorRelatedRequestObservationContextAfter = contexts.get(7);
359+
assertFilterChainObservation(errorRelatedRequestObservationContextBefore, "before", 1);
360+
assertFilterChainObservation(errorRelatedRequestObservationContextAfter, "after", 1);
361+
362+
assertThat(errorRelatedRequestObservationContextBefore.getParentObservation()).isNotNull();
363+
assertThat(errorRelatedRequestObservationContextBefore.getParentObservation()).isSameAs(initialRequestObservationContextBefore.getParentObservation());
364+
assertThat(errorRelatedRequestObservationContextAfter.getParentObservation()).isNotNull();
365+
assertThat(errorRelatedRequestObservationContextAfter.getParentObservation()).isSameAs(initialRequestObservationContextBefore.getParentObservation());
366+
}
367+
313368
@Test
314369
public void doFilterWhenMultipleFiltersThenObservationRegistryObserves() throws Exception {
315370
ObservationHandler<Observation.Context> handler = mock(ObservationHandler.class);

0 commit comments

Comments
 (0)