X Tutup
Skip to content

Commit 4aca4d1

Browse files
committed
Merge pull request python-telegram-bot#187 from python-telegram-bot/flaky-tests
Flaky tests
2 parents efd1050 + 2e6db13 commit 4aca4d1

27 files changed

+267
-426
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ install:
1111
- pip install -r requirements.txt
1212
- pip install -r requirements-dev.txt
1313
script:
14-
- nosetests --with-coverage --cover-package telegram/
14+
- nosetests -v --with-flaky --no-flaky-report --with-coverage --cover-package=telegram/
1515
- flake8 telegram
1616
- 'if [[ $TRAVIS_PYTHON_VERSION != 2.6 ]]; then pylint -E telegram --disable=no-name-in-module,import-error; fi'
1717
after_success:

requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ nose
33
pep257
44
pylint
55
unittest2
6+
flaky

telegram/bot.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -143,28 +143,38 @@ def decorator(self, *args, **kwargs):
143143
decorator
144144
"""
145145
url, data = func(self, *args, **kwargs)
146+
return Bot._post_message(url, data, kwargs)
147+
return decorator
146148

147-
if not data.get('chat_id'):
148-
raise TelegramError('Invalid chat_id')
149+
@staticmethod
150+
def _post_message(url, data, kwargs, timeout=None, network_delay=2.):
151+
"""Posts a message to the telegram servers.
149152
150-
if kwargs.get('reply_to_message_id'):
151-
reply_to_message_id = kwargs.get('reply_to_message_id')
152-
data['reply_to_message_id'] = reply_to_message_id
153+
Returns:
154+
telegram.Message
153155
154-
if kwargs.get('reply_markup'):
155-
reply_markup = kwargs.get('reply_markup')
156-
if isinstance(reply_markup, ReplyMarkup):
157-
data['reply_markup'] = reply_markup.to_json()
158-
else:
159-
data['reply_markup'] = reply_markup
156+
"""
157+
if not data.get('chat_id'):
158+
raise TelegramError('Invalid chat_id')
160159

161-
result = request.post(url, data)
160+
if kwargs.get('reply_to_message_id'):
161+
reply_to_message_id = kwargs.get('reply_to_message_id')
162+
data['reply_to_message_id'] = reply_to_message_id
162163

163-
if result is True:
164-
return result
164+
if kwargs.get('reply_markup'):
165+
reply_markup = kwargs.get('reply_markup')
166+
if isinstance(reply_markup, ReplyMarkup):
167+
data['reply_markup'] = reply_markup.to_json()
168+
else:
169+
data['reply_markup'] = reply_markup
165170

166-
return Message.de_json(result)
167-
return decorator
171+
result = request.post(url, data, timeout=timeout,
172+
network_delay=network_delay)
173+
174+
if result is True:
175+
return result
176+
177+
return Message.de_json(result)
168178

169179
@log
170180
def getMe(self):
@@ -431,12 +441,12 @@ def sendSticker(self,
431441
return url, data
432442

433443
@log
434-
@message
435444
def sendVideo(self,
436445
chat_id,
437446
video,
438447
duration=None,
439448
caption=None,
449+
timeout=None,
440450
**kwargs):
441451
"""Use this method to send video files, Telegram clients support mp4
442452
videos (other formats may be sent as telegram.Document).
@@ -453,6 +463,9 @@ def sendVideo(self,
453463
caption:
454464
Video caption (may also be used when resending videos by file_id).
455465
[Optional]
466+
timeout:
467+
float. If this value is specified, use it as the definitive timeout
468+
(in seconds) for urlopen() operations. [Optional]
456469
reply_to_message_id:
457470
If the message is a reply, ID of the original message. [Optional]
458471
reply_markup:
@@ -474,7 +487,7 @@ def sendVideo(self,
474487
if caption:
475488
data['caption'] = caption
476489

477-
return url, data
490+
return self._post_message(url, data, kwargs, timeout=timeout)
478491

479492
@log
480493
@message

telegram/photosize.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ def __init__(self,
5353
# Optionals
5454
self.file_size = int(kwargs.get('file_size', 0))
5555

56+
def __eq__(self, other):
57+
if not isinstance(other, self.__class__):
58+
return False
59+
return (self.file_id == other.file_id and
60+
self.width == other.width and
61+
self.height == other.height and
62+
self.file_size == other.file_size)
63+
5664
@staticmethod
5765
def de_json(data):
5866
"""

telegram/utils/request.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,27 +127,37 @@ def get(url):
127127
@_try_except_req
128128
def post(url,
129129
data,
130+
timeout=None,
130131
network_delay=2.):
131132
"""Request an URL.
132133
Args:
133134
url:
134135
The web location we want to retrieve.
135136
data:
136137
A dict of (str, unicode) key/value pairs.
138+
timeout:
139+
float. If this value is specified, use it as the definitive timeout (in
140+
seconds) for urlopen() operations. [Optional]
137141
network_delay:
138-
Additional timeout in seconds to allow the response from Telegram to
139-
take some time.
142+
float. If using the timeout specified in `data` (which is a timeout for
143+
the Telegram servers operation), then `network_delay` as an extra delay
144+
(in seconds) to compensate for network latency.
145+
default: 2 [Optional]
146+
147+
Notes:
148+
If neither `timeout` nor `data['timeout']` is specified. The underlying
149+
defaults are used.
140150
141151
Returns:
142152
A JSON object.
153+
143154
"""
155+
urlopen_kwargs = {}
144156

145-
# Add time to the timeout of urlopen to allow data to be transferred over
146-
# the network.
147-
if 'timeout' in data:
148-
timeout = data['timeout'] + network_delay
149-
else:
150-
timeout = None
157+
if timeout is not None:
158+
urlopen_kwargs['timeout'] = timeout
159+
elif 'timeout' in data:
160+
urlopen_kwargs['timeout'] = data['timeout'] + network_delay
151161

152162
if InputFile.is_inputfile(data):
153163
data = InputFile(data)
@@ -160,7 +170,7 @@ def post(url,
160170
data=data.encode(),
161171
headers={'Content-Type': 'application/json'})
162172

163-
result = urlopen(request, timeout=timeout).read()
173+
result = urlopen(request, **urlopen_kwargs).read()
164174
return _parse(result)
165175

166176

tests/base.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121

2222
import os
2323
import sys
24+
import signal
25+
import traceback
26+
27+
from nose.tools import make_decorator
28+
2429
sys.path.append('.')
2530

2631
import json
@@ -54,3 +59,32 @@ def is_dict(dictionary):
5459
return True
5560

5661
return False
62+
63+
64+
class TestTimedOut(AssertionError):
65+
66+
def __init__(self, time_limit, frame):
67+
super(TestTimedOut, self).__init__('time_limit={0}'.format(time_limit))
68+
self.time_limit = time_limit
69+
self.frame = frame
70+
71+
72+
def timeout(time_limit):
73+
def decorator(func):
74+
def timed_out(_signum, frame):
75+
raise TestTimedOut(time_limit, frame)
76+
77+
def newfunc(*args, **kwargs):
78+
orig_handler = signal.signal(signal.SIGALRM, timed_out)
79+
signal.alarm(time_limit)
80+
try:
81+
rc = func(*args, **kwargs)
82+
finally:
83+
signal.alarm(0)
84+
signal.signal(signal.SIGALRM, orig_handler)
85+
return rc
86+
87+
newfunc = make_decorator(func)(newfunc)
88+
return newfunc
89+
90+
return decorator

tests/test_audio.py

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
import os
2323
import unittest
2424
import sys
25+
from flaky import flaky
26+
2527
sys.path.append('.')
2628

2729
import telegram
28-
from tests.base import BaseTest
30+
from tests.base import BaseTest, timeout
2931

3032

3133
class AudioTest(BaseTest, unittest.TestCase):
@@ -50,10 +52,9 @@ def setUp(self):
5052
'file_size': self.file_size
5153
}
5254

55+
@flaky(3, 1)
56+
@timeout(10)
5357
def test_send_audio_required_args_only(self):
54-
"""Test telegram.Bot sendAudio method"""
55-
print('Testing bot.sendAudio - With required arguments only')
56-
5758
message = self._bot.sendAudio(self._chat_id,
5859
self.audio_file)
5960

@@ -67,10 +68,9 @@ def test_send_audio_required_args_only(self):
6768
self.assertEqual(audio.mime_type, self.mime_type)
6869
self.assertEqual(audio.file_size, self.file_size)
6970

71+
@flaky(3, 1)
72+
@timeout(10)
7073
def test_send_audio_all_args(self):
71-
"""Test telegram.Bot sendAudio method"""
72-
print('Testing bot.sendAudio - With all arguments')
73-
7474
message = self._bot.sendAudio(self._chat_id,
7575
self.audio_file,
7676
duration=self.duration,
@@ -89,10 +89,9 @@ def test_send_audio_all_args(self):
8989
self.assertEqual(audio.mime_type, self.mime_type)
9090
self.assertEqual(audio.file_size, self.file_size)
9191

92+
@flaky(3, 1)
93+
@timeout(10)
9294
def test_send_audio_mp3_file(self):
93-
"""Test telegram.Bot sendAudio method"""
94-
print('Testing bot.sendAudio - MP3 File')
95-
9695
message = self._bot.sendAudio(chat_id=self._chat_id,
9796
audio=self.audio_file,
9897
duration=self.duration,
@@ -109,10 +108,9 @@ def test_send_audio_mp3_file(self):
109108
self.assertEqual(audio.mime_type, self.mime_type)
110109
self.assertEqual(audio.file_size, self.file_size)
111110

111+
@flaky(3, 1)
112+
@timeout(10)
112113
def test_send_audio_mp3_file_custom_filename(self):
113-
"""Test telegram.Bot sendAudio method"""
114-
print('Testing bot.sendAudio - MP3 File with custom filename')
115-
116114
message = self._bot.sendAudio(chat_id=self._chat_id,
117115
audio=self.audio_file,
118116
duration=self.duration,
@@ -130,10 +128,9 @@ def test_send_audio_mp3_file_custom_filename(self):
130128
self.assertEqual(audio.mime_type, self.mime_type)
131129
self.assertEqual(audio.file_size, self.file_size)
132130

131+
@flaky(3, 1)
132+
@timeout(10)
133133
def test_send_audio_mp3_url_file(self):
134-
"""Test telegram.Bot sendAudio method"""
135-
print('Testing bot.sendAudio - MP3 File by URL')
136-
137134
message = self._bot.sendAudio(chat_id=self._chat_id,
138135
audio=self.audio_file_url,
139136
duration=self.duration,
@@ -150,10 +147,9 @@ def test_send_audio_mp3_url_file(self):
150147
self.assertEqual(audio.mime_type, self.mime_type)
151148
self.assertEqual(audio.file_size, self.file_size)
152149

150+
@flaky(3, 1)
151+
@timeout(10)
153152
def test_send_audio_resend(self):
154-
"""Test telegram.Bot sendAudio method"""
155-
print('Testing bot.sendAudio - Resend by file_id')
156-
157153
message = self._bot.sendAudio(chat_id=self._chat_id,
158154
audio=self.audio_file_id,
159155
duration=self.duration,
@@ -169,9 +165,6 @@ def test_send_audio_resend(self):
169165
self.assertEqual(audio.mime_type, self.mime_type)
170166

171167
def test_audio_de_json(self):
172-
"""Test Audio.de_json() method"""
173-
print('Testing Audio.de_json()')
174-
175168
audio = telegram.Audio.de_json(self.json_dict)
176169

177170
self.assertEqual(audio.file_id, self.audio_file_id)
@@ -182,17 +175,11 @@ def test_audio_de_json(self):
182175
self.assertEqual(audio.file_size, self.file_size)
183176

184177
def test_audio_to_json(self):
185-
"""Test Audio.to_json() method"""
186-
print('Testing Audio.to_json()')
187-
188178
audio = telegram.Audio.de_json(self.json_dict)
189179

190180
self.assertTrue(self.is_json(audio.to_json()))
191181

192182
def test_audio_to_dict(self):
193-
"""Test Audio.to_dict() method"""
194-
print('Testing Audio.to_dict()')
195-
196183
audio = telegram.Audio.de_json(self.json_dict)
197184

198185
self.assertTrue(self.is_dict(audio.to_dict()))
@@ -203,9 +190,9 @@ def test_audio_to_dict(self):
203190
self.assertEqual(audio['mime_type'], self.mime_type)
204191
self.assertEqual(audio['file_size'], self.file_size)
205192

193+
@flaky(3, 1)
194+
@timeout(10)
206195
def test_error_send_audio_empty_file(self):
207-
print('Testing bot.sendAudio - Null file')
208-
209196
json_dict = self.json_dict
210197

211198
del(json_dict['file_id'])
@@ -215,9 +202,9 @@ def test_error_send_audio_empty_file(self):
215202
lambda: self._bot.sendAudio(chat_id=self._chat_id,
216203
**json_dict))
217204

205+
@flaky(3, 1)
206+
@timeout(10)
218207
def test_error_send_audio_empty_file_id(self):
219-
print('Testing bot.sendAudio - Empty file_id')
220-
221208
json_dict = self.json_dict
222209

223210
del(json_dict['file_id'])
@@ -227,9 +214,9 @@ def test_error_send_audio_empty_file_id(self):
227214
lambda: self._bot.sendAudio(chat_id=self._chat_id,
228215
**json_dict))
229216

217+
@flaky(3, 1)
218+
@timeout(10)
230219
def test_error_audio_without_required_args(self):
231-
print('Testing bot.sendAudio - Without required arguments')
232-
233220
json_dict = self.json_dict
234221

235222
del(json_dict['file_id'])

0 commit comments

Comments
 (0)
X Tutup