diff --git a/tests/test_event_builder.py b/tests/test_event_builder.py index 77b535e6..d708aafc 100644 --- a/tests/test_event_builder.py +++ b/tests/test_event_builder.py @@ -269,6 +269,134 @@ def test_create_conversion_event__with_event_tags(self): event_builder.EventBuilder.HTTP_VERB, event_builder.EventBuilder.HTTP_HEADERS) + def test_create_conversion_event__with_event_tags_revenue(self): + """ Test that create_conversion_event creates Event object with right + params when only revenue event tags are provided. """ + + expected_params = { + 'accountId': '12001', + 'projectId': '111001', + 'visitorId': 'test_user', + 'eventName': 'test_event', + 'eventEntityId': '111095', + 'eventMetrics': [{ + 'name': 'revenue', + 'value': 4200 + }], + 'eventFeatures': [{ + 'name': 'non-revenue', + 'type': 'custom', + 'value': 'abc', + 'shouldIndex': False, + }, { + 'name': 'revenue', + 'type': 'custom', + 'value': 4200, + 'shouldIndex': False, + }], + 'layerStates': [{ + 'layerId': '111182', + 'revision': '42', + 'decision': { + 'experimentId': '111127', + 'variationId': '111129', + 'isLayerHoldback': False + }, + 'actionTriggered': True, + } + ], + 'timestamp': 42123, + 'revision': '42', + 'isGlobalHoldback': False, + 'userFeatures': [{ + 'id': '111094', + 'name': 'test_attribute', + 'type': 'custom', + 'value': 'test_value', + 'shouldIndex': True + }], + 'clientEngine': 'python-sdk', + 'clientVersion': version.__version__ + } + with mock.patch('time.time', return_value=42.123), \ + mock.patch('optimizely.bucketer.Bucketer._generate_bucket_value', return_value=5042): + event_obj = self.event_builder.create_conversion_event( + 'test_event', 'test_user', {'test_attribute': 'test_value'}, {'revenue': 4200, 'non-revenue': 'abc'}, + [('111127', '111129')] + ) + + # Sort event features based on ID + event_obj.params['eventFeatures'] = sorted(event_obj.params['eventFeatures'], key=lambda x: x.get('name')) + self._validate_event_object(event_obj, + event_builder.EventBuilder.CONVERSION_ENDPOINT, + expected_params, + event_builder.EventBuilder.HTTP_VERB, + event_builder.EventBuilder.HTTP_HEADERS) + + def test_create_conversion_event__with_event_tags_numeric_value(self): + """ Test that create_conversion_event creates Event object with right + params when only numeric metric event tags are provided. """ + + expected_params = { + 'accountId': '12001', + 'projectId': '111001', + 'visitorId': 'test_user', + 'eventName': 'test_event', + 'eventEntityId': '111095', + 'eventMetrics': [{ + 'name': 'value', + 'value': 1.234 + }], + 'eventFeatures': [{ + 'name': 'non-revenue', + 'type': 'custom', + 'value': 'abc', + 'shouldIndex': False, + }, { + 'name': 'value', + 'type': 'custom', + 'value': 1.234, + 'shouldIndex': False, + }], + 'layerStates': [{ + 'layerId': '111182', + 'revision': '42', + 'decision': { + 'experimentId': '111127', + 'variationId': '111129', + 'isLayerHoldback': False + }, + 'actionTriggered': True, + } + ], + 'timestamp': 42123, + 'revision': '42', + 'isGlobalHoldback': False, + 'userFeatures': [{ + 'id': '111094', + 'name': 'test_attribute', + 'type': 'custom', + 'value': 'test_value', + 'shouldIndex': True + }], + 'clientEngine': 'python-sdk', + 'clientVersion': version.__version__ + } + with mock.patch('time.time', return_value=42.123), \ + mock.patch('optimizely.bucketer.Bucketer._generate_bucket_value', return_value=5042): + event_obj = self.event_builder.create_conversion_event( + 'test_event', 'test_user', {'test_attribute': 'test_value'}, {'value': 1.234, 'non-revenue': 'abc'}, + [('111127', '111129')] + ) + + # Sort event features based on ID + event_obj.params['eventFeatures'] = sorted(event_obj.params['eventFeatures'], key=lambda x: x.get('name')) + self._validate_event_object(event_obj, + event_builder.EventBuilder.CONVERSION_ENDPOINT, + expected_params, + event_builder.EventBuilder.HTTP_VERB, + event_builder.EventBuilder.HTTP_HEADERS) + def test_create_conversion_event__with_invalid_event_tags(self): """ Test that create_conversion_event creates Event object with right params when invalid event tags are provided. """ diff --git a/tests/test_optimizely.py b/tests/test_optimizely.py index 08a0933c..52044d39 100644 --- a/tests/test_optimizely.py +++ b/tests/test_optimizely.py @@ -448,6 +448,142 @@ def test_track__with_event_tags(self): self._validate_event_object(mock_dispatch_event.call_args[0][0], 'https://logx.optimizely.com/log/event', expected_params, 'POST', {'Content-Type': 'application/json'}) + def test_track__with_event_tags_revenue(self): + """ Test that track calls dispatch_event with right params when only revenue + event tags are provided only. """ + + with mock.patch('optimizely.decision_service.DecisionService.get_variation', + return_value=self.project_config.get_variation_from_id( + 'test_experiment', '111128' + )) as mock_get_variation, \ + mock.patch('time.time', return_value=42), \ + mock.patch('optimizely.event_dispatcher.EventDispatcher.dispatch_event') as mock_dispatch_event: + self.optimizely.track('test_event', 'test_user', attributes={'test_attribute': 'test_value'}, + event_tags={'revenue': 4200, 'non-revenue': 'abc'}) + + expected_params = { + 'visitorId': 'test_user', + 'clientVersion': version.__version__, + 'clientEngine': 'python-sdk', + 'revision': '42', + 'userFeatures': [{ + 'shouldIndex': True, + 'type': 'custom', + 'id': '111094', + 'value': 'test_value', + 'name': 'test_attribute' + }], + 'projectId': '111001', + 'isGlobalHoldback': False, + 'eventEntityId': '111095', + 'eventName': 'test_event', + 'eventFeatures': [{ + 'name': 'non-revenue', + 'type': 'custom', + 'value': 'abc', + 'shouldIndex': False, + }, { + 'name': 'revenue', + 'type': 'custom', + 'value': 4200, + 'shouldIndex': False, + }], + 'eventMetrics': [{ + 'name': 'revenue', + 'value': 4200 + }], + 'timestamp': 42000, + 'layerStates': [{ + 'revision': '42', + 'decision': { + 'variationId': '111128', + 'isLayerHoldback': False, + 'experimentId': '111127' + }, + 'actionTriggered': True, + 'layerId': '111182' + }], + 'accountId': '12001' + } + mock_get_variation.assert_called_once_with(self.project_config.get_experiment_from_key('test_experiment'), + 'test_user', {'test_attribute': 'test_value'}) + self.assertEqual(1, mock_dispatch_event.call_count) + + # Sort event features based on ID + mock_dispatch_event.call_args[0][0].params['eventFeatures'] = sorted( + mock_dispatch_event.call_args[0][0].params['eventFeatures'], key=lambda x: x.get('name') + ) + self._validate_event_object(mock_dispatch_event.call_args[0][0], 'https://logx.optimizely.com/log/event', + expected_params, 'POST', {'Content-Type': 'application/json'}) + + def test_track__with_event_tags_numeric_value(self): + """ Test that track calls dispatch_event with right params when only numeric metric + event tags are provided. """ + + with mock.patch('optimizely.decision_service.DecisionService.get_variation', + return_value=self.project_config.get_variation_from_id( + 'test_experiment', '111128' + )) as mock_get_variation, \ + mock.patch('time.time', return_value=42), \ + mock.patch('optimizely.event_dispatcher.EventDispatcher.dispatch_event') as mock_dispatch_event: + self.optimizely.track('test_event', 'test_user', attributes={'test_attribute': 'test_value'}, + event_tags={'value':1.234, 'non-revenue': 'abc'}) + + expected_params = { + 'visitorId': 'test_user', + 'clientVersion': version.__version__, + 'clientEngine': 'python-sdk', + 'revision': '42', + 'userFeatures': [{ + 'shouldIndex': True, + 'type': 'custom', + 'id': '111094', + 'value': 'test_value', + 'name': 'test_attribute' + }], + 'projectId': '111001', + 'isGlobalHoldback': False, + 'eventEntityId': '111095', + 'eventName': 'test_event', + 'eventFeatures': [{ + 'name': 'non-revenue', + 'type': 'custom', + 'value': 'abc', + 'shouldIndex': False, + }, { + 'name': 'value', + 'type': 'custom', + 'value': 1.234, + 'shouldIndex': False, + }], + 'eventMetrics': [{ + 'name': 'value', + 'value': 1.234 + }], + 'timestamp': 42000, + 'layerStates': [{ + 'revision': '42', + 'decision': { + 'variationId': '111128', + 'isLayerHoldback': False, + 'experimentId': '111127' + }, + 'actionTriggered': True, + 'layerId': '111182' + }], + 'accountId': '12001' + } + mock_get_variation.assert_called_once_with(self.project_config.get_experiment_from_key('test_experiment'), + 'test_user', {'test_attribute': 'test_value'}) + self.assertEqual(1, mock_dispatch_event.call_count) + + # Sort event features based on ID + mock_dispatch_event.call_args[0][0].params['eventFeatures'] = sorted( + mock_dispatch_event.call_args[0][0].params['eventFeatures'], key=lambda x: x.get('name') + ) + self._validate_event_object(mock_dispatch_event.call_args[0][0], 'https://logx.optimizely.com/log/event', + expected_params, 'POST', {'Content-Type': 'application/json'}) + def test_track__with_event_tags__forced_bucketing(self): """ Test that track calls dispatch_event with right params when event_value information is provided after a forced bucket. """