@@ -126,23 +126,32 @@ def test_seen_ids_are_persisted_to_cache(self):
126126 self .assertIn ('new-event-123' , cached )
127127
128128 def test_is_error_flag_for_all_event_types (self ):
129- """Exercise every mapped event type through the task and verify is_error matches the _ERROR suffix."""
130- self ._set_keycloak_events ([_make_keycloak_event (kc_type ) for kc_type in settings .KEYCLOAK_EVENT_MAP ])
129+ """Every mapped event type is submitted with the correct is_error flag."""
130+ # Hardcoded so the test catches regressions in the _ERROR suffix rule
131+ # (instead of re-deriving it the same way the production code does).
132+ expected_is_error = {
133+ 'LOGIN' : False ,
134+ 'LOGIN_ERROR' : True ,
135+ 'REGISTER' : False ,
136+ 'REGISTER_ERROR' : True ,
137+ 'LOGOUT' : False ,
138+ 'CODE_TO_TOKEN' : False ,
139+ 'CODE_TO_TOKEN_ERROR' : True ,
140+ 'INTROSPECT_TOKEN' : False ,
141+ 'REFRESH_TOKEN' : False ,
142+ }
143+ # If a new type is added to KEYCLOAK_EVENT_MAP, extend the table above.
144+ self .assertEqual (set (expected_is_error ), set (settings .KEYCLOAK_EVENT_MAP ))
145+
146+ self ._set_keycloak_events ([_make_keycloak_event (kc_type ) for kc_type in expected_is_error ])
131147
132148 poll_keycloak_events ()
133149
134- submitted_types = {
150+ submitted = {
135151 call .kwargs ['properties' ]['keycloak_event_type' ]: call .kwargs ['properties' ]['is_error' ]
136152 for call in self .mock_ph .capture .call_args_list
137153 }
138- for kc_type in settings .KEYCLOAK_EVENT_MAP :
139- self .assertIn (kc_type , submitted_types , f'{ kc_type } was not submitted' )
140- expected_error = kc_type .endswith ('_ERROR' )
141- self .assertEqual (
142- submitted_types [kc_type ],
143- expected_error ,
144- f'{ kc_type } : expected is_error={ expected_error } , got { submitted_types [kc_type ]} ' ,
145- )
154+ self .assertEqual (submitted , expected_is_error )
146155
147156 @override_settings (KEYCLOAK_EVENTS_PAGE_SIZE = 3 )
148157 def test_pagination_fetches_all_events (self ):
@@ -154,10 +163,10 @@ def test_pagination_fetches_all_events(self):
154163 self .assertEqual (mock_kc_client .request .call_count , 3 ) # pages: 3+3+1
155164
156165 def test_client_id_resolution (self ):
157- """clientId is taken from details. token_issued_for when present, else from the top-level clientId."""
166+ """clientId is attributed ( token_issued_for or top-level); keycloakCallerClientId is raw Keycloak clientId."""
158167 cases = [
159168 (
160- 'INTROSPECT_TOKEN uses details. token_issued_for' ,
169+ 'INTROSPECT_TOKEN: attributed to token_issued_for, caller stays stalwart ' ,
161170 _make_keycloak_event (
162171 'INTROSPECT_TOKEN' ,
163172 client_id = 'stalwart' ,
@@ -169,38 +178,30 @@ def test_client_id_resolution(self):
169178 },
170179 ),
171180 'desktop' ,
181+ 'stalwart' ,
172182 ),
173183 (
174- 'LOGIN has no details; top-level clientId wins' ,
184+ 'LOGIN has no details; top-level clientId wins for both fields ' ,
175185 _make_keycloak_event ('LOGIN' , client_id = 'desktop' ),
176186 'desktop' ,
177- ),
178- (
179- 'REFRESH_TOKEN details without token_issued_for; top-level clientId wins' ,
180- _make_keycloak_event (
181- 'REFRESH_TOKEN' ,
182- client_id = 'desktop' ,
183- details = {
184- 'token_id' : 'ofrtrt:fake' ,
185- 'grant_type' : 'refresh_token' ,
186- 'refresh_token_type' : 'Offline' ,
187- },
188- ),
189187 'desktop' ,
190188 ),
191189 (
192190 'no top-level clientId and no token_issued_for' ,
193191 _make_keycloak_event ('LOGIN' , include_client_id = False ),
194192 None ,
193+ None ,
195194 ),
196195 ]
197196
198- for label , event , expected_client_id in cases :
197+ for label , event , expected_client_id , expected_caller in cases :
199198 with self .subTest (case = label ):
200199 self .mock_ph .reset_mock ()
201200 cache .delete (settings .KEYCLOAK_SEEN_EVENTS_CACHE_KEY )
202201 self ._set_keycloak_events ([event ])
203202
204203 poll_keycloak_events ()
205204
206- self .assertEqual (self ._last_capture_properties ()['clientId' ], expected_client_id )
205+ props = self ._last_capture_properties ()
206+ self .assertEqual (props ['clientId' ], expected_client_id )
207+ self .assertEqual (props ['keycloakCallerClientId' ], expected_caller )
0 commit comments