Added .travis.yml (for travis-ci) and tox.ini files

Targets:

* Runs the unit-tests for python 2.7
* Tests unit-test coverage
* Try to build docs
* Code style checks:
  * flake8
  * isort

Codes changes:
* Fixed tests for httpdownloader (using tmp dir)
* Implemented a couple of tests for Stats plugin but they fail to run on travis

Issues:
* Can't get py26 to work because of installing libtorrent through apt and
  the option system_site_packages fails for 2.6.
This commit is contained in:
bendikro 2014-09-21 16:37:29 +02:00 committed by Calum Lind
parent 8dc9a0773c
commit 66f2739be7
18 changed files with 285 additions and 62 deletions

35
.travis.yml Normal file
View File

@ -0,0 +1,35 @@
language: python
python:
# - "2.6"
- "2.7"
# command to install dependencies
install:
- pip install tox
- lsb_release -a
- sudo add-apt-repository ppa:deluge-team/ppa -y
- sudo apt-get update
- sudo apt-get install python-libtorrent
script:
- tox
env:
- TOX_ENV=pydef
- TOX_ENV=plugins
- TOX_ENV=flake8
- TOX_ENV=flake8-complexity
- TOX_ENV=isort
- TOX_ENV=docs
- TOX_ENV=testcoverage
virtualenv:
system_site_packages: true
before_script:
- export PYTHONPATH=$PYTHONPATH:$PWD
- python -c "import libtorrent as lt; print lt.version"
script:
- tox -e $TOX_ENV

View File

@ -30,6 +30,7 @@ try:
import dbus
bus = dbus.SessionBus()
dbus_fileman = bus.get_object("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1")
except:
dbus_fileman = None

View File

@ -1,6 +0,0 @@
#!/bin/sh
while true; do
python test.py
sleep 2
done;

View File

@ -1,22 +0,0 @@
from __future__ import print_function
from deluge.common import fsize
from deluge.ui.client import sclient
sclient.set_core_uri()
def print_totals(totals):
for name, value in totals.iteritems():
print(name, fsize(value))
print("overhead:")
print("up:", fsize(totals["total_upload"] - totals["total_payload_upload"]))
print("down:", fsize(totals["total_download"] - totals["total_payload_download"]))
print("==totals==")
print_totals(sclient.stats_get_totals())
print("==session totals==")
print_totals(sclient.stats_get_session_totals())

View File

@ -0,0 +1,44 @@
import twisted.internet.defer as defer
from twisted.trial import unittest
import deluge.component as component
from deluge.common import fsize
from deluge.tests import common as tests_common
from deluge.ui.client import client
def print_totals(totals):
for name, value in totals.iteritems():
print(name, fsize(value))
print("overhead:")
print("up:", fsize(totals["total_upload"] - totals["total_payload_upload"]))
print("down:", fsize(totals["total_download"] - totals["total_payload_download"]))
class StatsTestCase(unittest.TestCase):
def setUp(self): # NOQA
defer.setDebugging(True)
tests_common.set_tmp_config_dir()
client.start_classic_mode()
client.core.enable_plugin("Stats")
def tearDown(self): # NOQA
client.stop_classic_mode()
def on_shutdown(result):
component._ComponentRegistry.components = {}
return component.shutdown().addCallback(on_shutdown)
def test_client_totals(self):
def callback(args):
print_totals(args)
d = client.stats.get_totals()
d.addCallback(callback)
def test_session_totals(self):
def callback(args):
print_totals(args)
d = client.stats.get_session_totals()
d.addCallback(callback)

View File

@ -2,10 +2,11 @@ from twisted.internet import defer
from twisted.internet.error import CannotListenError
from twisted.trial import unittest
import deluge.tests.common as common
from deluge import error
from deluge.core.authmanager import AUTH_LEVEL_ADMIN
from deluge.ui.client import Client, client, DaemonSSLProxy
from deluge.ui.client import client, Client, DaemonSSLProxy
from . import common
class NoVersionSendingDaemonSSLProxy(DaemonSSLProxy):

View File

@ -7,7 +7,8 @@ from twisted.trial import unittest
import deluge.config
from deluge.config import Config
from deluge.tests.common import set_tmp_config_dir
from .common import set_tmp_config_dir
DEFAULTS = {"string": "foobar", "int": 1, "float": 0.435, "bool": True, "unicode": u"foobar"}

View File

@ -13,11 +13,12 @@ from twisted.web.static import File
import deluge.component as component
import deluge.error
import deluge.tests.common as common
from deluge.core.core import Core
from deluge.core.rpcserver import RPCServer
from deluge.ui.web.common import compress
from . import common
warnings.filterwarnings("ignore", category=RuntimeWarning)
warnings.resetwarnings()

View File

@ -1,3 +1,4 @@
import tempfile
import warnings
from email.utils import formatdate
@ -8,11 +9,12 @@ from twisted.trial import unittest
from twisted.web.http import NOT_MODIFIED
from twisted.web.server import Site
import deluge.tests.common as common
from deluge.httpdownloader import download_file
from deluge.log import setup_logger
from deluge.ui.web.common import compress
from . import common
try:
from twisted.web.resource import Resource
except ImportError:
@ -25,6 +27,11 @@ warnings.resetwarnings()
rpath = common.rpath
temp_dir = tempfile.mkdtemp()
def fname(name):
return "%s/%s" % (temp_dir, name)
class TestRedirectResource(Resource):
@ -132,13 +139,13 @@ class DownloadFileTestCase(unittest.TestCase):
return filename
def test_download(self):
d = download_file("http://localhost:%d/" % self.listen_port, "index.html")
d.addCallback(self.assertEqual, "index.html")
d = download_file("http://localhost:%d/" % self.listen_port, fname("index.html"))
d.addCallback(self.assertEqual, fname("index.html"))
return d
def test_download_without_required_cookies(self):
url = "http://localhost:%d/cookie" % self.listen_port
d = download_file(url, "none")
d = download_file(url, fname("none"))
d.addCallback(self.fail)
d.addErrback(self.assertIsInstance, Failure)
return d
@ -146,68 +153,68 @@ class DownloadFileTestCase(unittest.TestCase):
def test_download_with_required_cookies(self):
url = "http://localhost:%d/cookie" % self.listen_port
cookie = {"cookie": "password=deluge"}
d = download_file(url, "monster", headers=cookie)
d.addCallback(self.assertEqual, "monster")
d = download_file(url, fname("monster"), headers=cookie)
d.addCallback(self.assertEqual, fname("monster"))
d.addCallback(self.assertContains, "COOKIE MONSTER!")
return d
def test_download_with_rename(self):
url = "http://localhost:%d/rename?filename=renamed" % self.listen_port
d = download_file(url, "original")
d.addCallback(self.assertEqual, "renamed")
d = download_file(url, fname("original"))
d.addCallback(self.assertEqual, fname("renamed"))
d.addCallback(self.assertContains, "This file should be called renamed")
return d
def test_download_with_rename_exists(self):
open('renamed', 'w').close()
open(fname('renamed'), 'w').close()
url = "http://localhost:%d/rename?filename=renamed" % self.listen_port
d = download_file(url, "original")
d.addCallback(self.assertEqual, "renamed-1")
d = download_file(url, fname("original"))
d.addCallback(self.assertEqual, fname("renamed-1"))
d.addCallback(self.assertContains, "This file should be called renamed")
return d
def test_download_with_rename_sanitised(self):
url = "http://localhost:%d/rename?filename=/etc/passwd" % self.listen_port
d = download_file(url, "original")
d.addCallback(self.assertEqual, "passwd")
d = download_file(url, fname("original"))
d.addCallback(self.assertEqual, fname("passwd"))
d.addCallback(self.assertContains, "This file should be called /etc/passwd")
return d
def test_download_with_rename_prevented(self):
url = "http://localhost:%d/rename?filename=spam" % self.listen_port
d = download_file(url, "forced", force_filename=True)
d.addCallback(self.assertEqual, "forced")
d = download_file(url, fname("forced"), force_filename=True)
d.addCallback(self.assertEqual, fname("forced"))
d.addCallback(self.assertContains, "This file should be called spam")
return d
def test_download_with_gzip_encoding(self):
url = "http://localhost:%d/gzip?msg=success" % self.listen_port
d = download_file(url, "gzip_encoded")
d = download_file(url, fname("gzip_encoded"))
d.addCallback(self.assertContains, "success")
return d
def test_download_with_gzip_encoding_disabled(self):
url = "http://localhost:%d/gzip?msg=fail" % self.listen_port
d = download_file(url, "gzip_encoded", allow_compression=False)
d = download_file(url, fname("gzip_encoded"), allow_compression=False)
d.addCallback(self.failIfContains, "fail")
return d
def test_page_redirect(self):
url = 'http://localhost:%d/redirect' % self.listen_port
d = download_file(url, "none")
d = download_file(url, fname("none"))
d.addCallback(self.fail)
d.addErrback(self.assertIsInstance, Failure)
return d
def test_page_not_found(self):
d = download_file("http://localhost:%d/page/not/found" % self.listen_port, "none")
d = download_file("http://localhost:%d/page/not/found" % self.listen_port, fname("none"))
d.addCallback(self.fail)
d.addErrback(self.assertIsInstance, Failure)
return d
def test_page_not_modified(self):
headers = {'If-Modified-Since': formatdate(usegmt=True)}
d = download_file("http://localhost:%d/" % self.listen_port, "index.html", headers=headers)
d = download_file("http://localhost:%d/" % self.listen_port, fname("index.html"), headers=headers)
d.addCallback(self.fail)
d.addErrback(self.assertIsInstance, Failure)
return d

View File

@ -7,12 +7,13 @@ from twisted.trial import unittest
import deluge.component as component
import deluge.core.torrent
import deluge.tests.common as common
from deluge._libtorrent import lt
from deluge.core.core import Core
from deluge.core.rpcserver import RPCServer
from deluge.core.torrent import Torrent
from . import common
config_setup = False
core = None
rpcserver = None

View File

@ -3,9 +3,10 @@ import os
from twisted.trial import unittest
import deluge.ui.tracker_icons
from deluge.tests.common import set_tmp_config_dir
from deluge.ui.tracker_icons import TrackerIcon, TrackerIcons
from .common import set_tmp_config_dir
set_tmp_config_dir()
icons = TrackerIcons()

View File

@ -29,7 +29,7 @@ from deluge import component, httpdownloader
from deluge.common import is_magnet
from deluge.configmanager import ConfigManager, get_config_dir
from deluge.ui import common as uicommon
from deluge.ui.client import Client, client
from deluge.ui.client import client, Client
from deluge.ui.coreconfig import CoreConfig
from deluge.ui.sessionproxy import SessionProxy
from deluge.ui.web.common import _, compress

View File

@ -14,6 +14,7 @@ import os
import sys
from datetime import date
import mock
import pkg_resources
try:
@ -22,6 +23,7 @@ except ImportError:
get_version = None
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
on_travis = os.environ.get('TRAVIS', None) == 'true'
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
@ -55,7 +57,7 @@ MOCK_MODULES = ['deluge.ui.languages', 'deluge.ui.countries', 'deluge.ui.gtkui.g
'twisted.web', 'twisted.web.client', 'twisted.web.error',
'win32gui', 'win32api', 'win32con', '_winreg']
if on_rtd:
if on_rtd or on_travis:
MOCK_MODULES += ['libtorrent', 'pygtk', "gtk", "gobject", "gtk.gdk", "pango", "cairo", "pangocairo"]
for mod_name in MOCK_MODULES:
@ -67,7 +69,7 @@ for mod_name in MOCK_MODULES:
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinxcontrib.napoleon']
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinxcontrib.napoleon', 'sphinx.ext.coverage']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

View File

@ -14,10 +14,6 @@ includes = glib, gio, cairo, pango, pangocairo, atk, gobject, gtk.keysyms,
zope.interface, mako.cache, email.mime, libtorrent, gtkosx_application
frameworks = CoreFoundation, Foundation, AppKit
[flake8]
max-line-length = 120
builtins = _,__request__
[isort]
known_standard_library=unicodedata
line_length=120

View File

@ -18,6 +18,7 @@ from distutils.command.build import build as _build
from distutils.command.clean import clean as _clean
from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand
import msgfmt
from version import get_version
@ -35,6 +36,23 @@ def windows_check():
desktop_data = 'deluge/ui/data/share/applications/deluge.desktop'
class PyTest(TestCommand):
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = []
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = []
self.test_suite = True
def run_tests(self):
import pytest
errcode = pytest.main(self.test_args)
sys.exit(errcode)
class BuildTranslations(cmd.Command):
description = 'Compile .po files into .mo files & create .desktop file'
@ -269,7 +287,8 @@ cmdclass = {
'build_docs': BuildDocs,
'clean_plugins': CleanPlugins,
'clean': Clean,
'egg_info_plugins': EggInfoPlugins
'egg_info_plugins': EggInfoPlugins,
'test': PyTest,
}
# Data files to be installed to the system
@ -333,6 +352,7 @@ setup(
url="http://deluge-torrent.org",
license="GPLv3",
cmdclass=cmdclass,
tests_require=['pytest'],
data_files=_data_files,
package_data={"deluge": ["ui/gtkui/glade/*.glade",
"ui/gtkui/glade/*.ui",

141
tox.ini Normal file
View File

@ -0,0 +1,141 @@
# Tox (http://tox.testrun.org/) is a tool for running tests
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
[flake8]
max-line-length = 120
builtins = _,__request__
exclude = .tox, .git, dist, build
ignore = E123,E133,E226,E241,E242
[tox]
envlist = py27, py26, flake8, isort, docs
[testenv]
commands = {envpython} setup.py test
sitepackages=True
deps =
twisted
service_identity
mako
chardet
pyopenssl
pyxdg
pytest
whitelist_externals=
py.test
setenv =
PYTHONPATH = {env:PYTHONPATH}:{env:PWD}
[pytest]
python_functions=test_
norecursedirs=.tox .git dist build
pep8maxlinelength = 120
whitelist_externals=
{[testenv]whitelist_externals}
commands=
py.test deluge
[testenv:testcoverage]
install_command=pip install {opts} {packages}
deps =
{[testenv]deps}
pytest-cov
coverage
whitelist_externals=
{[testenv]whitelist_externals}
coverage
commands=
coverage run --branch --source=deluge -m py.test deluge/tests/
coverage report
# For creating html report
# coverage html -d docs/build/htmlcoverage
[testenv:pydef]
commands=
python -c "import libtorrent as lt; print lt.version"
py.test deluge/tests
[testenv:plugins]
commands=
py.test deluge/plugins
[testenv:py26]
basepython=python2.6
commands=
{[testenv:pydef]commands}
[testenv:py27]
basepython=python2.7
commands=
{[testenv:pydef]commands}
[testenv:isort]
deps =
{[testenv]deps}
isort
whitelist_externals=
{[testenv]whitelist_externals}
isort
commands=
python -c "import subprocess, sys; output = subprocess.check_output('isort --recursive --diff --stdout deluge docs/ *.py', shell=True); print output; sys.exit(len(output) != 0)"
[testenv:flake8]
setenv =
{[testenv]setenv}
whitelist_externals=
{[testenv]whitelist_externals}
flake8
deps =
{[testenv]deps}
flake8
pep8-naming
commands=
flake8 deluge
[testenv:flake8-complexity]
setenv =
{[testenv]setenv}
whitelist_externals=
{[testenv]whitelist_externals}
flake8
sh
deps =
{[testenv:flake8]deps}
mccabe
commands=
sh -c "flake8 --max-complexity 10 deluge || true"
[testenv:docscoverage]
changedir=docs
install_command=pip install {opts} {packages}
deps =
{[testenv]deps}
sphinx
sphinxcontrib-napoleon
coverage
pytest-cov
whitelist_externals=
{[testenv]whitelist_externals}
mkdir
sphinx-build
commands=
mkdir -p build/doccoverage
sphinx-build -W -b coverage -d build/doctrees source build/doccoverage
py.test --doctest-glob='*.rst'
[testenv:docs]
changedir=docs
install_command=pip install {opts} --allow-external PIL --allow-unverified PIL {packages}
whitelist_externals=
{[testenv]whitelist_externals}
sphinx-build
deps =
{[testenv]deps}
sphinx
sphinxcontrib-napoleon
PIL
commands=
python -c "import sphinxcontrib.napoleon"
sphinx-build -E -W -b html -d build/doctrees source build/html