diff --git a/dosagelib/cmd.py b/dosagelib/cmd.py index 14d77098b..b835f0f7b 100644 --- a/dosagelib/cmd.py +++ b/dosagelib/cmd.py @@ -322,10 +322,10 @@ def get_tagged_scraper_name(scraperobj, limit=None, reasons=None): return name + suffix -def main(): +def main(args=None): """Parse options and execute commands.""" try: - options = setup_options().parse_args() + options = setup_options().parse_args(args=args) options.basepath = os.path.expanduser(options.basepath) res = run(options) except KeyboardInterrupt: diff --git a/dosagelib/director.py b/dosagelib/director.py index 9dd3cc898..3c144c461 100644 --- a/dosagelib/director.py +++ b/dosagelib/director.py @@ -177,6 +177,7 @@ def getComics(options): finish() finally: events.getHandler().end() + events.clear_handlers() return errors diff --git a/dosagelib/events.py b/dosagelib/events.py index cf611b37a..5374b88e0 100644 --- a/dosagelib/events.py +++ b/dosagelib/events.py @@ -328,6 +328,7 @@ def getHandlerNames(): return sorted(_handler_classes.keys()) +# FIXME: Hidden singleton :( _handlers = [] @@ -338,6 +339,10 @@ def addHandler(name, basepath=None, baseurl=None, allowDownscale=False): _handlers.append(_handler_classes[name](basepath, baseurl, allowDownscale)) +def clear_handlers(): + del _handlers[:] + + class MultiHandler(object): """Encapsulate a list of handlers.""" diff --git a/dosagelib/plugins/x.py b/dosagelib/plugins/x.py index 4e8faf22d..df46e30d5 100644 --- a/dosagelib/plugins/x.py +++ b/dosagelib/plugins/x.py @@ -11,7 +11,7 @@ from ..helpers import bounceStarter class Xkcd(_ParserScraper): name = 'xkcd' - url = 'http://xkcd.com/' + url = 'https://xkcd.com/' starter = bounceStarter stripUrl = url + '%s/' firstStripUrl = stripUrl % '1' diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 4b02005d9..000000000 --- a/tests/__init__.py +++ /dev/null @@ -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 diff --git a/tests/httpmocks.py b/tests/httpmocks.py new file mode 100644 index 000000000..e91c82a03 --- /dev/null +++ b/tests/httpmocks.py @@ -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') diff --git a/tests/test_comics.py b/tests/modules/check_comics.py similarity index 100% rename from tests/test_comics.py rename to tests/modules/check_comics.py diff --git a/tests/conftest.py b/tests/modules/conftest.py similarity index 100% rename from tests/conftest.py rename to tests/modules/conftest.py diff --git a/tests/responses/bf-405.html.gz b/tests/responses/bf-405.html.gz new file mode 100644 index 000000000..b7e928b76 Binary files /dev/null and b/tests/responses/bf-405.html.gz differ diff --git a/tests/responses/bf-home.html.gz b/tests/responses/bf-home.html.gz new file mode 100644 index 000000000..1f927dec3 Binary files /dev/null and b/tests/responses/bf-home.html.gz differ diff --git a/tests/responses/empty.png b/tests/responses/empty.png new file mode 100644 index 000000000..91a99b94e Binary files /dev/null and b/tests/responses/empty.png differ diff --git a/tests/responses/xkcd-1898.html.gz b/tests/responses/xkcd-1898.html.gz new file mode 100644 index 000000000..a26acc5cd Binary files /dev/null and b/tests/responses/xkcd-1898.html.gz differ diff --git a/tests/responses/xkcd-1899.html.gz b/tests/responses/xkcd-1899.html.gz new file mode 100644 index 000000000..4ada9f36e Binary files /dev/null and b/tests/responses/xkcd-1899.html.gz differ diff --git a/tests/responses/xkcd-302.html.gz b/tests/responses/xkcd-302.html.gz new file mode 100644 index 000000000..ec4bdceee Binary files /dev/null and b/tests/responses/xkcd-302.html.gz differ diff --git a/tests/responses/xkcd-303.html.gz b/tests/responses/xkcd-303.html.gz new file mode 100644 index 000000000..fea0974d4 Binary files /dev/null and b/tests/responses/xkcd-303.html.gz differ diff --git a/tests/test_dosage.py b/tests/test_dosage.py index ec910cc65..50aff45ee 100644 --- a/tests/test_dosage.py +++ b/tests/test_dosage.py @@ -1,19 +1,28 @@ # -*- coding: utf-8 -*- # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # 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 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): - """Run dosage with given options.""" - run_checked([sys.executable, cmd, '--allow-multiple'] + options) +def cmd(*options): + """'Fake' run dosage with given 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): @@ -21,38 +30,43 @@ class TestDosage(object): def test_list_comics(self): for option in ("-l", "--list", "--singlelist"): - run_with_options([option]) + cmd_ok(option) def test_display_version(self): - run_with_options(["--version"]) + cmd_ok("--version") def test_display_help(self): for option in ("-h", "--help"): - run_with_options([option]) + with pytest.raises(SystemExit): + cmd(option) def test_module_help(self): - run_with_options(["-m", "xkcd"]) + cmd_ok("-m", "xkcd") def test_no_comics_specified(self): - with pytest.raises(OSError): - run_with_options([]) + cmd_err() def test_unknown_option(self): - with pytest.raises(OSError): - run_with_options(['--imadoofus']) + with pytest.raises(SystemExit): + cmd('--imadoofus') def test_multiple_comics_match(self): - with pytest.raises(OSError): - run_with_options(['Garfield']) + cmd_err('Garfield') + @responses.activate def test_fetch_html_and_rss_json(self, tmpdir): - run_with_options(["-n", "2", "-v", "-b", str(tmpdir), "-o", "html", - "-o", "rss", "-o", "json", "xkcd"]) + httpmocks.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): - run_with_options(["--numstrips", "2", "--baseurl", "bla", - "--basepath", str(tmpdir), "--output", "rss", - "--output", "html", "--adult", "BloomingFaeries"]) + httpmocks.bloomingfaeries() + cmd_ok("--numstrips", "2", "--baseurl", "bla", "--basepath", + str(tmpdir), "--output", "rss", "--output", "html", "--adult", + "BloomingFaeries") + @responses.activate 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") diff --git a/tests/test_vote.py b/tests/test_vote.py index 8dac29aec..801897db3 100644 --- a/tests/test_vote.py +++ b/tests/test_vote.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- # Copyright (C) 2004-2008 Tristan Seligmann and Jonathan Jacobs # 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 +import responses + from dosagelib import scraper +import httpmocks class ATestScraper(scraper._BasicScraper): @@ -14,6 +17,8 @@ class ATestScraper(scraper._BasicScraper): class TestVote(object): + @responses.activate def test_vote(self): + httpmocks.vote() answer = ATestScraper('Test_Test').vote() assert answer in ('counted', 'no'), 'invalid answer %r' % answer diff --git a/tox.ini b/tox.ini index 6afa8551b..987f2e44c 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ envlist = py27, py35, py36, flake8 [testenv] 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 \ --junitxml={toxworkdir}/junit-{envname}.xml {posargs}