def test_fetch_artifact_request_with_retries(self): emitter_mock = Mock() config = DecisioningConfig("client123", "org999", artifact_location=ARTIFACT_URL, event_emitter=emitter_mock) with patch( "target_decisioning_engine.artifact_provider.BACKOFF_FACTOR", 0): self.provider = ArtifactProvider(config) self.assertEqual(self.provider.http_retry.backoff_factor, 0) request_spy = spy_decorator( urllib3.connectionpool.HTTPConnectionPool.urlopen) with patch.object(urllib3.connectionpool.HTTPConnectionPool, "urlopen", request_spy): self.provider.initialize() self.assertIsNone(self.provider.artifact) self.assertIsNone(self.provider.last_response_data) self.assertIsNone(self.provider.last_response_etag) self.assertTrue(self.provider.polling_timer.is_alive()) self.assertEqual(request_spy.mock.call_count, 11) self.assertEqual(emitter_mock.call_count, 1) self.assertEqual(emitter_mock.call_args[0][0], ARTIFACT_DOWNLOAD_FAILED) self.assertTrue( isinstance(emitter_mock.call_args[0][1].get("error"), MaxRetryError))
def initialize(self): """Initialize TargetClient""" if requires_decisioning_engine(self.config.get("decisioning_method")): try: request_location_hint_cookie( self, self.config.get("target_location_hint")) decisioning_config = DecisioningConfig( self.config.get("client"), self.config.get("organization_id"), polling_interval=self.config.get("polling_interval"), artifact_location=self.config.get("artifact_location"), artifact_payload=self.config.get("artifact_payload"), environment=self.config.get("environment"), cdn_environment=self.config.get("cdn_environment"), cdn_base_path=self.config.get("cdn_base_path"), send_notification_func=self.send_notifications, telemetry_enabled=self.config.get("telemetry_enabled"), event_emitter=self.event_emitter, maximum_wait_ready=self.config.get("maximum_wait_ready"), property_token=self.config.get("property_token")) self.decisioning_engine = TargetDecisioningEngine( decisioning_config) self.decisioning_engine.initialize() self.event_emitter(CLIENT_READY) except Exception as err: self.logger.error( "Unable to initialize TargetDecisioningEngine: \n {}". format(str(err))) else: # Should emit client_ready event after client gets returned by TargetClient.create timer = Timer(CLIENT_READY_DELAY, self.event_emitter, [CLIENT_READY]) timer.start()
def test_get_polling_interval_above_minimum(self): config = DecisioningConfig(None, None, polling_interval=350) self.provider = ArtifactProvider(config) with patch.object(self.provider.pool_manager, "request", return_value=HTTPResponse()): self.provider.initialize() self.assertEqual(self.provider.polling_interval, 350)
def test_determine_artifact_location_without_property(self): config = DecisioningConfig("MyClient", "12345@AdobeOrg", environment=ENVIRONMENT_DEV, cdn_environment=ENVIRONMENT_STAGE) artifact_location = determine_artifact_location(config) self.assertEqual( artifact_location, "https://assets.staging.adobetarget.com/MyClient/development/v1/rules.json" )
def test_get_polling_interval_not_numeric(self): config = DecisioningConfig(None, None, polling_interval="bad") self.provider = ArtifactProvider(config) with patch.object(self.provider.pool_manager, "request", return_value=HTTPResponse()): self.provider.initialize() self.assertEqual( self.provider.polling_interval, DecisioningEngineConstants.DEFAULT_POLLING_INTERVAL)
def test_get_polling_interval_below_minimum(self): config = DecisioningConfig(None, None, polling_interval=200) self.provider = ArtifactProvider(config) with patch.object(self.provider.pool_manager, "request", return_value=HTTPResponse()): self.provider.initialize() self.assertEqual( self.provider.polling_interval, DecisioningEngineConstants.MINIMUM_POLLING_INTERVAL)
def test_determine_artifact_location_with_property(self): config = DecisioningConfig( "MyClient", "12345@AdobeOrg", environment=ENVIRONMENT_DEV, cdn_environment=ENVIRONMENT_STAGE, property_token="693de2cd-ac92-d2c7-59fc-a3c0f2bce646") artifact_location = determine_artifact_location(config) self.assertEqual( artifact_location, "https://assets.staging.adobetarget.com/MyClient/development/v1/" + "693de2cd-ac92-d2c7-59fc-a3c0f2bce646/rules.json")
def create_decisioning_config(config_dict): """Converts dict representation of decisioning config to DecisioningConfig object""" return DecisioningConfig( config_dict.get("client"), config_dict.get("organizationId"), polling_interval=config_dict.get("pollingInterval"), artifact_location=config_dict.get("artifactLocation"), artifact_payload=config_dict.get("artifactPayload"), environment=config_dict.get("environment"), cdn_environment=config_dict.get("cdn_environment"), cdn_base_path=config_dict.get("cdnBasePath"), send_notification_func=config_dict.get("sendNotificationFunc"), telemetry_enabled=config_dict.get("telemetryEnabled"), event_emitter=config_dict.get("eventEmitter"), maximum_wait_ready=config_dict.get("maximumWaitReady"))
def test_polling_works(self): config = DecisioningConfig("client123", "org999", polling_interval=1, artifact_location=None) self.provider = ArtifactProvider(config) with patch.object(self.provider, "_get_polling_interval", return_value=1): with patch.object(self.provider.pool_manager, "request", return_value=HTTPResponse()) as mock_http_call: self.provider.initialize() time.sleep(5) self.assertGreater(mock_http_call.call_count, 3)
def test_artifact_location_from_config(self): config = DecisioningConfig("client123", "org999", polling_interval=350, artifact_location=ARTIFACT_URL) self.provider = ArtifactProvider(config) with patch.object(self.provider.pool_manager, "request", return_value=HTTPResponse()) as mock_http_call: self.provider.initialize() expected_args = ("GET", ARTIFACT_URL) self.assertEqual(mock_http_call.call_count, 1) self.assertEqual(mock_http_call.call_args[0], expected_args) self.assertEqual(mock_http_call.call_args[1].get("headers"), {}) self.assertEqual(self.provider.artifact_location, ARTIFACT_URL) self.assertTrue(self.provider.polling_timer.is_alive())
def test_determine_artifact_location_invalid_env(self): config = DecisioningConfig("MyClient", "12345@AdobeOrg", environment="bad") mock_logger = Mock() with patch("target_decisioning_engine.utils.logger", mock_logger): artifact_location = determine_artifact_location(config) self.assertEqual( artifact_location, "https://assets.adobetarget.com/MyClient/production/v1/rules.json" ) self.assertEqual(mock_logger.debug.call_count, 1) self.assertEqual( mock_logger.debug.call_args[0][0], "'bad' is not a valid target environment, defaulting to 'production'." )
def test_determine_artifact_location(self): config = DecisioningConfig("client123", "org999", polling_interval=350, artifact_location=None) self.provider = ArtifactProvider(config) with patch.object(self.provider.pool_manager, "request", return_value=HTTPResponse()) as mock_http_call: self.provider.initialize() constructed_url = "https://assets.adobetarget.com/client123/production/v1/rules.json" expected_args = ("GET", constructed_url) self.assertEqual(mock_http_call.call_count, 1) self.assertEqual(mock_http_call.call_args[0], expected_args) self.assertEqual(mock_http_call.call_args[1].get("headers"), {}) self.assertEqual(self.provider.artifact_location, constructed_url) self.assertTrue(self.provider.polling_timer.is_alive())
def setUp(self): self.headers = { "x-geo-latitude": 37.773972, "x-geo-longitude": -122.431297, "x-geo-country-code": "US", "x-geo-region-code": "CA", "x-geo-city": "SANFRANCISCO" } self.config = DecisioningConfig("myClient", "myOrgId") geo_values = { "x-geo-longitude": -122.4, "x-geo-latitude": 37.75, "x-geo-city": "SAN FRANCISCO", "x-geo-region-code": "CA", "x-geo-country-code": "US" } self.mock_geo_response = HTTPResponse(body=json.dumps(geo_values), status=OK)
def test_artifact_from_config(self): config = DecisioningConfig("client123", "org999", polling_interval=350, artifact_location=ARTIFACT_URL, artifact_payload={ "a": 1, "b": 2 }) self.provider = ArtifactProvider(config) with patch.object(self.provider.pool_manager, "request", return_value=HTTPResponse()) as mock_http_call: self.provider.initialize() mock_http_call.assert_not_called() self.assertEqual(self.provider.artifact_location, ARTIFACT_URL) self.assertEqual(self.provider.artifact, {"a": 1, "b": 2}) self.assertTrue(self.provider.polling_timer.is_alive())
def setUp(self): self.default_config = DecisioningConfig("client123", "org999", artifact_location=ARTIFACT_URL, event_emitter=Mock()) self.provider = None
def test_determine_artifact_location_filter_missing_parts(self): config = DecisioningConfig(None, None, environment=ENVIRONMENT_DEV) artifact_location = determine_artifact_location(config) self.assertEqual( artifact_location, "https://assets.adobetarget.com/development/v1/rules.json")
"web", "address": { "url": "http://local-target-test:8080/" }, "userAgent": "Mozilla/5.0 (Macintosh Intel Mac OS X 10.15 rv:73.0) Gecko/20100101 Firefox/73.0" }, "prefetch": { "mboxes": [{ "name": "mbox-something", "index": 1 }] } }) CONFIG = DecisioningConfig("clientId", "orgId", maximum_wait_ready=500) MOCK_ARTIFACT_RESPONSE = HTTPResponse(status=200, body=json.dumps(ARTIFACT_BLANK)) MOCK_ARTIFACT_RESPONSE_BAD = HTTPResponse(status=500) MOCK_ARTIFACT_RESPONSE_UNSUPPORTED_VERSION = HTTPResponse( status=200, body=json.dumps(ARTIFACT_UNSUPPORTED_VERSION)) class TestTargetDecisioningEngine(unittest.TestCase): def setUp(self): self.decisioning = None def tearDown(self): if self.decisioning: self.decisioning.stop_polling()