Merge branch 'offline-tests'

This commit is contained in:
Tobias Gruetzmacher 2017-10-15 15:08:09 +02:00
commit 5b5cf6ad48
18 changed files with 104 additions and 56 deletions

View file

@ -322,10 +322,10 @@ def get_tagged_scraper_name(scraperobj, limit=None, reasons=None):
return name + suffix return name + suffix
def main(): def main(args=None):
"""Parse options and execute commands.""" """Parse options and execute commands."""
try: try:
options = setup_options().parse_args() options = setup_options().parse_args(args=args)
options.basepath = os.path.expanduser(options.basepath) options.basepath = os.path.expanduser(options.basepath)
res = run(options) res = run(options)
except KeyboardInterrupt: except KeyboardInterrupt:

View file

@ -177,6 +177,7 @@ def getComics(options):
finish() finish()
finally: finally:
events.getHandler().end() events.getHandler().end()
events.clear_handlers()
return errors return errors

View file

@ -328,6 +328,7 @@ def getHandlerNames():
return sorted(_handler_classes.keys()) return sorted(_handler_classes.keys())
# FIXME: Hidden singleton :(
_handlers = [] _handlers = []
@ -338,6 +339,10 @@ def addHandler(name, basepath=None, baseurl=None, allowDownscale=False):
_handlers.append(_handler_classes[name](basepath, baseurl, allowDownscale)) _handlers.append(_handler_classes[name](basepath, baseurl, allowDownscale))
def clear_handlers():
del _handlers[:]
class MultiHandler(object): class MultiHandler(object):
"""Encapsulate a list of handlers.""" """Encapsulate a list of handlers."""

View file

@ -11,7 +11,7 @@ from ..helpers import bounceStarter
class Xkcd(_ParserScraper): class Xkcd(_ParserScraper):
name = 'xkcd' name = 'xkcd'
url = 'http://xkcd.com/' url = 'https://xkcd.com/'
starter = bounceStarter starter = bounceStarter
stripUrl = url + '%s/' stripUrl = url + '%s/'
firstStripUrl = stripUrl % '1' firstStripUrl = stripUrl % '1'

View file

@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2013-2014 Bastian Kleineidam
# Copyright (C) 2015-2017 Tobias Gruetzmacher
from __future__ import absolute_import, division, print_function
import os
import subprocess
basedir = os.path.dirname(__file__)
dosage_cmd = os.path.join(os.path.dirname(basedir), "dosage")
def run(cmd, verbosity=0, **kwargs):
"""Run command without error checking.
@return: command return code"""
if kwargs.get("shell"):
# for shell calls the command must be a string
cmd = " ".join(cmd)
return subprocess.call(cmd, **kwargs)
def run_checked(cmd, ret_ok=(0,), **kwargs):
"""Run command and raise OSError on error."""
retcode = run(cmd, **kwargs)
if retcode not in ret_ok:
msg = "Command `%s' returned non-zero exit status %d" % (cmd, retcode)
raise OSError(msg)
return retcode

52
tests/httpmocks.py Normal file
View file

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2017 Tobias Gruetzmacher
from __future__ import absolute_import, division, print_function
import gzip
import os.path
import re
try:
from functools import lru_cache
except ImportError:
from backports.functools_lru_cache import lru_cache
from responses import add, GET, POST
_basedir = os.path.dirname(__file__)
def _file(name):
return os.path.join(_basedir, 'responses', name)
@lru_cache()
def _content(name):
with gzip.open(_file(name + '.html.gz'), 'r') as f:
return f.read()
@lru_cache()
def _img():
with open(_file('empty.png'), 'rb') as f:
return f.read()
def xkcd():
add(GET, 'https://xkcd.com/', _content('xkcd-1899'))
for page in (302, 303, 1898, 1899):
add(GET, 'https://xkcd.com/%i/' % page, _content('xkcd-%i' % page))
add(GET, re.compile(r'https://imgs\.xkcd\.com/.*\.png'), _img(), content_type='image/png')
def bloomingfaeries():
add(GET, 'http://www.bloomingfaeries.com/', _content('bf-home'))
add(GET, 'http://www.bloomingfaeries.com/comic/public/bloomin-faeries-405/', _content('bf-405'))
add(GET, re.compile(r'http://www\.bloomingfaeries\.com/.*\.jpg'), _img(), content_type='image/jpeg')
def vote():
add(POST, 'http://gaecounter.appspot.com/count/', 'no')

Binary file not shown.

Binary file not shown.

BIN
tests/responses/empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,19 +1,28 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs
# Copyright (C) 2012-2014 Bastian Kleineidam # Copyright (C) 2012-2014 Bastian Kleineidam
# Copyright (C) 2015-2016 Tobias Gruetzmacher # Copyright (C) 2015-2017 Tobias Gruetzmacher
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import pytest import pytest
import sys import responses
from . import dosage_cmd, run_checked import dosagelib.cmd
import httpmocks
def run_with_options(options, cmd=dosage_cmd): def cmd(*options):
"""Run dosage with given options.""" """'Fake' run dosage with given options."""
run_checked([sys.executable, cmd, '--allow-multiple'] + options) return dosagelib.cmd.main(('--allow-multiple',) + options)
def cmd_ok(*options):
assert cmd(*options) == 0
def cmd_err(*options):
assert cmd(*options) == 1
class TestDosage(object): class TestDosage(object):
@ -21,38 +30,43 @@ class TestDosage(object):
def test_list_comics(self): def test_list_comics(self):
for option in ("-l", "--list", "--singlelist"): for option in ("-l", "--list", "--singlelist"):
run_with_options([option]) cmd_ok(option)
def test_display_version(self): def test_display_version(self):
run_with_options(["--version"]) cmd_ok("--version")
def test_display_help(self): def test_display_help(self):
for option in ("-h", "--help"): for option in ("-h", "--help"):
run_with_options([option]) with pytest.raises(SystemExit):
cmd(option)
def test_module_help(self): def test_module_help(self):
run_with_options(["-m", "xkcd"]) cmd_ok("-m", "xkcd")
def test_no_comics_specified(self): def test_no_comics_specified(self):
with pytest.raises(OSError): cmd_err()
run_with_options([])
def test_unknown_option(self): def test_unknown_option(self):
with pytest.raises(OSError): with pytest.raises(SystemExit):
run_with_options(['--imadoofus']) cmd('--imadoofus')
def test_multiple_comics_match(self): def test_multiple_comics_match(self):
with pytest.raises(OSError): cmd_err('Garfield')
run_with_options(['Garfield'])
@responses.activate
def test_fetch_html_and_rss_json(self, tmpdir): def test_fetch_html_and_rss_json(self, tmpdir):
run_with_options(["-n", "2", "-v", "-b", str(tmpdir), "-o", "html", httpmocks.xkcd()
"-o", "rss", "-o", "json", "xkcd"]) cmd_ok("-n", "2", "-v", "-b", str(tmpdir), "-o", "html", "-o", "rss",
"-o", "json", "xkcd")
@responses.activate
def test_fetch_html_and_rss_2(self, tmpdir): def test_fetch_html_and_rss_2(self, tmpdir):
run_with_options(["--numstrips", "2", "--baseurl", "bla", httpmocks.bloomingfaeries()
"--basepath", str(tmpdir), "--output", "rss", cmd_ok("--numstrips", "2", "--baseurl", "bla", "--basepath",
"--output", "html", "--adult", "BloomingFaeries"]) str(tmpdir), "--output", "rss", "--output", "html", "--adult",
"BloomingFaeries")
@responses.activate
def test_fetch_indexed(self, tmpdir): def test_fetch_indexed(self, tmpdir):
run_with_options(["-n", "2", "-v", "-b", str(tmpdir), "xkcd:303"]) httpmocks.xkcd()
cmd_ok("-n", "2", "-v", "-b", str(tmpdir), "xkcd:303")

View file

@ -1,11 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs
# Copyright (C) 2012-2014 Bastian Kleineidam # Copyright (C) 2012-2014 Bastian Kleineidam
# Copyright (C) 2015-2016 Tobias Gruetzmacher # Copyright (C) 2015-2017 Tobias Gruetzmacher
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import responses
from dosagelib import scraper from dosagelib import scraper
import httpmocks
class ATestScraper(scraper._BasicScraper): class ATestScraper(scraper._BasicScraper):
@ -14,6 +17,8 @@ class ATestScraper(scraper._BasicScraper):
class TestVote(object): class TestVote(object):
@responses.activate
def test_vote(self): def test_vote(self):
httpmocks.vote()
answer = ATestScraper('Test_Test').vote() answer = ATestScraper('Test_Test').vote()
assert answer in ('counted', 'no'), 'invalid answer %r' % answer assert answer in ('counted', 'no'), 'invalid answer %r' % answer

View file

@ -3,7 +3,7 @@ envlist = py27, py35, py36, flake8
[testenv] [testenv]
commands = commands =
{envbindir}/py.test --cov=dosage --cov=dosagelib --tb=short -n4 \ {envbindir}/py.test --cov=dosagelib --tb=short -n4 \
--cov-report=xml:{toxworkdir}/cov-{envname}.xml --cov-report=term \ --cov-report=xml:{toxworkdir}/cov-{envname}.xml --cov-report=term \
--junitxml={toxworkdir}/junit-{envname}.xml {posargs} --junitxml={toxworkdir}/junit-{envname}.xml {posargs}