1+ package com .baeldung .resilience4j .eventendpoints ;
2+
3+ import io .github .resilience4j .circuitbreaker .CircuitBreaker ;
4+ import io .github .resilience4j .circuitbreaker .CircuitBreakerConfig ;
5+ import io .github .resilience4j .circuitbreaker .CircuitBreakerRegistry ;
6+ import io .github .resilience4j .circuitbreaker .event .CircuitBreakerEvent ;
7+ import io .github .resilience4j .circuitbreaker .event .CircuitBreakerOnErrorEvent ;
8+ import io .github .resilience4j .circuitbreaker .event .CircuitBreakerOnSuccessEvent ;
9+ import org .junit .jupiter .api .BeforeEach ;
10+ import org .junit .jupiter .api .Test ;
11+ import org .junit .jupiter .api .extension .ExtendWith ;
12+ import org .mockito .ArgumentCaptor ;
13+ import org .mockito .Captor ;
14+ import org .mockito .Mock ;
15+ import org .mockito .junit .jupiter .MockitoExtension ;
16+ import org .slf4j .Logger ;
17+
18+ import java .util .ArrayList ;
19+ import java .util .List ;
20+
21+ import static org .junit .jupiter .api .Assertions .*;
22+
23+ @ ExtendWith (MockitoExtension .class )
24+ class CircuitBreakerEventConsumerUnitTest {
25+
26+ private CircuitBreaker circuitBreaker ;
27+ private CircuitBreaker .EventPublisher eventPublisher ;
28+
29+ @ Mock
30+ private Logger mockLogger ;
31+
32+ @ Captor
33+ private ArgumentCaptor <String > logMessageCaptor ;
34+
35+ @ Captor
36+ private ArgumentCaptor <CircuitBreakerEvent > eventCaptor ;
37+
38+ @ BeforeEach
39+ void setUp () {
40+ CircuitBreakerConfig config = CircuitBreakerConfig .custom ()
41+ .failureRateThreshold (50 )
42+ .slidingWindowSize (5 )
43+ .build ();
44+
45+ CircuitBreakerRegistry registry = CircuitBreakerRegistry .of (config );
46+ circuitBreaker = registry .circuitBreaker ("testService" );
47+ eventPublisher = circuitBreaker .getEventPublisher ();
48+ }
49+
50+ @ Test
51+ void givenSuccessEventConsumer_whenSuccessfulCallExecuted_thenSuccessEventIsPublished () {
52+ // Arrange
53+ List <CircuitBreakerEvent > capturedEvents = new ArrayList <>();
54+ eventPublisher .onSuccess (capturedEvents ::add );
55+
56+ // Act
57+ String result = circuitBreaker .executeSupplier (() -> "success" );
58+
59+ // Assert
60+ assertEquals (1 , capturedEvents .size ());
61+ assertInstanceOf (CircuitBreakerOnSuccessEvent .class , capturedEvents .get (0 ));
62+ assertEquals ("success" , result );
63+ }
64+
65+ @ Test
66+ void givenErrorEventConsumer_whenFailingCallExecuted_thenErrorEventIsPublished () {
67+ // Arrange
68+ List <CircuitBreakerEvent > capturedEvents = new ArrayList <>();
69+ eventPublisher .onError (capturedEvents ::add );
70+
71+ // Act & Assert
72+ RuntimeException exception = assertThrows (RuntimeException .class , () ->
73+ circuitBreaker .executeSupplier (() -> {
74+ throw new RuntimeException ("Test error" );
75+ })
76+ );
77+
78+ assertEquals (1 , capturedEvents .size ());
79+ assertInstanceOf (CircuitBreakerOnErrorEvent .class , capturedEvents .get (0 ));
80+ assertEquals ("Test error" , exception .getMessage ());
81+ }
82+
83+ @ Test
84+ void givenFailureRateExceededConsumer_whenConsumerRegistered_thenPublisherAcceptsRegistration () {
85+ // Arrange
86+ List <CircuitBreakerEvent > capturedEvents = new ArrayList <>();
87+
88+ // Act
89+ eventPublisher .onFailureRateExceeded (capturedEvents ::add );
90+
91+ // Assert
92+ assertNotNull (eventPublisher );
93+ }
94+
95+ @ Test
96+ void givenStateTransitionConsumer_whenConsumerRegistered_thenPublisherAcceptsRegistration () {
97+ // Arrange
98+ List <CircuitBreakerEvent > capturedEvents = new ArrayList <>();
99+
100+ // Act
101+ eventPublisher .onStateTransition (capturedEvents ::add );
102+
103+ // Assert
104+ assertNotNull (eventPublisher );
105+ }
106+
107+ @ Test
108+ void givenResetEventConsumer_whenConsumerRegistered_thenPublisherAcceptsRegistration () {
109+ // Arrange
110+ List <CircuitBreakerEvent > capturedEvents = new ArrayList <>();
111+
112+ // Act
113+ eventPublisher .onReset (capturedEvents ::add );
114+
115+ // Assert
116+ assertNotNull (eventPublisher );
117+ }
118+
119+ @ Test
120+ void givenMultipleEventConsumers_whenAllConsumersRegistered_thenAllRegistrationsAccepted () {
121+ // Arrange
122+ List <CircuitBreakerEvent > successEvents = new ArrayList <>();
123+ List <CircuitBreakerEvent > errorEvents = new ArrayList <>();
124+ List <CircuitBreakerEvent > stateTransitionEvents = new ArrayList <>();
125+
126+ // Act
127+ eventPublisher
128+ .onSuccess (successEvents ::add )
129+ .onError (errorEvents ::add )
130+ .onStateTransition (stateTransitionEvents ::add );
131+
132+ // Assert
133+ assertNotNull (eventPublisher );
134+ }
135+
136+ @ Test
137+ void givenNullConsumers_whenRegisteringEventConsumers_thenNoExceptionThrown () {
138+ // Arrange & Act & Assert
139+ assertDoesNotThrow (() -> {
140+ eventPublisher
141+ .onSuccess (null )
142+ .onError (null )
143+ .onIgnoredError (null );
144+ });
145+
146+ String result = circuitBreaker .executeSupplier (() -> "test" );
147+ assertEquals ("test" , result );
148+ }
149+
150+ @ Test
151+ void givenEventPublisher_whenChainingMultipleConsumerRegistrations_thenSamePublisherInstanceReturned () {
152+ // Arrange & Act
153+ CircuitBreaker .EventPublisher publisher = eventPublisher
154+ .onSuccess (event -> {
155+ })
156+ .onError (event -> {
157+ })
158+ .onIgnoredError (event -> {
159+ })
160+ .onCallNotPermitted (event -> {
161+ })
162+ .onFailureRateExceeded (event -> {
163+ })
164+ .onSlowCallRateExceeded (event -> {
165+ })
166+ .onStateTransition (event -> {
167+ })
168+ .onReset (event -> {
169+ });
170+
171+ // Assert
172+ assertSame (eventPublisher , publisher );
173+ }
174+
175+ @ Test
176+ void givenMultipleEventConsumers_whenDifferentEventsTriggered_thenCorrespondingEventsAreCaptured () {
177+ // Arrange
178+ List <String > eventTypes = new ArrayList <>();
179+
180+ eventPublisher .onSuccess (event -> eventTypes .add ("SUCCESS" ));
181+ eventPublisher .onError (event -> eventTypes .add ("ERROR" ));
182+ eventPublisher .onStateTransition (event -> eventTypes .add ("STATE_TRANSITION" ));
183+
184+ // Act
185+ circuitBreaker .executeSupplier (() -> "success" );
186+ try {
187+ circuitBreaker .executeSupplier (() -> {
188+ throw new RuntimeException ();
189+ });
190+ } catch (Exception ignored ) {
191+ }
192+
193+ // Assert
194+ assertTrue (eventTypes .contains ("SUCCESS" ));
195+ assertTrue (eventTypes .contains ("ERROR" ));
196+ }
197+
198+ @ Test
199+ void givenCircuitBreakerInstance_whenGettingEventPublisher_thenNotNullPublisherReturned () {
200+ // Arrange & Act
201+ CircuitBreaker .EventPublisher publisher = circuitBreaker .getEventPublisher ();
202+
203+ // Assert
204+ assertNotNull (publisher );
205+ assertSame (eventPublisher , publisher );
206+ }
207+
208+ @ Test
209+ void givenSuccessEventConsumer_whenMultipleSuccessfulCallsExecuted_thenAllSuccessEventsArePublished () {
210+ // Arrange
211+ List <CircuitBreakerEvent > events = new ArrayList <>();
212+ eventPublisher .onSuccess (events ::add );
213+
214+ // Act
215+ circuitBreaker .executeSupplier (() -> "first" );
216+ circuitBreaker .executeSupplier (() -> "second" );
217+ circuitBreaker .executeSupplier (() -> "third" );
218+
219+ // Assert
220+ assertEquals (3 , events .size ());
221+ events .forEach (event ->
222+ assertInstanceOf (CircuitBreakerOnSuccessEvent .class , event )
223+ );
224+ }
225+
226+ @ Test
227+ void givenCallNotPermittedConsumer_whenConsumerRegistered_thenPublisherAcceptsRegistration () {
228+ // Arrange
229+ List <CircuitBreakerEvent > capturedEvents = new ArrayList <>();
230+
231+ // Act
232+ eventPublisher .onCallNotPermitted (capturedEvents ::add );
233+
234+ // Assert
235+ assertNotNull (eventPublisher );
236+ }
237+
238+ @ Test
239+ void givenSlowCallRateExceededConsumer_whenConsumerRegistered_thenPublisherAcceptsRegistration () {
240+ // Arrange
241+ List <CircuitBreakerEvent > capturedEvents = new ArrayList <>();
242+
243+ // Act
244+ eventPublisher .onSlowCallRateExceeded (capturedEvents ::add );
245+
246+ // Assert
247+ assertNotNull (eventPublisher );
248+ }
249+
250+ @ Test
251+ void givenMultipleConsumersForSameEventType_whenEventPublished_thenAllConsumersReceiveEvent () {
252+ // Arrange
253+ List <String > consumerMessages = new ArrayList <>();
254+
255+ eventPublisher .onSuccess (event -> consumerMessages .add ("consumer1" ));
256+ eventPublisher .onSuccess (event -> consumerMessages .add ("consumer2" ));
257+
258+ // Act
259+ circuitBreaker .executeSupplier (() -> "test" );
260+
261+ // Assert
262+ assertEquals (2 , consumerMessages .size ());
263+ assertTrue (consumerMessages .contains ("consumer1" ));
264+ assertTrue (consumerMessages .contains ("consumer2" ));
265+ }
266+ }
0 commit comments