@@ -48,7 +48,7 @@ def test_configurations_disable_odp(self):
4848 mock_logger .reset_mock ()
4949
5050 # these call should be dropped gracefully with None
51- manager .identify_user (' user1' )
51+ manager .identify_user ({ 'fs_user_id' : ' user1'} )
5252
5353 manager .send_event ('t1' , 'a1' , {}, {})
5454 mock_logger .error .assert_called_once_with ('ODP is not enabled.' )
@@ -126,10 +126,11 @@ def test_identify_user_datafile_not_ready(self):
126126
127127 manager = OdpManager (False , OptimizelySegmentsCache , event_manager = event_manager , logger = mock_logger )
128128
129+ identifiers = {'fs_user_id' : 'user1' , 'email' : 'user@example.com' }
129130 with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
130- manager .identify_user ('user1' )
131+ manager .identify_user (identifiers )
131132
132- mock_identify_user .assert_called_once_with ('user1' )
133+ mock_identify_user .assert_called_once_with (identifiers )
133134 mock_logger .error .assert_not_called ()
134135
135136 def test_identify_user_odp_integrated (self ):
@@ -139,13 +140,14 @@ def test_identify_user_odp_integrated(self):
139140 manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
140141 manager .update_odp_config ('key1' , 'host1' , [])
141142
143+ identifiers = {'fs_user_id' : 'user1' , 'email' : 'user@example.com' }
142144 with mock .patch .object (event_manager , 'dispatch' ) as mock_dispatch_event :
143- manager .identify_user ('user1' )
145+ manager .identify_user (identifiers )
144146
145147 mock_dispatch_event .assert_called_once_with ({
146148 'type' : 'fullstack' ,
147149 'action' : 'identified' ,
148- 'identifiers' : {'fs_user_id' : 'user1' },
150+ 'identifiers' : {'fs_user_id' : 'user1' , 'email' : 'user@example.com' },
149151 'data' : {
150152 'idempotence_id' : mock .ANY ,
151153 'data_source_type' : 'sdk' ,
@@ -161,8 +163,9 @@ def test_identify_user_odp_not_integrated(self):
161163 manager = OdpManager (False , CustomCache (), event_manager = event_manager , logger = mock_logger )
162164 manager .update_odp_config (None , None , [])
163165
166+ identifiers = {'fs_user_id' : 'user1' , 'email' : 'user@example.com' }
164167 with mock .patch .object (event_manager , 'dispatch' ) as mock_dispatch_event :
165- manager .identify_user ('user1' )
168+ manager .identify_user (identifiers )
166169
167170 mock_dispatch_event .assert_not_called ()
168171 mock_logger .error .assert_not_called ()
@@ -175,13 +178,94 @@ def test_identify_user_odp_disabled(self):
175178 manager = OdpManager (False , OptimizelySegmentsCache , event_manager = event_manager , logger = mock_logger )
176179 manager .enabled = False
177180
181+ identifiers = {'fs_user_id' : 'user1' , 'email' : 'user@example.com' }
178182 with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
179- manager .identify_user ('user1' )
183+ manager .identify_user (identifiers )
180184
181185 mock_identify_user .assert_not_called ()
182186 mock_logger .error .assert_not_called ()
183187 mock_logger .debug .assert_called_with ('ODP identify event is not dispatched (ODP disabled).' )
184188
189+ def test_identify_user_single_identifier_skipped (self ):
190+ """Single identifier should NOT trigger an ODP identify event."""
191+ mock_logger = mock .MagicMock ()
192+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
193+
194+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
195+ manager .update_odp_config ('key1' , 'host1' , [])
196+
197+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
198+ manager .identify_user ({'fs_user_id' : 'user1' })
199+
200+ mock_identify_user .assert_not_called ()
201+ mock_logger .debug .assert_any_call ('ODP identify event is not dispatched (fewer than 2 valid identifiers).' )
202+
203+ def test_identify_user_multiple_identifiers_sent (self ):
204+ """Multiple identifiers should trigger an ODP identify event."""
205+ mock_logger = mock .MagicMock ()
206+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
207+
208+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
209+ manager .update_odp_config ('key1' , 'host1' , [])
210+
211+ identifiers = {'fs_user_id' : 'user1' , 'vuid' : 'vuid-abc' }
212+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
213+ manager .identify_user (identifiers )
214+
215+ mock_identify_user .assert_called_once_with (identifiers )
216+
217+ def test_identify_user_three_identifiers_sent (self ):
218+ """Three identifiers should trigger an ODP identify event with all identifiers."""
219+ mock_logger = mock .MagicMock ()
220+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
221+
222+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
223+ manager .update_odp_config ('key1' , 'host1' , [])
224+
225+ identifiers = {'fs_user_id' : 'user1' , 'vuid' : 'vuid-abc' , 'email' : 'user@example.com' }
226+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
227+ manager .identify_user (identifiers )
228+
229+ mock_identify_user .assert_called_once_with (identifiers )
230+
231+ def test_identify_user_null_empty_values_not_counted (self ):
232+ """Null and empty identifier values should not count toward the identifier total."""
233+ mock_logger = mock .MagicMock ()
234+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
235+
236+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
237+ manager .update_odp_config ('key1' , 'host1' , [])
238+
239+ # Two identifiers but one is empty - should not send
240+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
241+ manager .identify_user ({'fs_user_id' : 'user1' , 'email' : '' })
242+
243+ mock_identify_user .assert_not_called ()
244+ mock_logger .debug .assert_any_call ('ODP identify event is not dispatched (fewer than 2 valid identifiers).' )
245+
246+ mock_logger .reset_mock ()
247+
248+ # Two identifiers but one is None - should not send
249+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
250+ manager .identify_user ({'fs_user_id' : 'user1' , 'email' : None })
251+
252+ mock_identify_user .assert_not_called ()
253+ mock_logger .debug .assert_any_call ('ODP identify event is not dispatched (fewer than 2 valid identifiers).' )
254+
255+ def test_identify_user_zero_identifiers_skipped (self ):
256+ """Zero identifiers should NOT trigger an ODP identify event."""
257+ mock_logger = mock .MagicMock ()
258+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
259+
260+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
261+ manager .update_odp_config ('key1' , 'host1' , [])
262+
263+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
264+ manager .identify_user ({})
265+
266+ mock_identify_user .assert_not_called ()
267+ mock_logger .debug .assert_any_call ('ODP identify event is not dispatched (fewer than 2 valid identifiers).' )
268+
185269 def test_send_event_datafile_not_ready (self ):
186270 mock_logger = mock .MagicMock ()
187271 event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
0 commit comments