Skip to content

Commit

Permalink
Chat lifecycle test was added.
Browse files Browse the repository at this point in the history
  • Loading branch information
quasiyoke committed Jan 6, 2018
1 parent 9bd5c84 commit 03e4cfe
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 58 deletions.
87 changes: 45 additions & 42 deletions randtalkbot/stranger.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
LANGUAGES_MAX_LENGTH = 40
LOGGER = logging.getLogger('randtalkbot.stranger')


def _(string_instance):
return string_instance

Expand Down Expand Up @@ -121,47 +120,51 @@ async def _advertise(self):
.where(Stranger.looking_for_partner_from != None) \
.count()

if searching_for_partner_count > 1:
if StatsService.get_instance().get_stats().get_sex_ratio() >= 1:
message = _(
'The search is going on. {0} users are looking for partner -- change'
' your preferences (languages, partner\'s sex) using /setup command to talk'
' with them.\n'
'Chat *lacks females!* Send the link to your friends and earn {1} bonuses'
' for every invited female and {2} bonus for each male (the more bonuses'
' you have -- the faster partner\'s search will be):',
)
else:
message = _(
'The search is going on. {0} users are looking for partner -- change your'
' preferences (languages, partner\'s sex) using /setup command to talk'
' with them.\n'
'Chat *lacks males!* Send the link to your friends and earn {1} bonuses'
' for every invited male and {2} bonus for each female (the more bonuses'
' you have -- the faster partner\'s search will be):',
)
sender = self.get_sender()
try:
await sender.send_notification(
message,
searching_for_partner_count,
type(self).REWARD_BIG,
type(self).REWARD_SMALL,
disable_notification=True,
)
await sender.send_notification(
_(
'Do you want to talk with somebody, practice in foreign languages or you'
' just want to have some fun? Rand Talk will help you!'
' It\'s a bot matching you with a random stranger of desired sex'
' speaking on your language. {0}',
),
self.get_invitation_link(),
disable_notification=True,
disable_web_page_preview=True,
)
except TelegramError as err:
LOGGER.warning('Advertise. Can\'t notify the stranger. %s', err)
if searching_for_partner_count <= 1:
return

if StatsService.get_instance().get_stats().get_sex_ratio() >= 1:
message = _(
'The search is going on. {0} users are looking for partner -- change'
' your preferences (languages, partner\'s sex) using /setup command to talk'
' with them.\n'
'Chat *lacks females!* Send the link to your friends and earn {1} bonuses'
' for every invited female and {2} bonus for each male (the more bonuses'
' you have -- the faster partner\'s search will be):',
)
else:
message = _(
'The search is going on. {0} users are looking for partner -- change your'
' preferences (languages, partner\'s sex) using /setup command to talk'
' with them.\n'
'Chat *lacks males!* Send the link to your friends and earn {1} bonuses'
' for every invited male and {2} bonus for each female (the more bonuses'
' you have -- the faster partner\'s search will be):',
)

sender = self.get_sender()

try:
await sender.send_notification(
message,
searching_for_partner_count,
type(self).REWARD_BIG,
type(self).REWARD_SMALL,
disable_notification=True,
)
await sender.send_notification(
_(
'Do you want to talk with somebody, practice in foreign languages or you'
' just want to have some fun? Rand Talk will help you!'
' It\'s a bot matching you with a random stranger of desired sex'
' speaking on your language. {0}',
),
self.get_invitation_link(),
disable_notification=True,
disable_web_page_preview=True,
)
except TelegramError as err:
LOGGER.warning('Advertise. Can\'t notify the stranger. %s', err)

def advertise_later(self):
# pylint: disable=attribute-defined-outside-init
Expand Down
2 changes: 1 addition & 1 deletion telepot_testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from .aio import create_open, DelegatorBot
from .helpers import assert_sent_message, finalize, receive_message
from .helpers import assert_sent_message, finalize, receive_message, UPDATES_TIMEOUT
28 changes: 20 additions & 8 deletions telepot_testing/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import asyncio
import logging
from pprint import pformat

LOGGER = logging.getLogger('telepot_testing')
# pylint: disable=invalid-name
Expand All @@ -14,15 +15,20 @@
UPDATES_FUTURES = []
UPDATES_TIMEOUT = 1

async def assert_sent_message(chat_id, text):
await assert_sent_update({
async def assert_sent_message(chat_id, text, disable_notification=None):
expected_update = {
'chat': {
'id': chat_id,
},
'text': text,
})
}

if disable_notification is not None:
expected_update['disable_notification'] = disable_notification

await assert_sent_update(expected_update)

async def assert_sent_update(update):
async def assert_sent_update(expected_update):
async def get_sent_update():
try:
future = SENT_FUTURES[0]
Expand All @@ -41,7 +47,9 @@ async def get_sent_update():
await asyncio.wait_for(future, timeout=UPDATES_TIMEOUT)
except asyncio.TimeoutError:
SENT_FUTURES.remove(future)
raise AssertionError(f'No updates were sent while we did expect `{update}`')
raise AssertionError(
f'No updates were sent while we did expect `{expected_update_repr}`',
)
# pylint: disable=bare-except
except:
SENT_FUTURES.remove(future)
Expand All @@ -51,10 +59,14 @@ async def get_sent_update():
SENT_FUTURES.remove(future)
return future.result()

sent_update = await get_sent_update()
actual_update = await get_sent_update()
actual_update_repr = pformat(actual_update)
expected_update_repr = pformat(expected_update)

if sent_update != update:
raise AssertionError(f'Expected sent update `{sent_update}` to be equal `{update}`')
if actual_update != expected_update:
raise AssertionError(
f'Expected sent update `{actual_update_repr}` to be equal `{expected_update_repr}`',
)

async def finalize():
LOGGER.debug('Finalizing')
Expand Down
18 changes: 14 additions & 4 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import asyncio
import datetime
from functools import wraps
import logging
from asynctest.mock import patch, Mock
Expand All @@ -19,15 +20,24 @@
import telepot_testing
from telepot_testing import finalize as finalize_telepot

LOGGER = logging.getLogger('tests.helpers')
TIME_TOLERANCE = datetime.timedelta(seconds=.1)

def assert_db(db_dict):
def assert_model(model, model_dict):
def raise_assertion_error(key, actual_value, expected_value):
raise AssertionError(
f'Value of `{key}` is `{actual_value}` but should be `{expected_value}`',
)

for key, expected_value in model_dict.items():
actual_value = getattr(model, key)

if actual_value != expected_value:
raise AssertionError(
f'Value of `{key}` is `{actual_value}` but should be `{expected_value}`',
)
if isinstance(expected_value, datetime.datetime):
if abs(actual_value - expected_value) > TIME_TOLERANCE:
raise_assertion_error(key, actual_value, expected_value)
elif actual_value != expected_value:
raise_assertion_error(key, actual_value, expected_value)

strangers_dicts = db_dict.get('strangers')

Expand Down
105 changes: 105 additions & 0 deletions tests/test_chat_lifecycle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# RandTalkBot Bot matching you with a random person on Telegram.
# Copyright (C) 2018 quasiyoke
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import datetime
import logging
import asynctest
from asynctest.mock import patch, CoroutineMock
from telepot_testing import assert_sent_message, receive_message
from .helpers import assert_db, finalize, run, patch_telepot

LOGGER = logging.getLogger('tests.test_chat_lifecycle')
STRANGER1_2 = {
'id': 12,
'invitation': 'bar_invitation',
'languages': '["en"]',
'partner_sex': 'not_specified',
'sex': 'not_specified',
'telegram_id': 120,
}
STRANGER1_1 = {
'id': 11,
'invitation': 'foo_invitation',
'languages': '["en"]',
'partner_sex': 'not_specified',
'sex': 'not_specified',
'telegram_id': 110,
}
STRANGER2_1 = {
'id': 21,
'invitation': '21_invitation',
'languages': '["en"]',
'looking_for_partner_from': datetime.datetime(1970, 1, 1),
'partner_sex': 'female',
'sex': 'not_specified',
'telegram_id': 210,
}
TALK1 = {
'id': 1,
'partner1_id': STRANGER1_1['id'],
'partner1_sent': 0,
'partner2_id': STRANGER1_2['id'],
'partner2_sent': 1,
'searched_since': datetime.datetime(1970, 1, 1)
}

class TestChatLifecycle(asynctest.TestCase):
@patch_telepot
def setUp(self):
run(self, {
'strangers': [STRANGER1_1, STRANGER1_2, STRANGER2_1],
'talks': [],
})

def tearDown(self):
finalize(self)

@patch('randtalkbot.stranger.StatsService')
async def test_unsuccessful_search(self, stats_service_mock):
from randtalkbot.stranger import asyncio as asyncio_mock
stats_service_mock.get_instance \
.return_value \
.get_stats \
.return_value \
.get_sex_ratio \
.return_value = 0.9

with patch('randtalkbot.stranger.asyncio.sleep', CoroutineMock()):
receive_message(STRANGER1_1['telegram_id'], '/begin')
await assert_sent_message(
STRANGER1_1['telegram_id'],
'*Rand Talk:* Looking for a stranger for you 🤔',
)
assert_db({
'strangers': [
{
'id': STRANGER1_1['id'],
'looking_for_partner_from': datetime.datetime.utcnow()
},
],
})
LOGGER.debug('Check calling %s', asyncio_mock.sleep)
asyncio_mock.sleep.assert_called_once_with(30)

await assert_sent_message(
STRANGER1_1['telegram_id'],
'*Rand Talk:* The search is going on. 2 users are looking for partner — change your'
' preferences (languages, partner\'s sex) using /setup command to talk with'
' them.\n'
'Chat *lacks females!* Send the link to your friends and earn 3 bonuses for'
' every invited female and 1 bonus for each male (the more bonuses you'
' have → the faster partner\'s search will be):',
disable_notification=True,
)
await assert_sent_message(
STRANGER1_1['telegram_id'],
'*Rand Talk:* Do[\u2009](http://randtalk.ml/static/img/logo-125x125.png) you want'
' to talk with somebody, practice in foreign languages or you just'
' want to have some fun? Rand Talk will help you! It\'s a bot matching you'
' with a random stranger of desired sex speaking on your language. [Check it out!]'
'(https://telegram.me/RandTalkBot?start=eyJpIjoiZm9vX2ludml0YXRpb24ifQ==)',
disable_notification=True,
)
3 changes: 1 addition & 2 deletions tests/test_invites.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from randtalkbot.stranger import Stranger
from .helpers import assert_db, finalize, run, patch_telepot

LOGGER = logging.getLogger('test_invites')
LOGGER = logging.getLogger('tests.test_invites')
STRANGER1_2 = {
'id': 2,
'invitation': 'bar',
Expand Down Expand Up @@ -94,7 +94,6 @@ async def test_muting_bonuses(self):
STRANGER1_1_INVITER['telegram_id'],
'*Rand Talk:* Notifications about bonuses were muted for 1 hour 🤐',
)
LOGGER.debug('Its OK')
receive_message(STRANGER1_1['telegram_id'], 'Hello')
await assert_sent_message(STRANGER1_2['telegram_id'], 'Hello')
except Exception as err:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_stranger.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async def test_add_bonuses__muted(self):
self.assertEqual(self.stranger.bonus_count, 1001)
self.stranger._notify_about_bonuses.assert_not_called()

@patch('randtalkbot.stranger.asyncio', CoroutineMock())
@patch('randtalkbot.stranger.asyncio.sleep', CoroutineMock())
@patch('randtalkbot.stranger.StatsService')
async def test_advertise__people_are_searching_chat_lacks_males(self, stats_service_mock):
from randtalkbot.stranger import asyncio as asyncio_mock
Expand Down

0 comments on commit 03e4cfe

Please sign in to comment.