Beispiel #1
0
    def test_get_offers_server_side(self):
        expected_result = deepcopy(EXPECTED_PREFETCH_RESULT)
        expected_result["response"]["edgeHost"] = "mboxedge28.tt.omtrdc.net"
        expected_result["target_location_hint_cookie"] = {
            "name": "mboxEdgeCluster",
            "value": "28",
            "maxAge": 1860
        }
        expected_result["meta"] = {
            "decisioning_method": DecisioningMethod.SERVER_SIDE.value
        }

        get_offers_opts = {
            "request": PREFETCH_REQUEST,
            "session_id": "dummy_session"
        }

        client_opts = dict(CONFIG)
        client_opts["decisioning_method"] = DecisioningMethod.SERVER_SIDE.value

        with patch.object(DeliveryApi, "execute", return_value=create_delivery_response(DELIVERY_API_RESPONSE)):
            client = TargetClient.create(client_opts)
            result = client.get_offers(get_offers_opts)
            result_dict = to_dict(result)
            expect_to_match_object(result_dict, expected_result)
Beispiel #2
0
    def test_send_notifications_display_type(self):
        event_token = "B8C2FP2IuBgmeJcDfXHjGpNWHtnQtQrJfmRrQugEa2qCnQ9Y9OaLL2gsdrWQTvE54PwSz67rmXWmSnkXpSSS2Q=="
        options = [
            Option(content="<h1>it's firefox</h1>",
                   type=OptionType.HTML,
                   event_token=event_token)
        ]
        mbox = MboxResponse(options=options, metrics=[], name="browser-mbox")
        self.provider.add_notification(mbox)

        self.provider.send_notifications()

        time.sleep(1)
        self.assertEqual(self.mock_notify.call_count, 1)
        self.assertEqual(
            len(self.mock_notify.call_args[0][0]["request"].notifications), 1)
        received = to_dict(
            self.mock_notify.call_args[0][0]["request"].notifications[0])
        expected = {
            "id":
            "expect.any(String)",
            "impressionId":
            "expect.any(String)",
            "timestamp":
            "expect.any(Number)",
            "type":
            "display",
            "mbox": {
                "name": "browser-mbox"
            },
            "tokens": [
                "B8C2FP2IuBgmeJcDfXHjGpNWHtnQtQrJfmRrQugEa2qCnQ9Y9OaLL2gsdrWQTvE54PwSz67rmXWmSnkXpSSS2Q=="
            ]
        }
        expect_to_match_object(received, expected)
Beispiel #3
0
    def test_get_offers_on_device_decisioning_emits_notifications(self):
        get_offers_opts = {
            "request": EXECUTE_REQUEST,
            "session_id": "dummy_session"
        }

        client_opts = dict(CONFIG)
        client_opts["decisioning_method"] = DecisioningMethod.ON_DEVICE.value
        client_opts["target_location_hint"] = "28"

        # send_notifications call
        with patch.object(DeliveryApi, "execute", return_value=create_delivery_response({})) \
                as mock_delivery_api:

            with patch("target_decisioning_engine.artifact_provider.urllib3.PoolManager") as mock_artifact_provider:
                artifact_instance = mock_artifact_provider.return_value
                artifact_response = HTTPResponse(status=OK, body=json.dumps(ARTIFACT_AB_SIMPLE))
                artifact_instance.request.return_value = artifact_response

                client = TargetClient.create(client_opts)
                self.assertEqual(mock_artifact_provider.call_count, 1)

                result = client.get_offers(get_offers_opts)
                self.assertIsNotNone(result.get("response"))
                self.assertEqual(result.get("response").status, OK)
                self.assertIsNotNone(result.get("response").execute)

                time.sleep(1)  # notifications sent async
                self.assertEqual(mock_delivery_api.call_count, 1)
                notification_request = to_dict(mock_delivery_api.call_args[0][2])
                expect_to_match_object(notification_request, EXPECTED_NOTIFICATION_REQUEST)
Beispiel #4
0
    def test_send_notifications_no_duplicates(self):
        event_token = "yYWdmhDasVXGPWlpX1TRZDSAQdPpz2XBromX4n+pX9jf5r+rP39VCIaiiZlXOAYq"
        content = [{
            "type":
            "insertAfter",
            "selector":
            "HTML > BODY > DIV:nth-of-type(1) > H1:nth-of-type(1)",
            "cssSelector":
            "HTML > BODY > DIV:nth-of-type(1) > H1:nth-of-type(1)",
            "content":
            "<p id='action_insert_15882850825432970'>Better to remain silent and be thought a fool \
                    than to speak out and remove all doubt.</p>"
        }]
        options = [
            Option(content=content,
                   type=OptionType.ACTIONS,
                   event_token=event_token)
        ]
        metrics = [
            Metric(type=MetricType.CLICK,
                   event_token="/GMYvcjhUsR6WVqQElppUw==",
                   selector="#action_insert_15882853393943012")
        ]
        mbox = MboxResponse(options=options,
                            metrics=metrics,
                            name="target-global-mbox")
        self.provider.add_notification(mbox)
        self.provider.add_notification(mbox)  # duplicate

        self.provider.send_notifications()

        time.sleep(1)
        self.assertEqual(self.mock_notify.call_count, 1)
        self.assertEqual(
            len(self.mock_notify.call_args[0][0]["request"].notifications), 1)
        received = to_dict(
            self.mock_notify.call_args[0][0]["request"].notifications[0])
        expected = {
            "id":
            "expect.any(String)",
            "impressionId":
            "expect.any(String)",
            "timestamp":
            "expect.any(Number)",
            "type":
            "display",
            "mbox": {
                "name": "target-global-mbox"
            },
            "tokens": [
                "yYWdmhDasVXGPWlpX1TRZDSAQdPpz2XBromX4n+pX9jf5r+rP39VCIaiiZlXOAYq"
            ]
        }
        expect_to_match_object(received, expected)
 def trace_request(self, mode, request_type, mbox_request, context):
     """Sets request details on self.request
     :param mode: ("execute"|"prefetch") mode
     :param request_type: ("mbox"|"view"|"pageLoad") request type
     :param mbox_request: (delivery_api_client.Model.request_details.RequestDetails|
         delivery_api_client.Model.mbox_request.MboxRequest) request details
     :param context: (target_decisioning_engine.types.decisioning_context.DecisioningContext) decisioning context
     """
     self.request = {
         "pageURL": context.get("page", {}).get("url"),
         "host": context.get("page", {}).get("domain"),
         request_type: to_dict(mbox_request) if mbox_request else {}
     }
     self.request[request_type]["type"] = mode
Beispiel #6
0
    def process_rule(self, rule, context, request_type, request_detail, post_processors, tracer):
        """Uses json logic to evaluate request context against the rules and returns an MboxResponse
        :param rule: (target_decisioning_engine.types.decisioning_artifact.Rule) rule
        :param context: (target_decisioning_engine.types.decisioning_context.DecisioningContext) context
        :param request_type: ( "mbox"|"view"|"pageLoad") request type
        :param request_detail: (delivery_api_client.Model.request_details.RequestDetails |
            delivery_api_client.Model.mbox_request.MboxRequest) request details
        :param post_processors: (list<callable>) post-processors used to process an mbox if needed
        :param tracer: (target_decisioning_engine.trace_provider.RequestTracer) request tracer
        :return: (delivery_api_client.Model.mbox_response.MboxResponse)
        """
        rule_context = deepcopy(context)
        consequence = None
        page = rule_context.get("page")
        referring = rule_context.get("referring")

        if request_detail and request_detail.address:
            page = create_page_context(request_detail.address) or page
            referring = create_page_context(request_detail.address) or referring

        rule_context.update({
            "page": to_dict(page),
            "referring": to_dict(referring),
            "mbox": to_dict(create_mbox_context(request_detail)),
            "allocation": compute_allocation(self.client_id, rule.get("meta", {}).get(ACTIVITY_ID), self.visitor_id)
        })

        rule_satisfied = jsonLogic(rule.get("condition"), rule_context)
        tracer.trace_rule_evaluated(rule, rule_context, rule_satisfied)

        if rule_satisfied:
            consequence = create_mbox_response(deepcopy(rule.get("consequence")))
            consequence.index = request_detail.index if hasattr(request_detail, "index") else None

            for post_process_func in post_processors:
                consequence = post_process_func(rule, consequence, request_type, request_detail, tracer)
        return consequence
    def _fetch_artifact(self, artifact_url):
        """Fetch artifact from server"""
        self.perf_tool.time_start(TIMING_ARTIFACT_DOWNLOADED_TOTAL)
        headers = {}
        self.logger.debug("{} fetching artifact - {}".format(LOG_TAG, artifact_url))

        if self.last_response_etag:
            headers["If-None-Match"] = self.last_response_etag

        try:
            self.perf_tool.time_start(TIMING_ARTIFACT_DOWNLOADED_FETCH)
            res = self.pool_manager.request(HTTP_GET, artifact_url, headers=headers, retries=self.http_retry)
            self.perf_tool.time_end(TIMING_ARTIFACT_DOWNLOADED_FETCH)
            self.logger.debug("{} artifact received - status={}".format(LOG_TAG, res.status))

            if res.status == NOT_MODIFIED and self.last_response_data:
                return self.last_response_data

            if res.status == FORBIDDEN:
                raise Exception("Artifact request is not authorized. This is likely due to On-Device-Decisioning "
                                "being disabled in Admin settings.  Please enable and try again.")

            if res.status != OK:
                raise Exception("Non-200 status code response from artifact request: {}".format(res.status))

            self.perf_tool.time_start(TIMING_ARTIFACT_READ_JSON)
            response_data = json.loads(res.data)
            self.perf_tool.time_end(TIMING_ARTIFACT_READ_JSON)
            etag = res.headers.get("Etag")
            if etag:
                self.last_response_data = response_data
                self.last_response_etag = etag

            geo = create_or_update_geo_object(geo_data=res.headers)
            self._emit_new_artifact(response_data, to_dict(geo))

            self.perf_tool.time_end(TIMING_ARTIFACT_DOWNLOADED_TOTAL)
            return response_data
        except Exception as err:
            self.logger.error(MESSAGES.get("ARTIFACT_FETCH_ERROR")(str(err)))
            failure_event = {
                "artifact_location": artifact_url,
                "error": err
            }
            self.event_emitter(ARTIFACT_DOWNLOAD_FAILED, failure_event)
        return None
Beispiel #8
0
    def test_get_offers_valid_on_device_decisioning_response(self):
        get_offers_opts = {
            "request": PREFETCH_REQUEST,
            "session_id": "dummy_session"
        }

        client_opts = dict(CONFIG)
        client_opts["decisioning_method"] = DecisioningMethod.ON_DEVICE.value
        client_opts["target_location_hint"] = "28"

        with patch("target_decisioning_engine.artifact_provider.urllib3.PoolManager") as mock_artifact_provider:
            artifact_instance = mock_artifact_provider.return_value
            artifact_response = HTTPResponse(status=OK, body=json.dumps(ARTIFACT_AB_SIMPLE))
            artifact_instance.request.return_value = artifact_response

            with patch.object(DeliveryApi, "execute", return_value=create_delivery_response(LOCATION_HINT_RESPONSE)):
                client = TargetClient.create(client_opts)
                result = client.get_offers(get_offers_opts)
                result_dict = to_dict(result)
                expect_to_match_object(result_dict, EXPECTED_PREFETCH_RESULT)
    def __init__(self, config, target_options, artifact_trace):
        """
        :param config: (target_decisioning_engine.types.decisioning_config.DecisioningConfig) config
        :param target_options: (target_decisioning_engine.types.target_delivery_request.TargetDeliveryRequest) options
        :param artifact_trace: (dict) artifact trace
        """
        self.config = config
        self.target_options = target_options
        self.artifact_trace = artifact_trace
        self.client_code = config.client
        self.session_id = target_options.session_id
        self.request = target_options.request
        self.show_traces = self.request.trace is not None
        self.profile = None

        tnt_id_parts = self.request.id.tnt_id.split(".") if self.request.id and is_string(self.request.id.tnt_id) \
            else [None, None]
        tnt_id = tnt_id_parts[0]
        profile_location = tnt_id_parts[1] if len(tnt_id_parts) >= 2 else None

        visitor_id = to_dict(self.request.id)
        visitor_id["tntId"] = tnt_id
        visitor_id["profileLocation"] = profile_location
        self.profile = {"visitorId": visitor_id}
Beispiel #10
0
def validate_metrics(result_metrics, expected_metrics):
    """Validate metrics"""
    result_metrics = to_dict(result_metrics)
    for index, expected_metric in enumerate(expected_metrics):
        expect_to_match_object(result_metrics[index], expected_metric)