1+ package dev .openfeature .sdk .hooks .logging ;
2+
3+ import static org .mockito .ArgumentMatchers .any ;
4+ import static org .mockito .ArgumentMatchers .anyString ;
5+ import static org .mockito .ArgumentMatchers .argThat ;
6+ import static org .mockito .ArgumentMatchers .contains ;
7+ import static org .mockito .Mockito .mock ;
8+ import static org .mockito .Mockito .never ;
9+ import static org .mockito .Mockito .verify ;
10+ import static org .mockito .Mockito .when ;
11+
12+ import dev .openfeature .sdk .ClientMetadata ;
13+ import dev .openfeature .sdk .ErrorCode ;
14+ import dev .openfeature .sdk .EvaluationContext ;
15+ import dev .openfeature .sdk .FlagEvaluationDetails ;
16+ import dev .openfeature .sdk .FlagValueType ;
17+ import dev .openfeature .sdk .HookContext ;
18+ import dev .openfeature .sdk .ImmutableContext ;
19+ import dev .openfeature .sdk .Metadata ;
20+ import dev .openfeature .sdk .exceptions .GeneralError ;
21+ import lombok .SneakyThrows ;
22+ import org .junit .jupiter .api .BeforeEach ;
23+ import org .junit .jupiter .api .Test ;
24+ import org .simplify4u .slf4jmock .LoggerMock ;
25+ import org .slf4j .Logger ;
26+ import org .slf4j .spi .LoggingEventBuilder ;
27+
28+ public class LoggingHookTest {
29+
30+ private static final String FLAG_KEY = "some-key" ;
31+ private static final String DEFAULT_VALUE = "default" ;
32+ private static final String DOMAIN = "some-domain" ;
33+ private static final String PROVIDER_NAME = "some-provider" ;
34+ private static final String REASON = "some-reason" ;
35+ private static final String VALUE = "some-value" ;
36+ private static final String VARIANT = "some-variant" ;
37+ private static final String ERROR_MESSAGE = "some fake error!" ;
38+ private static final ErrorCode ERROR_CODE = ErrorCode .GENERAL ;
39+
40+ private HookContext <Object > hookContext ;
41+ private LoggingEventBuilder mockBuilder ;
42+ private Logger logger ;
43+
44+ @ BeforeEach
45+ void each () {
46+
47+ // create a fake hook context
48+ hookContext = HookContext .builder ().flagKey (FLAG_KEY ).defaultValue (DEFAULT_VALUE )
49+ .clientMetadata (new ClientMetadata () {
50+ @ Override
51+ public String getDomain () {
52+ return DOMAIN ;
53+ }
54+ }).providerMetadata (new Metadata () {
55+ @ Override
56+ public String getName () {
57+ return PROVIDER_NAME ;
58+ }
59+ }).type (FlagValueType .BOOLEAN ).ctx (new ImmutableContext ()).build ();
60+
61+ // mock logging
62+ logger = mock (Logger .class );
63+ mockBuilder = mock (LoggingEventBuilder .class );
64+ when (mockBuilder .addKeyValue (anyString (), anyString ())).thenReturn (mockBuilder );
65+ when (logger .atInfo ()).thenReturn (mockBuilder );
66+ when (logger .atError ()).thenReturn (mockBuilder );
67+ LoggerMock .setMock (LoggingHook .class , logger );
68+ }
69+
70+ @ SneakyThrows
71+ @ Test
72+ void beforeLogsAllPropsExceptEvaluationContext () {
73+ LoggingHook hook = new LoggingHook ();
74+ hook .before (hookContext , null );
75+
76+ verify (logger ).atInfo ();
77+ verifyCommonProps (mockBuilder );
78+ verify (mockBuilder , never ()).addKeyValue (anyString (), any (EvaluationContext .class ));
79+ verify (mockBuilder ).log (argThat ((String s ) -> s .contains ("Before" )));
80+ }
81+
82+ @ SneakyThrows
83+ @ Test
84+ void beforeLogsAllPropsAndEvaluationContext () {
85+ LoggingHook hook = new LoggingHook (true );
86+ hook .before (hookContext , null );
87+
88+ verify (logger ).atInfo ();
89+ verifyCommonProps (mockBuilder );
90+ verify (mockBuilder ).addKeyValue (contains (LoggingHook .EVALUATION_CONTEXT_KEY ), any (EvaluationContext .class ));
91+ verify (mockBuilder ).log (argThat ((String s ) -> s .contains ("Before" )));
92+ }
93+
94+ @ SneakyThrows
95+ @ Test
96+ void afterLogsAllPropsExceptEvaluationContext () {
97+ LoggingHook hook = new LoggingHook ();
98+ FlagEvaluationDetails <Object > details = FlagEvaluationDetails .builder ().reason (REASON ).variant (VARIANT ).value (VALUE ).build ();
99+ hook .after (hookContext , details , null );
100+
101+ verify (logger ).atInfo ();
102+ verifyAfterProps (mockBuilder );
103+ verifyCommonProps (mockBuilder );
104+ verify (mockBuilder , never ()).addKeyValue (anyString (), any (EvaluationContext .class ));
105+ verify (mockBuilder ).log (argThat ((String s ) -> s .contains ("After" )));
106+ }
107+
108+ @ SneakyThrows
109+ @ Test
110+ void afterLogsAllPropsAndEvaluationContext () {
111+ LoggingHook hook = new LoggingHook (true );
112+ FlagEvaluationDetails <Object > details = FlagEvaluationDetails .builder ().reason (REASON ).variant (VARIANT ).value (VALUE ).build ();
113+ hook .after (hookContext , details , null );
114+
115+ verify (logger ).atInfo ();
116+ verifyAfterProps (mockBuilder );
117+ verifyCommonProps (mockBuilder );
118+ verify (mockBuilder ).addKeyValue (contains (LoggingHook .EVALUATION_CONTEXT_KEY ), any (EvaluationContext .class ));
119+ verify (mockBuilder ).log (argThat ((String s ) -> s .contains ("After" )));
120+ }
121+
122+ @ SneakyThrows
123+ @ Test
124+ void errorLogsAllPropsExceptEvaluationContext () {
125+ LoggingHook hook = new LoggingHook ();
126+ GeneralError error = new GeneralError (ERROR_MESSAGE );
127+ hook .error (hookContext , error , null );
128+
129+ verify (logger ).atError ();
130+ verifyCommonProps (mockBuilder );
131+ verifyErrorProps (mockBuilder );
132+ verify (mockBuilder , never ()).addKeyValue (anyString (), any (EvaluationContext .class ));
133+ verify (mockBuilder ).log (argThat ((String s ) -> s .contains ("Error" )), any (Exception .class ));
134+ }
135+
136+ @ SneakyThrows
137+ @ Test
138+ void errorLogsAllPropsAndEvaluationContext () {
139+ LoggingHook hook = new LoggingHook (true );
140+ GeneralError error = new GeneralError (ERROR_MESSAGE );
141+ hook .error (hookContext , error , null );
142+
143+ verify (logger ).atError ();
144+ verifyCommonProps (mockBuilder );
145+ verifyErrorProps (mockBuilder );
146+ verify (mockBuilder ).addKeyValue (contains (LoggingHook .EVALUATION_CONTEXT_KEY ), any (EvaluationContext .class ));
147+ verify (mockBuilder ).log (argThat ((String s ) -> s .contains ("Error" )), any (Exception .class ));
148+ }
149+
150+ private void verifyCommonProps (LoggingEventBuilder mockBuilder ) {
151+ verify (mockBuilder ).addKeyValue (LoggingHook .DOMAIN_KEY , DOMAIN );
152+ verify (mockBuilder ).addKeyValue (LoggingHook .FLAG_KEY_KEY , FLAG_KEY );
153+ verify (mockBuilder ).addKeyValue (LoggingHook .PROVIDER_NAME_KEY , PROVIDER_NAME );
154+ verify (mockBuilder ).addKeyValue (LoggingHook .DEFAULT_VALUE_KEY , DEFAULT_VALUE );
155+ }
156+
157+ private void verifyAfterProps (LoggingEventBuilder mockBuilder ) {
158+ verify (mockBuilder ).addKeyValue (LoggingHook .REASON_KEY , REASON );
159+ verify (mockBuilder ).addKeyValue (LoggingHook .VARIANT_KEY , VARIANT );
160+ verify (mockBuilder ).addKeyValue (LoggingHook .VALUE_KEY , VALUE );
161+ }
162+
163+ private void verifyErrorProps (LoggingEventBuilder mockBuilder ) {
164+ verify (mockBuilder ).addKeyValue (LoggingHook .ERROR_CODE_KEY , ERROR_CODE );
165+ verify (mockBuilder ).addKeyValue (LoggingHook .ERROR_MESSAGE_KEY , ERROR_MESSAGE );
166+ }
167+ }
0 commit comments