def test_get_response_success(self):
        expected_response = {"foo": "bar"}

        endpoint = _TestEndpoint(expected_response)
        manager = machinery.EndpointBinder.BoundEndpointManager(
            machinery._EndpointRequestLifecycleManager(endpoint), endpoint
        )
        machinery.EndpointBinder(endpoint).create_bound_endpoint(manager, HttpRequest())

        # can't use mock.patch.dict here because it doesn't implement the api that the unpatcher expects
        conf = tasks.future_task_runner.app.conf
        old_val = conf["task_always_eager"]
        conf["task_always_eager"] = True

        cache.set(tasks.JOB_COUNT_CACHE_KEY, 0)

        try:
            resp = manager.get_response()
        finally:
            conf["task_always_eager"] = old_val

        self.assertEqual(resp, (http.HTTPStatus.OK, expected_response))
        self.assertTrue(cache.get(tasks.JOB_COUNT_CACHE_KEY) != 0)

        self.assertEqual("deferred task executed", _TestEndpoint.semaphore["status"])
        self.assertEqual(3, _TestEndpoint.semaphore["retry_count"])
        self.assertEqual(3, _TestEndpoint.semaphore["filtered_retry_count_1"])
        self.assertEqual(1, _TestEndpoint.semaphore["filtered_retry_count_2"])

        _TestEndpoint.semaphore = {
            "status": None,
            "retry_count": 0,
            "filtered_retry_count_1": 0,
            "filtered_retry_count_2": 0,
        }
    def test_force_synchronous_tasks(self):
        expected_response = {"foo": "bar"}
        endpoint = _TestEndpoint(expected_response)
        manager = machinery.EndpointBinder.BoundEndpointManager(
            machinery._EndpointRequestLifecycleManager(endpoint), endpoint
        )
        machinery.EndpointBinder(endpoint).create_bound_endpoint(manager, HttpRequest())

        conf = tasks.future_task_runner.app.conf
        old_val = conf["task_always_eager"]
        conf["task_always_eager"] = True

        cache.set(tasks.JOB_COUNT_CACHE_KEY, 0)

        with mock.patch(
            "django_declarative_apis.machinery.tasks.future_task_runner.apply_async"
        ) as mock_apply:
            mock_apply.side_effect = kombu.exceptions.OperationalError

            with self.settings(DECLARATIVE_ENDPOINT_TASKS_FORCE_SYNCHRONOUS=True):
                try:
                    manager.get_response()
                except kombu.exceptions.OperationalError:
                    self.fail("OperationalError should not have been triggered")
                finally:
                    conf["task_always_eager"] = old_val

        self.assertEqual(0, mock_apply.call_count)
        self.assertEqual("deferred task executed", _TestEndpoint.semaphore["status"])
def _bind_endpoint(endpoint_cls, request, url_field=None):
    endpoint = endpoint_cls()
    binder = machinery.EndpointBinder(endpoint_cls)
    return binder.create_bound_endpoint(
        machinery._EndpointRequestLifecycleManager(endpoint),
        request,
        url_field=url_field,
    )
    def test_init_without_consumer_attributes(self):
        class _TestEndpoint(machinery.BaseEndpointDefinition):
            @property
            def resource(self):
                return {}

        endpoint = _TestEndpoint()
        endpoint_binder = machinery.EndpointBinder(endpoint)
        self.assertEqual(endpoint_binder.consumer_attributes, [])
    def test_get_response_with_filtered_list(self):
        class _TestResource:
            def __init__(self, name, secret):
                self.name = name
                self.secret = secret

        class _QuerySet(list):
            pass

        data = _QuerySet(
            [_TestResource("foo", "bar"),
             _TestResource("bar", "baz")])

        filter_def = {
            _TestResource: {
                "name": filtering.ALWAYS,
                "secret": filtering.NEVER
            }
        }

        class _TestEndpoint(machinery.EndpointDefinition):
            @machinery.endpoint_resource(type=_TestResource, filter=filter_def)
            def resource(self):
                return data

            @property
            def response(self):
                return {"people": self.resource}

            def __call__(self):
                return self

        endpoint = _TestEndpoint()
        manager = machinery.EndpointBinder.BoundEndpointManager(
            machinery._EndpointRequestLifecycleManager(endpoint), endpoint)
        machinery.EndpointBinder(endpoint).create_bound_endpoint(
            manager, HttpRequest())

        status, resp = manager.get_response()
        self.assertEqual(status, http.HTTPStatus.OK)
        # make sure the list is in the expected order
        resp["people"].sort(key=lambda p: p["name"].lower())
        self.assertEqual(resp, {"people": [{"name": "bar"}, {"name": "foo"}]})
    def test_get_response_kombu_error_attempts_exceeded(self):
        expected_response = {"foo": "bar"}
        endpoint = _TestEndpoint(expected_response)
        manager = machinery.EndpointBinder.BoundEndpointManager(
            machinery._EndpointRequestLifecycleManager(endpoint), endpoint
        )
        machinery.EndpointBinder(endpoint).create_bound_endpoint(manager, HttpRequest())

        conf = tasks.future_task_runner.app.conf
        old_val = conf["task_always_eager"]
        conf["task_always_eager"] = True

        cache.set(tasks.JOB_COUNT_CACHE_KEY, 0)

        with mock.patch(
            "django_declarative_apis.machinery.tasks.future_task_runner.apply_async"
        ) as mock_apply:
            exceptions = iter(
                [
                    kombu.exceptions.OperationalError,
                    kombu.exceptions.OperationalError,
                    kombu.exceptions.OperationalError,
                ]
            )

            def _side_effect(*args, **kwargs):
                try:
                    raise next(exceptions)
                except StopIteration:
                    return future_task_runner.apply(*args, **kwargs)

            mock_apply.side_effect = _side_effect

            try:
                manager.get_response()
                self.fail("should have triggered a kombu.exceptions.OperationalError")
            except kombu.exceptions.OperationalError:
                pass
            finally:
                conf["task_always_eager"] = old_val

        self.assertIsNone(_TestEndpoint.semaphore["status"])
    def test_get_response_kombu_error_retried(self):
        expected_response = {"foo": "bar"}
        endpoint = _TestEndpoint(expected_response)
        manager = machinery.EndpointBinder.BoundEndpointManager(
            machinery._EndpointRequestLifecycleManager(endpoint), endpoint)
        machinery.EndpointBinder(endpoint).create_bound_endpoint(
            manager, HttpRequest())

        conf = tasks.future_task_runner.app.conf
        old_val = conf["task_always_eager"]
        conf["task_always_eager"] = True

        cache.set(tasks.JOB_COUNT_CACHE_KEY, 0)

        with mock.patch(
                "django_declarative_apis.machinery.tasks.future_task_runner.apply_async"
        ) as mock_apply:
            exceptions = iter([
                kombu.exceptions.OperationalError,
                kombu.exceptions.OperationalError
            ])

            def _side_effect(*args, **kwargs):
                try:
                    raise next(exceptions)
                except StopIteration:
                    return future_task_runner.apply(*args, **kwargs)

            mock_apply.side_effect = _side_effect

            try:
                resp = manager.get_response()
            finally:
                conf["task_always_eager"] = old_val

        self.assertEqual(resp, (http.HTTPStatus.OK, expected_response))
        self.assertTrue(cache.get(tasks.JOB_COUNT_CACHE_KEY) != 0)

        self.assertEqual("deferred task executed",
                         _TestEndpoint.semaphore["status"])