Skip to content

Commit 7de6efe

Browse files
committed
Initial test cases
1 parent f969124 commit 7de6efe

File tree

14 files changed

+334
-23
lines changed

14 files changed

+334
-23
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,8 @@ telegram.jpg
7777

7878
# Exclude .exrc file for Vim
7979
.exrc
80+
81+
# Userbot artifacts
82+
unknown_errors.txt
83+
*.session
84+
session*.txt

requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ beautifulsoup4
88
pytest
99
pytest-timeout
1010
wheel
11+
tgintegration

tests/bots.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,22 @@
2323
from platform import python_implementation
2424

2525
# Provide some public fallbacks so it's easy for contributors to run tests on their local machine
26-
FALLBACKS = {
26+
BOT_FALLBACKS = {
2727
'token': '133505823:AAHZFMHno3mzVLErU5b5jJvaeG--qUyLyG0',
2828
'payment_provider_token': '284685063:TEST:ZGJlMmQxZDI3ZTc3',
2929
'chat_id': '12173560',
3030
'group_id': '-49740850',
31-
'channel_id': '@pythontelegrambottests'
31+
'channel_id': '@pythontelegrambottests',
32+
'username': '@PythonTelegramBot'
33+
}
34+
35+
session_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'integration')
36+
37+
USERBOT_FALLBACKS = {
38+
'session_name': os.path.join(session_dir, 'userbot_account'),
39+
'api_id': 269163,
40+
'api_hash': '8daa79bc8d892299125b8d9b80f64976',
41+
'phone_number': '+491728656978'
3242
}
3343

3444

@@ -52,4 +62,8 @@ def get(name, fallback):
5262

5363

5464
def get_bot():
55-
return {k: get(k, v) for k, v in FALLBACKS.items()}
65+
return {k: get(k, v) for k, v in BOT_FALLBACKS.items()}
66+
67+
68+
def get_userbot():
69+
return {k: get(k, v) for k, v in USERBOT_FALLBACKS.items()}

tests/conftest.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
# along with this program. If not, see [http://www.gnu.org/licenses/].
1919
import os
2020
import sys
21+
import time
2122
from collections import defaultdict
2223
from queue import Queue
23-
from threading import Thread, Event
24+
from threading import Event, Thread
2425
from time import sleep
2526

2627
import pytest
@@ -81,28 +82,36 @@ def create_dp(bot):
8182

8283
@pytest.fixture(scope='session')
8384
def _dp(bot):
84-
for dp in create_dp(bot):
85-
yield dp
85+
for d in create_dp(bot):
86+
yield d
87+
88+
89+
# noinspection PyProtectedMember
90+
def reset_dispatcher(dp):
91+
print('reset dispatcher')
92+
while not dp.update_queue.empty():
93+
dp.update_queue.get(False)
94+
dp.chat_data = defaultdict(dict)
95+
dp.user_data = defaultdict(dict)
96+
dp.handlers = {}
97+
dp.groups = []
98+
dp.error_handlers = []
99+
dp.__stop_event = Event()
100+
dp.__exception_event = Event()
101+
dp.__async_queue = Queue()
102+
dp.__async_threads = set()
103+
if dp._Dispatcher__singleton_semaphore.acquire(blocking=0):
104+
Dispatcher._set_singleton(dp)
105+
time.sleep(2)
106+
yield dp
107+
# noinspection PyUnresolvedReferences
108+
Dispatcher._Dispatcher__singleton_semaphore.release()
86109

87110

88111
@pytest.fixture(scope='function')
89112
def dp(_dp):
90-
# Reset the dispatcher first
91-
while not _dp.update_queue.empty():
92-
_dp.update_queue.get(False)
93-
_dp.chat_data = defaultdict(dict)
94-
_dp.user_data = defaultdict(dict)
95-
_dp.handlers = {}
96-
_dp.groups = []
97-
_dp.error_handlers = []
98-
_dp.__stop_event = Event()
99-
_dp.__exception_event = Event()
100-
_dp.__async_queue = Queue()
101-
_dp.__async_threads = set()
102-
if _dp._Dispatcher__singleton_semaphore.acquire(blocking=0):
103-
Dispatcher._set_singleton(_dp)
104-
yield _dp
105-
Dispatcher._Dispatcher__singleton_semaphore.release()
113+
for d in reset_dispatcher(_dp):
114+
yield d
106115

107116

108117
def pytest_configure(config):

tests/data/animated_gif.mp4

168 KB
Binary file not shown.

tests/integration/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
USERBOT_SESSION_ENV_VAR = 'USERBOT_SESSION'

tests/integration/conftest.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import os
2+
import time
3+
4+
import pytest
5+
6+
from telegram.ext import Updater
7+
from tests.bots import get_userbot
8+
from tests.conftest import reset_dispatcher
9+
from tests.integration import USERBOT_SESSION_ENV_VAR
10+
from tgintegration import BotIntegrationClient, InteractionClient
11+
12+
# Parse a base64-encoded Pyrogram session from environment variables, decode it, and save it as a
13+
# regular session.
14+
session_encoded = os.environ.get(USERBOT_SESSION_ENV_VAR)
15+
16+
# Same module as this file
17+
output_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'userbot_account.session')
18+
19+
# If session does not exist, create it from environment variable value.
20+
if not os.path.exists(output_file):
21+
if session_encoded is not None:
22+
InteractionClient.create_session_from_export(session_encoded, output_file)
23+
24+
25+
@pytest.fixture(scope='module')
26+
def userbot_info():
27+
return get_userbot()
28+
29+
30+
@pytest.fixture(scope='module')
31+
def updater(bot_info):
32+
up = Updater(bot_info['token'])
33+
print("Starting to poll...", end=' ', flush=True)
34+
up.start_polling()
35+
time.sleep(2)
36+
print("listening.")
37+
yield up
38+
time.sleep(1)
39+
if up.running:
40+
up.stop()
41+
42+
43+
@pytest.fixture(scope='module')
44+
def client(userbot_info, bot):
45+
c = BotIntegrationClient(
46+
bot_under_test=bot.get_me().username,
47+
session_name=userbot_info['session_name'],
48+
api_id=int(userbot_info['api_id']),
49+
api_hash=userbot_info['api_hash'],
50+
phone_number=userbot_info['phone_number'],
51+
max_wait_response=15, # seconds
52+
min_wait_consecutive=None, # We do not neet to wait for more than one message
53+
raise_no_response=False, # We will check for `response.empty` instead
54+
global_action_delay=2.0 # Let's never cause flood timeouts, even if it takes longer
55+
)
56+
print("Initializing integration test client...", end=' ', flush=True)
57+
c.start(debug=True)
58+
time.sleep(1)
59+
print("done.")
60+
yield c
61+
c.stop()
62+
63+
64+
@pytest.fixture(scope='function')
65+
def dp(updater):
66+
for d in reset_dispatcher(updater.dispatcher):
67+
def error(bot, update, error):
68+
print(error) # TODO: this is not right
69+
70+
d.add_error_handler(error)
71+
yield d
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
Run this file with python3.5+ in order to log in to Pyrogram with a Telegram user account
3+
interactively, creating a Pyrogram "session" file (json) in the process.
4+
It will try to log into the provided account like every regular Telegram client does,
5+
and you will be prompted for the login code.
6+
7+
Once the session is generated, you will be able to run the integration tests.
8+
9+
The configuration can be found in tests/bots.py and may be set via environment variables:
10+
- API_ID=12345
11+
- API_HASH=abcdefghijklmnopqrstuvwxyz123456
12+
- PHONE_NUMBER=+49123456789
13+
14+
Read here about how to obtain the values for API_ID and API_HASH:
15+
https://docs.pyrogram.ml/start/ProjectSetup#api-keys
16+
17+
It is okay to use the provided defaults for API_ID and API_HASH, but you should use your own
18+
(or a spare) Telegram account's PHONE_NUMBER.
19+
20+
Feel free to contact @JosXa on Telegram if you encounter problems.
21+
"""
22+
import os
23+
import sys
24+
25+
from tests.bots import get_bot, get_userbot
26+
from tests.integration import USERBOT_SESSION_ENV_VAR
27+
28+
try:
29+
from tgintegration import InteractionClient
30+
except ImportError:
31+
print("You need to install the TgIntegration library to run tests:")
32+
print("$ pip install -r requirements-dev.txt")
33+
sys.exit(1)
34+
35+
output_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),
36+
'session_min_base64.txt')
37+
38+
if __name__ == '__main__':
39+
userbot_info = get_userbot()
40+
bot_info = get_bot()
41+
peer_username = bot_info['username']
42+
43+
# Create a TgIntegration client (based on Pyrogram)
44+
client = InteractionClient(
45+
session_name="my_account",
46+
api_id=userbot_info['api_id'],
47+
api_hash=userbot_info['api_hash']
48+
)
49+
print("Starting client...")
50+
client.start()
51+
52+
# Send an initial message to the bot to register it as a known peer
53+
print("Sending initial message to peer")
54+
try:
55+
client.send_message(peer_username, "Hi, I'll be your testing buddy for today.")
56+
except Exception as e:
57+
print("Could not contact {}. Please write a message to this peer manually and run the "
58+
"script again.\nException is: {}".format(peer_username, e))
59+
sys.exit(1)
60+
61+
# Export the minified and base64-encoded session to be used in environment variables
62+
b64_string = client.export_minimal_session_b64(
63+
output_file,
64+
include_peers=[peer_username]
65+
).strip()
66+
67+
print('Initialized successfully.\n\n'
68+
'Now please set the {} test environment variable '
69+
'to the following:\n{}'.format(USERBOT_SESSION_ENV_VAR, b64_string))
70+
print('\nThis value was also written to\n{}'.format(output_file))
71+
print("\nIf you're using PyCharm, copy the key to clipboard and set the "
72+
"{} environment variable here:".format(USERBOT_SESSION_ENV_VAR))
73+
print("Run| Edit Configurations| Defaults| Python tests| py.test")
74+
client.stop()

tests/integration/test_entities.py

Whitespace-only changes.

0 commit comments

Comments
 (0)