Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Unit Testing a Decorated Function with max_time #54

Open
fxfitz opened this issue Jun 1, 2018 · 4 comments
Open

Question: Unit Testing a Decorated Function with max_time #54

fxfitz opened this issue Jun 1, 2018 · 4 comments

Comments

@fxfitz
Copy link

fxfitz commented Jun 1, 2018

I currently have a function that looks like the following:

@backoff.on_exception(
    backoff.expo,
    RuntimeError,
    max_time=30
)
def get_rules(url):
    response = requests.get(url)
    if not response.ok:
        msg = 'Unable to get latest rules: HTTP {} {}'.format(
            response.status_code,
            response.reason

        )
        raise RuntimeError(msg)

    return response.text

I'm having trouble when unit testing this since now it is retrying for 30 seconds.

What should I mock/monkeypatch so this won't retry for 30 seconds?

@bgreen-litl
Copy link
Member

For unit testing functions with requests calls in them, I recommend responses https://github.com/getsentry/responses

With backoff in particular, if I expect the call to fail, I usually mock time.sleep() to be a no-op.

However, I think that probably doesn't work with max_time, so this is a good question. I'd be willing to add a "best practice" regarding this to the backoff documentation once we figure out what that practice should be...

@fxfitz
Copy link
Author

fxfitz commented Jun 1, 2018

So I'm already using responses for this exact test, so I'm good on that front. :-)

I actually tried mocking time.sleep() just as it's done in the backoff tests, but I land up getting an OverflowError:

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.tox/py36/lib/python3.6/site-packages/backoff/_sync.py:109: in retry
    seconds = _next_wait(wait, jitter, elapsed, max_time_)
.tox/py36/lib/python3.6/site-packages/backoff/_common.py:38: in _next_wait
    seconds = jitter(value)
.tox/py36/lib/python3.6/site-packages/backoff/_jitter.py:28: in full_jitter
    return random.uniform(0, value)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <random.Random object at 0x7fa8b689cc18>, a = 0, b = 179769313486231590...5356329624224137216

    def uniform(self, a, b):
        "Get a random number in the range [a, b) or [a, b] depending on rounding."
>       return a + (b-a) * self.random()
E       OverflowError: int too large to convert to float

.tox/py36/lib/python3.6/random.py:369: OverflowError
----------------------------------------------------------------------- Captured log call -----------------------------------------------------------------------
_common.py                  75 ERROR    Backing off get_ruleset(...) for 0.2s (RuntimeError: Unable to get latest ruleset: HTTP 404 Not Found)
_common.py                  75 ERROR    Backing off get_ruleset(...) for 1.2s (RuntimeError: Unable to get latest ruleset: HTTP 404 Not Found)
_common.py                  75 ERROR    Backing off get_ruleset(...) for 1.4s (RuntimeError: Unable to get latest ruleset: HTTP 404 Not Found)
_common.py                  75 ERROR    Backing off get_ruleset(...) for 7.3s (RuntimeError: Unable to get latest ruleset: HTTP 404 Not Found)
_common.py                  75 ERROR    Backing off get_ruleset(...) for 6.5s (RuntimeError: Unable to get latest ruleset: HTTP 404 Not Found)

@fxfitz
Copy link
Author

fxfitz commented Jun 1, 2018

FWIW, I just switched to max_tries for now. I'll leave this open though for now.

@fxfitz fxfitz changed the title Question: Unit Testing a Decorated Function Question: Unit Testing a Decorated Function with max_time Jun 1, 2018
@mickey
Copy link

mickey commented Mar 31, 2019

A bit late to the party but for future reference I both tried monkey-patching sleep and timedelta.total_seconds without success.
I finally made it work with a lookup function:

def get_mysql_max_retry_time():
   return int(os.getenv("MYSQL_MAX_RETRY_TIME", "150"))


@backoff.on_exception(backoff.expo, pymysql.err.MySQLError,
                      max_time=get_mysql_max_retry_time, jitter=backoff.full_jitter)
def ping:()
  ...

So you could probably monkeypatch this function.
In my case, I'm using dotenv so I'm not monkeypatching but declared MYSQL_MAX_RETRY_TIME=0 in .env.test.
This works great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants