-
Notifications
You must be signed in to change notification settings - Fork 4
/
test_retry_session.py
122 lines (94 loc) · 3.69 KB
/
test_retry_session.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from __future__ import (
absolute_import, division, print_function, unicode_literals)
import logging
from collections import namedtuple
from contextlib import contextmanager
import requests
from stbt_rig import RetrySession
RetrySessionTestCtx = namedtuple(
"RetrySessionTestCtx", "http_mock session time")
@contextmanager
def retry_session_test_ctx():
import requests_mock
time_ = MockTime()
session = requests.Session()
adapter = requests_mock.Adapter()
session.mount('mock', adapter)
retrysession = RetrySession(10, session=session, _time=time_)
yield RetrySessionTestCtx(adapter, retrysession, time_)
def test_retrysession_happypath():
with retry_session_test_ctx() as ctx:
ctx.http_mock.register_uri('GET', '//test.com/path', text='resp')
with ctx.time.assert_duration(seconds=0):
assert ctx.session.get('mock://test.com/path').text == 'resp'
def test_retrysession_retry_after_500():
with retry_session_test_ctx() as ctx:
ctx.http_mock.register_uri(
'GET', '//test.com/path', [
{'text': 'bad', 'status_code': 500},
{'text': 'ok', 'status_code': 200},
])
with ctx.time.assert_duration(seconds=1):
assert ctx.session.get('mock://test.com/path').text == 'ok'
def test_retrysession_retry_after_202():
with retry_session_test_ctx() as ctx:
ctx.http_mock.register_uri(
'GET', '//test.com/path', [
{'text': 'retry', 'status_code': 202},
{'text': 'ok', 'status_code': 200},
])
with ctx.time.assert_duration(seconds=0):
assert ctx.session.get('mock://test.com/path').text == 'ok'
def test_retrysession_no_retry_after_400():
with retry_session_test_ctx() as ctx:
ctx.http_mock.register_uri(
'GET', '//test.com/path', [
{'text': 'bad', 'status_code': 400},
{'text': 'ok', 'status_code': 200},
])
with ctx.time.assert_duration(seconds=0):
resp = ctx.session.get('mock://test.com/path')
assert resp.text == 'bad'
assert resp.status_code == 400
def test_retrysession_timeout():
with retry_session_test_ctx() as ctx:
ctx.http_mock.register_uri(
'GET', '//test.com/path', text='bad', status_code=500)
with ctx.time.assert_duration(seconds=10):
try:
ctx.session.get('mock://test.com/path')
assert False, "GET should have thrown"
except requests.HTTPError as e:
assert e.response.text == 'bad'
assert e.response.status_code == 500
class MockTime(object):
def __init__(self, start_time=1500000000.):
self._time = start_time
self._functions = []
def time(self):
t = self._time
return t
def sleep(self, seconds):
logging.info("time.sleep(%s)", seconds)
while self._functions and self._functions[0][0] <= self._time + seconds:
_, fn = self._functions.pop(0)
fn()
self._time += seconds
def interrupt(self, exception):
def raise_exception():
raise exception
self.at(0, raise_exception)
def at(self, offset, function):
self._functions.append((self._time + offset, function))
self._functions.sort()
@contextmanager
def assert_duration(self, seconds):
start_time = self._time
yield self
assert self._time - start_time == seconds
@contextmanager
def patch(self):
from mock import patch
with patch("time.time", self.time), \
patch("time.sleep", self.sleep):
yield self