@@ -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', 'email' : 'user1@example.com' } )
5252
5353 manager .send_event ('t1' , 'a1' , {}, {})
5454 mock_logger .error .assert_called_once_with ('ODP is not enabled.' )
@@ -120,16 +120,68 @@ def test_fetch_qualified_segments__seg_cache_and_seg_mgr_are_none(self):
120120 mock_logger .error .assert_not_called ()
121121 mock_fetch_qualif_segments .assert_called_once_with ('fs_user_id' , 'user1' , [])
122122
123+ def test_identify_user_single_identifier_skipped (self ):
124+ """Single identifier should NOT dispatch an identify event."""
125+ mock_logger = mock .MagicMock ()
126+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
127+
128+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
129+ manager .update_odp_config ('key1' , 'host1' , [])
130+
131+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
132+ manager .identify_user ({'fs_user_id' : 'user1' })
133+
134+ mock_identify_user .assert_not_called ()
135+ mock_logger .debug .assert_any_call ('ODP identify event is not dispatched (only one identifier provided).' )
136+
137+ def test_identify_user_empty_values_not_counted (self ):
138+ """Identifiers with empty or null values should not count toward the minimum."""
139+ mock_logger = mock .MagicMock ()
140+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
141+
142+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
143+ manager .update_odp_config ('key1' , 'host1' , [])
144+
145+ with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
146+ manager .identify_user ({'fs_user_id' : 'user1' , 'email' : '' , 'vuid' : '' })
147+
148+ mock_identify_user .assert_not_called ()
149+ mock_logger .debug .assert_any_call ('ODP identify event is not dispatched (only one identifier provided).' )
150+
151+ def test_identify_user_multiple_identifiers_sent (self ):
152+ """Multiple valid identifiers should dispatch an identify event."""
153+ mock_logger = mock .MagicMock ()
154+ event_manager = OdpEventManager (mock_logger , OdpEventApiManager ())
155+
156+ manager = OdpManager (False , LRUCache (10 , 20 ), event_manager = event_manager , logger = mock_logger )
157+ manager .update_odp_config ('key1' , 'host1' , [])
158+
159+ with mock .patch .object (event_manager , 'dispatch' ) as mock_dispatch_event :
160+ manager .identify_user ({'fs_user_id' : 'user1' , 'email' : 'user1@example.com' })
161+
162+ mock_dispatch_event .assert_called_once_with ({
163+ 'type' : 'fullstack' ,
164+ 'action' : 'identified' ,
165+ 'identifiers' : {'fs_user_id' : 'user1' , 'email' : 'user1@example.com' },
166+ 'data' : {
167+ 'idempotence_id' : mock .ANY ,
168+ 'data_source_type' : 'sdk' ,
169+ 'data_source' : 'python-sdk' ,
170+ 'data_source_version' : version .__version__
171+ }})
172+ mock_logger .error .assert_not_called ()
173+
123174 def test_identify_user_datafile_not_ready (self ):
175+ """When datafile is not ready but ODP config allows, identifiers with 2+ valid entries should forward."""
124176 mock_logger = mock .MagicMock ()
125177 event_manager = OdpEventManager (OdpConfig (), mock_logger )
126178
127179 manager = OdpManager (False , OptimizelySegmentsCache , event_manager = event_manager , logger = mock_logger )
128180
129181 with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
130- manager .identify_user (' user1' )
182+ manager .identify_user ({ 'fs_user_id' : ' user1', 'email' : 'user1@example.com' } )
131183
132- mock_identify_user .assert_called_once_with (' user1' )
184+ mock_identify_user .assert_called_once_with ({ 'fs_user_id' : ' user1', 'email' : 'user1@example.com' } )
133185 mock_logger .error .assert_not_called ()
134186
135187 def test_identify_user_odp_integrated (self ):
@@ -140,12 +192,12 @@ def test_identify_user_odp_integrated(self):
140192 manager .update_odp_config ('key1' , 'host1' , [])
141193
142194 with mock .patch .object (event_manager , 'dispatch' ) as mock_dispatch_event :
143- manager .identify_user (' user1' )
195+ manager .identify_user ({ 'fs_user_id' : ' user1', 'vuid' : 'vuid123' } )
144196
145197 mock_dispatch_event .assert_called_once_with ({
146198 'type' : 'fullstack' ,
147199 'action' : 'identified' ,
148- 'identifiers' : {'fs_user_id' : 'user1' },
200+ 'identifiers' : {'fs_user_id' : 'user1' , 'vuid' : 'vuid123' },
149201 'data' : {
150202 'idempotence_id' : mock .ANY ,
151203 'data_source_type' : 'sdk' ,
@@ -162,7 +214,7 @@ def test_identify_user_odp_not_integrated(self):
162214 manager .update_odp_config (None , None , [])
163215
164216 with mock .patch .object (event_manager , 'dispatch' ) as mock_dispatch_event :
165- manager .identify_user (' user1' )
217+ manager .identify_user ({ 'fs_user_id' : ' user1', 'email' : 'user1@example.com' } )
166218
167219 mock_dispatch_event .assert_not_called ()
168220 mock_logger .error .assert_not_called ()
@@ -176,7 +228,7 @@ def test_identify_user_odp_disabled(self):
176228 manager .enabled = False
177229
178230 with mock .patch .object (event_manager , 'identify_user' ) as mock_identify_user :
179- manager .identify_user (' user1' )
231+ manager .identify_user ({ 'fs_user_id' : ' user1', 'email' : 'user1@example.com' } )
180232
181233 mock_identify_user .assert_not_called ()
182234 mock_logger .error .assert_not_called ()
0 commit comments