Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ quality:
test:
coverage run -m py.test -v .

test_novcr:
coverage run -m py.test -v . --vcr-record=none

coverage_report:
coverage report

Expand All @@ -16,7 +19,7 @@ coverages: coverage_report coverage_html

qa: quality test coverages

travis: quality test coverage_report
travis: quality test_novcr coverage_report

clean_docs:
$(MAKE) -C docs clean
Expand Down
19 changes: 19 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

import pytest

# This file lists files which should be ignored by pytest
Expand All @@ -24,3 +26,20 @@ def pytest_configure(config):
'markers',
'online: for tests that require online access. '
'Use --offline to skip them.')


@pytest.fixture(scope='module')
def vcr_cassette_dir(request):
# Override VCR.py cassette save location, to keep them out of code folders
parts = request.module.__name__.split('.')
if parts[0] == 'sopel':
# We know it's part of Sopel...
parts = parts[1:]
return os.path.join('test', 'vcr', *parts)


@pytest.fixture
def vcr_cassette_path(request, vcr_cassette_name):
# pytest-vcr 0.3.0 looks for this fixture name
# remove when killing off Python 3.3 support
return os.path.join(vcr_cassette_dir(request), vcr_cassette_name)
12 changes: 10 additions & 2 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
pytest<3.3; python_version == '3.3'
pytest>=4.6,<4.7; python_version != '3.3'
coveralls
flake8<3.6.0; python_version == '3.3'
flake8>=3.7.0,<3.8.0; python_version != '3.3'
flake8-coding
flake8-future-import<0.4.6
flake8-import-order; python_version > '3.3'
flake8-import-order<=1.18.1; python_version <= '3.3'
pytest<3.3; python_version == '3.3'
pytest>=4.6,<4.7; python_version != '3.3'
pytest-vcr==1.0.2; python_version != '3.3'
pytest-vcr==0.3.0; python_version == '3.3'
PyYAML<5.1; python_version == '3.3'
PyYAML<5.3; python_version == '3.4'
setuptools<40.0; python_version == '3.3'
sphinx
sphinxcontrib-autoprogram
vcrpy==2.1.1; python_version == '2.7'
vcrpy<1.12.0; python_version == '3.3'
vcrpy<2.1.0; python_version == '3.4'
vcrpy<3.0.0; python_version >= '3.5'
28 changes: 21 additions & 7 deletions sopel/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,9 +736,11 @@ class example(object):
:param bool user_help: whether this example should be included in
user-facing help output such as `.help command`
(optional; default ``False``; see below)
:param bool online: if ``True``, |pytest|_ will mark this
example as "online" (optional; default ``False``; see
below)
:param bool online: if ``True``, |pytest|_ will mark this example as
"online" (optional; default ``False``; see below)
:param bool vcr: if ``True``, this example's HTTP requests & responses will
be recorded for later reuse (optional; default ``False``;
see below)

.. |pytest| replace:: ``pytest``
.. _pytest: https://pypi.org/project/pytest/
Expand Down Expand Up @@ -766,13 +768,21 @@ class example(object):
can override this choice or include multiple examples by passing
``user_help=True`` to one or more ``example`` decorator(s).

Finally, passing ``online=True`` makes that particular example skippable if
Sopel's test suite is run in offline mode, which is mostly useful to make
life easier for other developers working on Sopel without Internet access.
Passing ``online=True`` makes that particular example skippable if Sopel's
test suite is run in offline mode, which is mostly useful to make life
easier for other developers working on Sopel without Internet access.

Finally, ``vcr=True`` records the example's HTTP requests and responses for
replaying during later test runs. It can be an alternative (or complement)
to ``online``, and is especially useful for testing plugin code that calls
on inconsistent or flaky remote APIs. The recorded "cassettes" of responses
can be committed alongside the code for use by CI services, etc. (See
`VCR.py <https://github.com/kevin1024/vcrpy>`_ & `pytest-vcr
<https://github.com/ktosiek/pytest-vcr>`_)
"""
def __init__(self, msg, result=None, privmsg=False, admin=False,
owner=False, repeat=1, re=False, ignore=None,
user_help=False, online=False):
user_help=False, online=False, vcr=False):
# Wrap result into a list for get_example_test
if isinstance(result, list):
self.result = result
Expand All @@ -787,6 +797,7 @@ def __init__(self, msg, result=None, privmsg=False, admin=False,
self.owner = owner
self.repeat = repeat
self.online = online
self.vcr = vcr

if isinstance(ignore, list):
self.ignore = ignore
Expand Down Expand Up @@ -820,6 +831,9 @@ def __call__(self, func):
if self.online:
test = pytest.mark.online(test)

if self.vcr:
test = pytest.mark.vcr(test)

sopel.test_tools.insert_into_module(
test, func.__module__, func.__name__, 'test_example'
)
Expand Down
4 changes: 2 additions & 2 deletions sopel/modules/currency.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ def exchange(bot, match):
@commands('cur', 'currency', 'exchange')
@example('.cur 100 usd in btc cad eur',
r'100\.0 USD is [\d\.]+ BTC, [\d\.]+ CAD, [\d\.]+ EUR',
re=True)
re=True, online=True)
@example('.cur 100 usd in btc cad eur can aux',
r'100\.0 USD is [\d\.]+ BTC, [\d\.]+ CAD, [\d\.]+ EUR, \(unsupported: CAN, AUX\)',
re=True)
re=True, online=True)
def exchange_cmd(bot, trigger):
if not trigger.group(2):
return bot.reply("No search term. Usage: {}cur 100 usd in btc cad eur"
Expand Down
3 changes: 3 additions & 0 deletions sopel/modules/isup.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ def isup_insecure(bot, trigger):


@module.commands('isup')
@module.example('.isup google.com',
'http://google.com looks fine to me.',
online=True, vcr=True)
def isup(bot, trigger):
"""Check if a website is up or not."""
handle_isup(bot, trigger, secure=True)
2 changes: 1 addition & 1 deletion sopel/modules/py.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def setup(bot):

@module.commands('py')
@module.output_prefix('[py] ')
@module.example('.py len([1,2,3])', '3', online=True)
@module.example('.py len([1,2,3])', '3', online=True, vcr=True)
def py(bot, trigger):
"""Evaluate a Python expression."""
if not trigger.group(2):
Expand Down
6 changes: 4 additions & 2 deletions sopel/modules/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ def duck_api(query):
'.duck site:grandorder.wiki chulainn alter',
r'https?:\/\/grandorder\.wiki\/C%C3%BA_Chulainn.*',
re=True,
online=True)
online=True,
vcr=True)
# the last example (in source line order) is what .help displays
@example(
'.duck sopel.chat irc bot',
r'https?:\/\/(sopel\.chat\/?|github\.com\/sopel-irc\/sopel)',
re=True,
online=True)
online=True,
vcr=True)
def duck(bot, trigger):
"""Queries DuckDuckGo for the specified input."""
query = trigger.group(2)
Expand Down
8 changes: 5 additions & 3 deletions sopel/modules/translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,13 @@ def tr(bot, trigger):
@commands('translate', 'tr')
@example('.tr :en :fr my dog',
'"mon chien" (en to fr, translate.google.com)',
online=True)
@example('.tr מחשב', '"computer" (iw to en, translate.google.com)', online=True)
online=True, vcr=True)
@example('.tr מחשב',
'"computer" (iw to en, translate.google.com)',
online=True, vcr=True)
@example('.tr mon chien',
'"my dog" (fr to en, translate.google.com)',
online=True)
online=True, vcr=True)
def tr2(bot, trigger):
"""Translates a phrase, with an optional language hint."""
command = trigger.group(2)
Expand Down
2 changes: 1 addition & 1 deletion sopel/modules/url.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def shutdown(bot):
@module.example(
'.title https://www.google.com',
'[ Google ] - www.google.com',
online=True)
online=True, vcr=True)
def title_command(bot, trigger):
"""
Show the title or URL information for the given URL, or the last URL seen
Expand Down
24 changes: 24 additions & 0 deletions test/vcr/modules/isup/test_example_isup_0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
interactions:
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
User-Agent: [python-requests/2.23.0]
method: HEAD
uri: http://google.com/
response:
body: {string: ''}
headers:
Cache-Control: ['public, max-age=2592000']
Content-Length: ['219']
Content-Type: [text/html; charset=UTF-8]
Date: ['Tue, 19 May 2020 22:12:25 GMT']
Expires: ['Thu, 18 Jun 2020 22:12:25 GMT']
Location: ['http://www.google.com/']
Server: [gws]
X-Frame-Options: [SAMEORIGIN]
X-XSS-Protection: ['0']
status: {code: 301, message: Moved Permanently}
version: 1
23 changes: 23 additions & 0 deletions test/vcr/modules/py/test_example_py_0.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
interactions:
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
User-Agent: [python-requests/2.23.0]
method: GET
uri: https://oblique.sopel.chat/py/len%28%5B1%2C2%2C3%5D%29
response:
body: {string: '3

'}
headers:
Cache-Control: [no-cache]
Content-Length: ['2']
Content-Type: [text/plain]
Date: ['Tue, 19 May 2020 22:12:26 GMT']
Server: [Google Frontend]
X-Cloud-Trace-Context: [ed0f69d3ecb92a108aa223368b6282b1;o=1]
status: {code: 200, message: OK}
version: 1
Loading