Example #1
0
def test_create_group_with_valid_symbols(client: BotIntegrationClient):
    client.send_message(text="test_create_group_with_valid_symbols",
                        chat_id=config('BOT_NAME'))

    group_name = create_group_command(client)
    assert group_is_existing(
        client, group_name), "Cannot find created group in the list"
Example #2
0
def test_delete_existing_group(client: BotIntegrationClient):
    client.send_message(text="test_delete_existing_group",
                        chat_id=config('BOT_NAME'))

    group_name = create_group_command(client)
    menu = enter_group(client, group_name)
    delete_group_command(client, group_name, menu)
Example #3
0
def test_create_group_abort(client: BotIntegrationClient):
    client.send_message(text="test_create_group_abort",
                        chat_id=config('BOT_NAME'))

    response = client.send_command_await("/create", num_expected=1)
    assert response.num_messages == 1
    assert response.full_text.startswith("Ok, send the name of the group")

    response = client.send_command_await("/cancel", num_expected=1)
    assert response.num_messages == 1
    assert response.full_text.startswith("Sure, what now?")
Example #4
0
def test_categories(client: BotIntegrationClient):
    # Responses implement __eq__
    assert (client.send_command_await("categories")
            == client.send_message_await(captions.CATEGORIES))

    cat = client.send_command_await("categories", num_expected=1)
    social = cat.inline_keyboards[0].press_button_await(pattern=r'.*Social')
    ilkb = social.inline_keyboards[0]
    assert ilkb.num_buttons > 3
    share_btn = ilkb.find_button(r'Share')
    assert 'Social' in share_btn.switch_inline_query
Example #5
0
def create_group_command(client: BotIntegrationClient,
                         generated_name: str = None):
    if not generated_name:
        generated_name = generate_name()

    client.send_command_await('/create', num_expected=1)
    response = client.send_message_await(generated_name)
    assert response.full_text.startswith('Saved'), \
        "Correctly saved responses start with 'Saved.'"

    return generated_name
def test_explore_button(client: BotIntegrationClient):
    res = client.send_command_await("/start", num_expected=3)
    btn = next(x for x in res.keyboard_buttons if 'explore' in x.lower())

    explore = client.send_message_await(btn)
    assert explore.num_messages == 1

    count = 10
    while "explored all the bots" not in explore.full_text:
        if count == 0:
            break  # ok
        explore = explore.inline_keyboards[0].press_button_await(
            pattern=r'.*🔄')  # emoji
        count -= 1
Example #7
0
def test_other(client: BotIntegrationClient):
    test = ["contributing", "rules", "examples"]

    for t in test:
        res = client.get_inline_bot_results(client.peer_id, t)
        assert res.find_results(title_pattern=re.compile(
            r'.*{}.*'.format(t), re.IGNORECASE)), "{} did not work".format(t)
def test_help(client: BotIntegrationClient):
    # Send /help and wait for one message
    res = client.send_command_await("/help", num_expected=1)

    # Make some assertions about the response
    assert not res.empty, "Bot did not respond to /help command"
    assert 'reliable and unbiased bot catalog' in res.full_text.lower()
    keyboard = res.inline_keyboards[0]
    assert len(keyboard.rows[0]) == 3  # 3 buttons in first row
    assert len(keyboard.rows[1]) == 1  # 1 button in second row

    # Click the inline button that says "Contributing"
    contributing = res.inline_keyboards[0].press_button_await(pattern=r'.*Contributing')
    assert not contributing.empty, 'Pressing "Contributing" button had no effect.'
    assert "to contribute to the botlist" in contributing.full_text.lower()

    # Click the inline button that says "Help"
    help_ = res.inline_keyboards[0].press_button_await(pattern=r'.*Help')
    assert not contributing.empty, 'Pressing "Help" button had no effect.'
    assert "first steps" in help_.full_text.lower()

    # Click the inline button that says "Examples"
    examples = res.inline_keyboards[0].press_button_await(pattern=r'.*Examples')
    assert not examples.empty, 'Pressing "Examples" button had no effect.'
    assert "examples for contributing to the botlist:" in examples.full_text.lower()
def test_commands(client: BotIntegrationClient):

    for c in client.command_list:
        print("Sending {} ({})".format(c.command, c.description))

        res = client.send_command_await(c.command)
        assert not res.empty
Example #10
0
def enter_group(client: BotIntegrationClient, name: str):
    response = client.send_command_await('/groups', num_expected=1)
    pattern = r'.*{} | .+ member(s)'.format(name)
    menu = response.inline_keyboards[0].press_button_await(pattern=pattern)

    assert not menu.empty, 'Pressing "group_name" button had no effect.'
    assert name.lower() in menu.full_text.lower()
    return menu
Example #11
0
def group_is_existing(client: BotIntegrationClient, group_name: str):
    response = client.send_command_await("/groups", num_expected=1)
    for row in response.inline_keyboards[0].rows:
        assert len(row) == 1, "Each row should be of length 1"
        if row[0].text.startswith(group_name):
            return True
    else:
        return False
def test_new(client: BotIntegrationClient):
    uname = '@test__bot'
    try:
        try:
            b = Bot.get(username=uname)
            b.delete_instance()
        except Bot.DoesNotExist:
            pass

        res = client.send_command_await("new", [uname])
        if client.get_me().id in settings.MODERATORS:
            assert 'is currently pending' in res.full_text.lower()
            assert res.inline_keyboards[0].find_button(r'.*Accept.*')
        else:
            assert re.search('you submitted.*for approval', res.full_text, re.IGNORECASE)
    finally:
        Bot.delete().where(Bot.username == uname)
Example #13
0
def test_search(client: BotIntegrationClient, bots):
    for username in bots:
        # First send the username in private chat to get target description of the bot
        res = client.send_message_await(username, num_expected=1)
        assert not res.empty, "Bot did not yield a response for username {}.".format(
            username)
        full_expected = res.full_text

        res = client.get_inline_bot_results(client.peer_id, username)
        results = res.find_results(title_pattern=re.compile(
            r'{}\b.*'.format(username), re.IGNORECASE))
        assert len(results) == 1, "Not exactly one result for {}".format(
            username)

        # Description of bot should be the same in inline query message and private message
        assert full_expected in results.pop().result.send_message.message, \
            "Message texts did not match."
Example #14
0
def client():
    integration_client = BotIntegrationClient(
        bot_under_test=config('BOT_NAME'),
        session_name='test_account',
        api_id=config('API_ID'),
        api_hash=config('API_HASH'),
        max_wait_response=20,
        min_wait_consecutive=20,
        global_action_delay=3)

    integration_client.start()
    integration_client.send_command(command='/cancel', bot=config('BOT_NAME'))

    try:
        yield integration_client
    except Exception:
        integration_client.send_command(command='/cancel',
                                        bot=config('BOT_NAME'))
    integration_client.stop()
Example #15
0
def rename_group_command(client: BotIntegrationClient, menu):
    new_name = generate_name()
    menu.inline_keyboards[0].press_button_await(pattern=r'.*Rename group',
                                                min_wait_consecutive=5)
    response = client.send_message_await(new_name, num_expected=2)

    assert response[0].text.startswith('Saved')
    assert response[1].text.startswith('Choose an action')
    assert group_is_existing(client, new_name)
    return new_name
Example #16
0
    def __init__(self, session_name, log_level=logging.INFO):
        self.purchase_balance = None
        self.withdrawal_balance = None
        self.diamonds = None

        self.menu = None  # type: ReplyKeyboard
        self.logger = logging.getLogger(self.__class__.__name__)
        self.logger.setLevel(log_level)

        self.client = BotIntegrationClient(session_name=session_name,
                                           bot_under_test='@DinoParkBot',
                                           max_wait_response=20,
                                           min_wait_consecutive=2.0,
                                           global_action_delay=1.0,
                                           config_file=os.path.join(
                                               examples_dir, 'config.ini'))
        self.client.start()

        self._update_keyboard()
        self.update_balance()
Example #17
0
def client():
    # Setup
    print('Initializing BotIntegrationClient')

    examples_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    c = BotIntegrationClient(
        session_name='my_account',
        bot_under_test='@BotListBot',  # We're going to test the @BotListBot
        max_wait_response=10,  # Wait a max of 10 seconds for responses, ...
        raise_no_response=
        False,  # ... then check for response.empty instead of raising
        min_wait_consecutive=
        2.0,  # Wait at least 2 seconds to collect more than one message
        global_action_delay=1.8,  # Space out all messages by 1.8 seconds
        workdir=examples_dir  # Load configuration from parent folder
    )

    print("Starting integration test client...")
    c.start()
    print("Client ready.")

    yield c  # py.test sugar to separate setup from teardown

    # Teardown
    c.stop()
Example #18
0
def client():
    # Setup
    print('Initializing BotController')

    examples_dir = Path(__file__).parent.parent

    c = BotIntegrationClient(
        session_name='tgintegration_examples',
        bot_under_test='@BotListBot',  # We're going to test the @BotListBot
        max_wait_response=10,  # Wait a max of 10 seconds for responses, ...
        raise_no_response=
        False,  # ... then check for response.empty instead of raising
        min_wait_consecutive=
        2.0,  # Wait at least 2 seconds to collect more than one message
        global_action_delay=1.8,  # Space out all messages by 1.8 seconds
        workdir=examples_dir,
        config_file=str(examples_dir / 'config.ini'))

    print("Starting integration test service...")
    c.start()
    print("Client ready.")

    yield c  # py.test sugar to separate setup from teardown

    # Teardown
    c.stop()
Example #19
0
def test_search(client: BotIntegrationClient, bots):
    for bot in bots:
        res = client.get_inline_bot_results(client.peer_id, bot.username)
        results = res.find_results(title_pattern=re.compile(
            r'{}\b.*'.format(bot.username), re.IGNORECASE))
        try:
            results.pop()  # pop first, make sure now it's empty
        except KeyError:
            print(results)
            raise KeyError("No result found for {}".format(bot.username))
        assert len(
            results
        ) == 0, "More than one article in inline query results for {}".format(
            bot.username)
Example #20
0
def test_add_members_to_existing_group(client: BotIntegrationClient):
    client.send_message(text="test_add_members_to_existing_group",
                        chat_id=config('BOT_NAME'))

    group_name = create_group_command(client)
    group_name = enter_group(client, group_name)
    button = group_name.inline_keyboards[0].press_button_await(
        pattern=r'.*Add members', min_wait_consecutive=5)

    assert not button.empty, 'Pressing "Add members" button had no effect.'
    assert button.full_text.startswith(
        'Ok, send'), "Adding users' message has been changed."

    user_name = generate_name()
    response = client.send_message_await(user_name, num_expected=1)
    assert response.full_text.startswith("Added")

    response = client.send_command_await("/done", num_expected=2)
    assert response[0].text.startswith('Saved new members')

    members = response[1].text.split('\n')[3:]
    members = [item.split()[1] for item in members]
    assert user_name in members, "User hasn't been added"
Example #21
0
    def setUp(self):
        """ Sets up the environment"""
        API_ID = os.environ.get("API_ID")
        API_HASH = os.environ.get("API_HASH")
        TEST_BOT_NAME = os.environ.get("TEST_BOT_NAME")
        if None in [API_HASH, API_ID, TEST_BOT_NAME]:
            print("API_ID, API_HASH, TEST_BOT_NAME not set")
            raise ValueError()

        self.TEST_BOT_NAME = TEST_BOT_NAME

        client = BotIntegrationClient(
            bot_under_test=TEST_BOT_NAME,
            session_name=
            './session/my_account',  # Arbitrary file path to the Pyrogram session file
            api_id=API_ID,  # See "Requirements" above, ...
            api_hash=API_HASH,  # alternatively use a `config.ini` file
            max_wait_response=15,  # Maximum timeout for bot responses
            min_wait_consecutive=
            2  # Minimum time to wait for consecutive messages
        )
        client.start()
        #client.clear_chat()
        self.client = client
def test_help(client: BotIntegrationClient):
    res = client.send_command_await("/help", num_expected=1)
    assert 'reliable and unbiased bot catalog' in res.full_text.lower()
    kb = res[0].reply_markup.inline_keyboard
    assert len(kb[0]) == 3
    assert len(kb[1]) == 1

    contributing = res.inline_keyboards[0].press_button_await(
        pattern=r'.*Contributing')
    assert "to contribute to the botlist" in contributing.full_text.lower()

    help_ = res.inline_keyboards[0].press_button_await(pattern=r'.*Help')
    assert "first steps" in help_.full_text.lower()

    examples = res.inline_keyboards[0].press_button_await(
        pattern=r'.*Examples')
    assert "Examples for contributing to the BotList:" in examples.full_text
Example #23
0
def client():
    # setup
    print('Initializing integration test client')

    c = BotIntegrationClient(bot_under_test=settings.BOT_UNDER_TEST,
                             max_wait_response=8,
                             min_wait_consecutive=1.5,
                             global_action_delay=1.5,
                             session_name=settings.TEST_USERBOT_SESSION,
                             api_id=settings.API_ID,
                             api_hash=settings.API_HASH,
                             phone_number=settings.TEST_USERBOT_PHONE)
    print("Starting client...")
    c.start()
    if c.peer_id in settings.MODERATORS:
        print("Restarting bot...")
        c.send_command_await("r", num_expected=2)  # restart bot
    # c.clear_chat()
    yield c
    # teardown
    c.stop()
Example #24
0
def test_explore_button(client: BotIntegrationClient):
    # Send /start to bot and wait for 3 messages
    start = client.send_command_await("/start", num_expected=3)

    # Click the "Explore" keyboard button
    explore = start.reply_keyboard.press_button_await(pattern=r'.*Explore')

    assert not explore.empty, 'Pressing the "Explore" button had no effect.'
    assert explore.inline_keyboards, 'The "Explore" message had no inline keyboard.'

    # Click the "Explore" inline keyboard button 10 times or until it says that
    # all bots have been explored
    count = 10
    while "explored all the bots" not in explore.full_text:
        if count == 0:
            break  # ok

        # Pressing an inline button also makes the BotController listen for edit events.
        explore = explore.inline_keyboards[0].press_button_await(index=2)
        assert not explore.empty, 'Pressing the "Explore" button had no effect.'
        count -= 1
def test_commands(client: BotIntegrationClient):
    # The BotController automatically loads the available commands and we test them all here
    for c in client.command_list:
        res = client.send_command_await(c.command)
        assert not res.empty, "Bot did not respond to command /{}.".format(
            c.command)
def test_start(client: BotIntegrationClient):
    # Send /start and wait for 3 messages
    res = client.send_command_await("/start", num_expected=3)
    assert res.num_messages == 3
    assert res[0].sticker  # First message is a sticker
Example #27
0
"""
Full version of the GitHub README.
"""

from tgintegration import BotIntegrationClient

print("Initializing service...")
# This example uses the configuration of `config.ini` (see examples/README)
client = BotIntegrationClient(
    bot_under_test='@BotListBot',
    session_name=
    'tgintegration_examples',  # Arbitrary file path to the Pyrogram session file
    max_wait_response=8,  # Maximum timeout for bot responses
    min_wait_consecutive=2,  # Minimum time to wait for consecutive messages
    raise_no_response=
    True  # Raise `InvalidResponseError` when no response received
)

print("Starting...")
client.start()

print("Clearing chat to start with a blank screen...")
client.clear_chat()

print(
    "Send the /start command to the bot_under_test and 'await' exactly three messages..."
)
response = client.send_command_await("start", num_expected=3)

assert response.num_messages == 3
print("Three messages received.")
Example #28
0
import os
import time
import traceback

from tgintegration import BotIntegrationClient
from tgintegration.response import Response
from typing import Dict

examples_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# This example uses the configuration of `config.ini` (see examples/README)
client = BotIntegrationClient(
    session_name='my_account',
    bot_under_test='@IdleTownBot',
    max_wait_response=15,  # Maximum time in seconds to wait for a response from the bot
    min_wait_consecutive=None,  # Do not wait for more than one message
    global_action_delay=2.3,  # The @IdleTownBot has a spam limit of about 1.9s
    workdir=examples_dir,  # Load configuration from parent folder
    config_file=os.path.join(examples_dir, 'config.ini')
)

client.load_config()
client.start()


def ascii_chars(text):
    # type: (str) -> str
    return ''.join(x for x in text if str.isalpha(x) or str.isdigit(x)).strip()


def get_buttons(response):
Example #29
0
def test_start(client: BotIntegrationClient):
    client.send_message(text="test_start", chat_id=config('BOT_NAME'))

    response = client.send_command_await("/start", num_expected=1)
    assert response.num_messages == 1
    assert response.full_text.startswith("Hello")
Example #30
0
class DinoParkGame:
    VALUE_PATTERN = re.compile(r'^.*?\s*(\w+): ([\d ]+).*$', re.MULTILINE)
    NUMBERS_ONLY_PATTERN = re.compile(r'\b(\d[\d ]+)\b')

    def __init__(self, session_name, log_level=logging.INFO):
        self.purchase_balance = None
        self.withdrawal_balance = None
        self.diamonds = None

        self.menu = None  # type: ReplyKeyboard
        self.logger = logging.getLogger(self.__class__.__name__)
        self.logger.setLevel(log_level)

        self.client = BotIntegrationClient(session_name=session_name,
                                           bot_under_test='@DinoParkBot',
                                           max_wait_response=20,
                                           min_wait_consecutive=2.0,
                                           global_action_delay=1.0,
                                           config_file=os.path.join(
                                               examples_dir, 'config.ini'))
        self.client.start()

        self._update_keyboard()
        self.update_balance()

    def _update_keyboard(self):
        start = self.client.send_command_await("start")
        self.menu = start.reply_keyboard

    def _extract_values(self, text):
        groups = self.VALUE_PATTERN.findall(text)
        try:
            return {g[0].lower(): str_to_int(g[1]) for g in groups}
        except KeyError:
            return {}

    def update_balance(self):
        balance = self.menu.press_button_await(r'.*Balance')
        values = self._extract_values(balance.full_text)

        self.purchase_balance = values['purchases']
        self.withdrawal_balance = values['withdrawals']
        self.diamonds = values['storehouse']

        self.logger.debug(
            "Balance updated: +{} for purchases, +{} for withdrawals, +{} diamonds."
            .format(self.purchase_balance, self.withdrawal_balance,
                    self.diamonds))

    def collect_diamonds(self):
        farm = self.menu.press_button_await(".*Farm")
        collected = farm.inline_keyboards[0].press_button_await(
            ".*Collect diamonds")

        num_collected = self._extract_values(collected.full_text).get(
            'collected', 0)
        self.diamonds += num_collected
        self.logger.info("{} diamonds collected.".format(
            num_collected if num_collected > 0 else 'No'))

    def sell_diamonds(self):
        market = self.menu.press_button_await(r'.*Marketplace')
        if not market.inline_keyboards:
            self.logger.debug("No selling available at the moment.")
            return
        sold_msg = market.inline_keyboards[0].press_button_await(
            r'Sell diamonds.*')

        values = self.VALUE_PATTERN.findall(sold_msg.full_text)
        sold = str_to_int(values[0][1])
        plus_purchase = str_to_int(values[1][1])
        plus_withdrawal = str_to_int(values[2][1])

        self.diamonds -= sold
        self.purchase_balance += plus_purchase
        self.withdrawal_balance += plus_withdrawal

        self.logger.info(
            "{} diamonds sold, +{} to purchase balance, +{} to withdrawal balance."
            .format(sold, plus_purchase, plus_withdrawal))

    def buy_dinosaurs(self):
        """
        Buy the best affordable dinosaurs
        """
        dinos = self.menu.press_button_await(r'.*Dinosaurs').inline_keyboards[
            0].press_button_await(r'.*Buy dinosaurs')

        # Build up a list of cost per dino
        dino_cost_sequence = []
        for msg in dinos.messages:
            # "Worth" in the message has no colon (:) before the number, therefore we use a numbers
            # only pattern
            values = self.NUMBERS_ONLY_PATTERN.findall(msg.caption)
            cost = str_to_int(values[0])
            dino_cost_sequence.append(cost)

        while True:
            try:
                can_afford_id = next(
                    x[0] for x in reversed(list(enumerate(dino_cost_sequence)))
                    if x[1] <= self.purchase_balance)
            except StopIteration:
                self.logger.debug("Can't afford any dinosaurs.")
                # Can not afford any
                break

            bought = dinos.inline_keyboards[can_afford_id].press_button_await(
                r'.*Buy')
            self.logger.info("Bought dinosaur: " + bought.full_text)

    def play_lucky_number(self):
        lucky_number = self.menu.press_button_await(
            r'.*Games').reply_keyboard.press_button_await(r'.*Lucky number')

        bet = lucky_number.reply_keyboard.press_button_await(
            r'.*Place your bet')

        if 'only place one bet per' in bet.full_text.lower():
            self.logger.debug("Already betted in this round")

            # Clean up
            self.client.delete_messages(
                self.client.peer_id,
                [bet.messages[0].message_id, bet.action_result.message_id])
            return
        self.client.send_message_await(str(random.randint(1, 30)))
        self.logger.debug("Bet placed.")