* improved unitesting (compat level for python 2.6 and unittest)

* preparation for SoftChroot (stubs and mocks)
This commit is contained in:
maxkoryukov
2016-02-03 06:30:09 +05:00
parent 7bff1b6c3c
commit 5da950f61b
10 changed files with 112 additions and 27 deletions

View File

@@ -152,7 +152,10 @@ def main():
headphones.DB_FILE = os.path.join(headphones.DATA_DIR, 'headphones.db')
# Read config and start logging
headphones.initialize(config_file)
try:
headphones.initialize(config_file)
except headphones.exceptions.SoftChrootError as e:
raise SystemExit('FATAL ERROR')
if headphones.DAEMON:
headphones.daemonize()

View File

@@ -29,7 +29,8 @@ from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
from headphones import versioncheck, logger
import headphones.config
from headphones.softchroot import SoftChroot
import headphones.exceptions
# (append new extras to the end)
POSSIBLE_EXTRAS = [
@@ -74,6 +75,7 @@ started = False
DATA_DIR = None
CONFIG = None
SOFT_CHROOT = None
DB_FILE = None
@@ -92,11 +94,11 @@ MIRRORLIST = ["musicbrainz.org", "headphones", "custom"]
UMASK = None
def initialize(config_file):
with INIT_LOCK:
global CONFIG
global SOFT_CHROOT
global _INITIALIZED
global CURRENT_VERSION
global LATEST_VERSION
@@ -136,6 +138,14 @@ def initialize(config_file):
logger.initLogger(console=not QUIET, log_dir=CONFIG.LOG_DIR,
verbose=VERBOSE)
if CONFIG.SOFT_CHROOT:
# soft chroot defined, lets try to initialize:
try:
SOFT_CHROOT = SoftChroot(str(CONFIG.SOFT_CHROOT))
except exceptions.SoftChrootError as e:
logger.error("SoftChroot error: %s", e)
raise e
if not CONFIG.CACHE_DIR:
# Put the cache dir in the data dir for now
CONFIG.CACHE_DIR = os.path.join(DATA_DIR, 'cache')

View File

@@ -1,6 +1,6 @@
#import unittest
#import mock
from unittest import TestCase
from headphones.unittestcompat import TestCase
import headphones.albumart

View File

@@ -236,6 +236,7 @@ _CONFIG_DEFINITIONS = {
'SAB_USERNAME': (str, 'SABnzbd', ''),
'SAMPLINGFREQUENCY': (int, 'General', 44100),
'SEARCH_INTERVAL': (int, 'General', 1440),
'SOFT_CHROOT': (path, 'General', ''),
'SONGKICK_APIKEY': (str, 'Songkick', 'nd1We7dFW2RqxPw8'),
'SONGKICK_ENABLED': (int, 'Songkick', 1),
'SONGKICK_FILTER_ENABLED': (int, 'Songkick', 0),
@@ -308,7 +309,7 @@ class Config(object):
definition = _CONFIG_DEFINITIONS[key]
if len(definition) == 3:
definition_type, section, default = definition
else:
elif len(definition) == 4:
definition_type, section, _, default = definition
return key, definition_type, section, ini_key, default

View File

@@ -1,26 +1,17 @@
#import unittest
import sys
import mock
from unittest import TestCase
from headphones.unittestcompat import TestCase
from mock import MagicMock
import headphones.config
from headphones.config import path
def is26():
if sys.version_info[0] == 2 and sys.version_info[1] == 6:
return True
return False
class ConfigPathTest(TestCase):
def test_path(self):
p = path('/tmp')
#fuckin python 2.6:
if not is26():
self.assertIsInstance(p, path)
self.assertIsNotNone(p)
self.assertTrue(True)
self.assertIsInstance(p, path)
self.assertIsNotNone(p)
def test_path_call(self):
s = '/tmp'
@@ -41,10 +32,7 @@ class ConfigPathTest(TestCase):
def test_path_repr(self):
s = '/tmp'
p1 = path(s)
#fuckin python 2.6:
if not is26():
self.assertIn('headphones.config.path', p1.__repr__())
self.assertTrue(True)
self.assertIn('headphones.config.path', p1.__repr__())
# patch required, since Config works ower a
@@ -62,9 +50,7 @@ class ConfigTest(TestCase):
"""Test creating headphones.Config"""
cf = headphones.config.Config('/tmp/notexist')
#fuckin python 2.6:
if not is26():
self.assertIsInstance(cf, headphones.config.Config)
self.assertIsInstance(cf, headphones.config.Config)
self.assertTrue(True)
def test_write(self, config_obj_fabric_mock):
@@ -84,6 +70,4 @@ class ConfigTest(TestCase):
general_opts_set = conf_mock['General'].__setitem__.call_args_list
general_opts_set = map(lambda x: x[0][0], general_opts_set)
#fuckin python 2.6:
if not is26():
self.assertIn('download_dir', general_opts_set, 'There is no download_dir in ConfigObj (submodule of Config)')
self.assertIn('download_dir', general_opts_set, 'There is no download_dir in ConfigObj (submodule of Config)')

View File

@@ -24,3 +24,9 @@ class NewzbinAPIThrottled(HeadphonesException):
"""
Newzbin has throttled us, deal with it
"""
class SoftChrootError(HeadphonesException):
"""
Fatal errors in SoftChroot module
"""
pass

14
headphones/softchroot.py Normal file
View File

@@ -0,0 +1,14 @@
import os
from headphones.exceptions import SoftChrootError
class SoftChroot(object):
def __init__(self, path):
path = path.strip()
if (not os.path.exists(path) or
not os.path.isdir(path)):
raise SoftChrootError('No such directory: %s' % path)
path = path.strip(os.path.sep) + os.path.sep
self.chroot = path

View File

@@ -0,0 +1,38 @@
import os
import mock
from headphones.unittestcompat import TestCase
from mock import MagicMock
from headphones.softchroot import SoftChroot
from headphones.exceptions import SoftChrootError
class SoftChrootTest(TestCase):
def test_create(self):
""" create headphones.SoftChroot """
cf = SoftChroot('/tmp/')
self.assertIsInstance(cf, SoftChroot)
@mock.patch('headphones.config.ConfigObj', name='ConfigObjMock')
def test_create_on_file(self, config_obj_fabric_mock):
""" create SoftChroot on file, not a directory """
path = os.path.join('tmp', 'notexist', 'asdf', '11', '12', 'np', 'itsssss')
with self.assertRaises(SoftChrootError) as exc:
cf = SoftChroot(path)
self.assertRegexpMatches(str(exc.exception), r'No such directory')
self.assertRegexpMatches(str(exc.exception), path)
@mock.patch('headphones.softchroot', name='SoftChrootMock')
def test_create_on_file(self, config_obj_fabric_mock):
""" create SoftChroot on file, not a directory """
path = os.path.join('tmp', 'notexist', 'asdf', '11', '12', 'np', 'itsssss')
with self.assertRaises(SoftChrootError) as exc:
cf = SoftChroot(path)
self.assertRegexpMatches(str(exc.exception), r'No such directory')
self.assertRegexpMatches(str(exc.exception), path)

View File

@@ -0,0 +1,28 @@
import sys
from unittest import TestCase as TC
def _is26():
if sys.version_info[0] == 2 and sys.version_info[1] == 6:
return True
return False
_dummy = _is26()
def _d(f):
def decorate(self, *args, **kw):
if _dummy:
return self.assertTrue(True)
return f(self, *args, **kw)
return decorate
class TestCase(TC):
"""
Wrapper for python 2.6 stubs
"""
@_d
def assertIsInstance(self, *args, **kw):
return super(TestCase, self).assertIsInstance(*args, **kw)
@_d
def assertIsIn(self, *args, **kw):
return super(TestCase, self).assertIsIn(*args, **kw)

View File

@@ -1369,6 +1369,7 @@ class WebInterface(object):
# Need to convert EXTRAS to a dictionary we can pass to the config:
# it'll come in as a string like 2,5,6,8
extra_munges = {
"dj-mix": "dj_mix",
"mixtape/street": "mixtape_street"