diff --git a/core/support.py b/core/support.py
index 27e03d99..b9ea1f9a 100755
--- a/core/support.py
+++ b/core/support.py
@@ -317,7 +317,8 @@ def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, t
longtitle += s + parsedTitle.get('episode_title')
item.contentEpisodeTitle = parsedTitle.get('episode_title')
except:
- logger.debug('Error')
+ import traceback
+ logger.error(traceback.format_exc())
longtitle = typo(longtitle, 'bold')
lang1, longtitle = scrapeLang(scraped, lang, longtitle)
diff --git a/platformcode/logger.py b/platformcode/logger.py
index 8815fd0a..e312617a 100644
--- a/platformcode/logger.py
+++ b/platformcode/logger.py
@@ -6,6 +6,15 @@ from __future__ import unicode_literals
import inspect, os, xbmc, sys
from platformcode import config
+# for test suite
+try:
+ xbmc.KodiStub()
+ testMode = True
+ record = False
+ recordedLog = ''
+ import html
+except:
+ testMode = False
LOG_FORMAT = '{addname}[{filename}.{function}:{line}]{sep} {message}'
DEBUG_ENABLED = config.get_setting("debug")
DEF_LEVEL = xbmc.LOGINFO if sys.version_info[0] >= 3 else xbmc.LOGNOTICE
@@ -28,6 +37,10 @@ def error(*args):
def log(*args, **kwargs):
msg = ''
for arg in args: msg += ' ' + str(arg)
+ if testMode and record:
+ global recordedLog
+ recordedLog += msg + '\n'
+ return
frame = inspect.currentframe().f_back.f_back
filename = frame.f_code.co_filename
filename = os.path.basename(filename).split('.')[0]
diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py
index 1e6c24a1..2372a28b 100644
--- a/platformcode/platformtools.py
+++ b/platformcode/platformtools.py
@@ -111,6 +111,70 @@ def dialog_browse(_type, heading, shares="files", mask="", useThumbs=False, trea
def dialog_register(heading, user=False, email=False, password=False, user_default='', email_default='', password_default='', captcha_img=''):
+ class Register(xbmcgui.WindowXMLDialog):
+ def Start(self, heading, user, email, password, user_default, email_default, password_default, captcha_img):
+ self.result = {}
+ self.heading = heading
+ self.user = user
+ self.email = email
+ self.password = password
+ self.user_default = user_default
+ self.email_default = email_default
+ self.password_default = password_default
+ self.captcha_img = captcha_img
+ self.doModal()
+
+ return self.result
+
+ def __init__(self, *args, **kwargs):
+ self.mensaje = kwargs.get("mensaje")
+ self.imagen = kwargs.get("imagen")
+
+ def onInit(self):
+ #### Kodi 18 compatibility ####
+ if config.get_platform(True)['num_version'] < 18:
+ self.setCoordinateResolution(2)
+ height = 90
+ self.getControl(10002).setText(self.heading)
+ if self.user:
+ self.getControl(10003).setText(self.user_default)
+ height += 70
+ else:
+ self.getControl(10003).setVisible(False)
+ if self.email:
+ self.getControl(10004).setText(self.email_default)
+ height += 70
+ else:
+ self.getControl(10004).setVisible(False)
+ if self.password:
+ self.getControl(10005).setText(self.password_default)
+ height += 70
+ else:
+ self.getControl(10005).setVisible(False)
+ if self.captcha_img:
+
+ self.getControl(10007).setImage(self.captcha_img)
+ height += 240
+ else:
+ self.getControl(10005).setVisible(False)
+ height += 40
+ if height < 250: height = 250
+ self.getControl(10000).setHeight(height)
+ self.getControl(10001).setHeight(height)
+ self.getControl(10000).setPosition(255, (720 - height) / 2)
+ self.setFocusId(30000)
+
+ def onClick(self, control):
+ if control in [10010]:
+ self.close()
+
+ elif control in [10009]:
+ if self.user: self.result['user'] = self.getControl(10003).getText()
+ if self.email: self.result['email'] = self.getControl(10004).getText()
+ if self.password: self.result['password'] = self.getControl(10005).getText()
+ if self.captcha_img: self.result['captcha'] = self.getControl(10006).getText()
+ self.close()
+
dialog = Register('Register.xml', config.get_runtime_path()).Start(heading, user, email, password, user_default, email_default, password_default, captcha_img)
return dialog
@@ -1274,68 +1338,3 @@ def get_platform():
ret["arch"] = "arm"
return ret
-
-
-class Register(xbmcgui.WindowXMLDialog):
- def Start(self, heading, user, email, password, user_default, email_default, password_default, captcha_img):
- self.result = {}
- self.heading = heading
- self.user = user
- self.email = email
- self.password = password
- self.user_default = user_default
- self.email_default = email_default
- self.password_default = password_default
- self.captcha_img = captcha_img
- self.doModal()
-
- return self.result
-
- def __init__(self, *args, **kwargs):
- self.mensaje = kwargs.get("mensaje")
- self.imagen = kwargs.get("imagen")
-
- def onInit(self):
- #### Kodi 18 compatibility ####
- if config.get_platform(True)['num_version'] < 18:
- self.setCoordinateResolution(2)
- height = 90
- self.getControl(10002).setText(self.heading)
- if self.user:
- self.getControl(10003).setText(self.user_default)
- height+=70
- else:
- self.getControl(10003).setVisible(False)
- if self.email:
- self.getControl(10004).setText(self.email_default)
- height+=70
- else:
- self.getControl(10004).setVisible(False)
- if self.password:
- self.getControl(10005).setText(self.password_default)
- height+=70
- else:
- self.getControl(10005).setVisible(False)
- if self.captcha_img:
-
- self.getControl(10007).setImage(self.captcha_img)
- height+=240
- else:
- self.getControl(10005).setVisible(False)
- height +=40
- if height < 250: height = 250
- self.getControl(10000).setHeight(height)
- self.getControl(10001).setHeight(height)
- self.getControl(10000).setPosition(255, (720-height)/2)
- self.setFocusId(30000)
-
- def onClick(self, control):
- if control in [10010]:
- self.close()
-
- elif control in [10009]:
- if self.user: self.result['user'] = self.getControl(10003).getText()
- if self.email: self.result['email'] = self.getControl(10004).getText()
- if self.password: self.result['password'] = self.getControl(10005).getText()
- if self.captcha_img: self.result['captcha'] = self.getControl(10006).getText()
- self.close()
\ No newline at end of file
diff --git a/tests/run.sh b/tests/run.sh
new file mode 100755
index 00000000..2f878315
--- /dev/null
+++ b/tests/run.sh
@@ -0,0 +1,12 @@
+python -m pip install --upgrade pip
+pip install sakee
+pip install html-testRunner
+pip install parameterized
+export PYTHONPATH=$PWD
+export KODI_INTERACTIVE=0
+export KODI_HOME=$PWD/tests/home
+if (( $# >= 1 ))
+then
+ export KOD_TST_CH=$1
+fi
+python tests/test_generic.py
\ No newline at end of file
diff --git a/tests/test_generic.py b/tests/test_generic.py
index 5ec5e91a..e4cb6eb5 100644
--- a/tests/test_generic.py
+++ b/tests/test_generic.py
@@ -135,6 +135,8 @@ channels = []
channel_list = channelselector.filterchannels("all") if 'KOD_TST_CH' not in os.environ else [Item(channel=os.environ['KOD_TST_CH'], action="mainlist")]
logger.info(channel_list)
ret = []
+
+logger.record = True
for chItem in channel_list:
try:
ch = chItem.channel
@@ -143,6 +145,7 @@ for chItem in channel_list:
hasChannelConfig = False
mainlist = module.mainlist(Item())
menuItemlist = {}
+ logMenu = {}
serversFound = {}
for it in mainlist:
@@ -155,6 +158,8 @@ for chItem in channel_list:
continue
itemlist = getattr(module, it.action)(it)
menuItemlist[it.title] = itemlist
+ logMenu[it.title] = logger.recordedLog
+ logger.recordedLog = ''
# some sites might have no link inside, but if all results are without servers, there's something wrong
for resIt in itemlist:
@@ -165,16 +170,22 @@ for chItem in channel_list:
serversFound[it.title] = [resIt]
if serversFound[it.title]:
+ if hasattr(module, 'play'):
+ serversFound[it.title] = [getattr(module, 'play')(resIt)[0] for srv in serversFound[it.title]]
servers.extend(
{'name': srv.server.lower(), 'server': srv} for srv in serversFound[it.title] if srv.server)
break
channels.append(
{'ch': ch, 'hasChannelConfig': hasChannelConfig, 'mainlist': mainlist, 'menuItemlist': menuItemlist,
- 'serversFound': serversFound, 'module': module})
+ 'serversFound': serversFound, 'module': module, 'logMenu': logMenu})
except:
import traceback
logger.error(traceback.format_exc())
+ print(logger.recordedLog)
+ logger.recordedLog = ''
+
+logger.record = False
from specials import news
dictNewsChannels, any_active = news.get_channels_list()
@@ -203,12 +214,26 @@ class GenericChannelTest(unittest.TestCase):
break
+def testnameCh(cls, num, params_dict):
+ return 'channels.' + params_dict['ch'] + ' -> ' + params_dict['title']
+
+
+def testnameSrv(cls, num, params_dict):
+ return 'servers.' + params_dict['name']
+
+
@parameterized.parameterized_class(
- [{'ch': ch['ch'], 'title': title, 'itemlist': itemlist, 'serversFound': ch['serversFound'][title] if title in ch['serversFound'] else True, 'module': ch['module']} for ch in channels for
- title, itemlist in ch['menuItemlist'].items()])
+ [{'ch': ch['ch'], 'title': title, 'itemlist': itemlist,
+ 'serversFound': ch['serversFound'][title] if title in ch['serversFound'] else True,
+ 'module': ch['module'], 'log': ch['logMenu'][title]}
+ for ch in channels
+ for title, itemlist in ch['menuItemlist'].items()], class_name_func=testnameCh)
class GenericChannelMenuItemTest(unittest.TestCase):
def test_menu(self):
print('testing ' + self.ch + ' --> ' + self.title)
+
+ logger.info(self.log)
+
self.assertTrue(self.module.host, 'channel ' + self.ch + ' has not a valid hostname')
self.assertTrue(self.itemlist, 'channel ' + self.ch + ' -> ' + self.title + ' is empty')
self.assertTrue(self.serversFound,
@@ -246,48 +271,46 @@ class GenericChannelMenuItemTest(unittest.TestCase):
self.assertTrue(nextPageItemlist,
'channel ' + self.ch + ' -> ' + self.title + ' has nextpage not working')
- print('
test passed')
+ print('test passed')
-@parameterized.parameterized_class(serversFinal)
+@parameterized.parameterized_class(serversFinal, class_name_func=testnameSrv)
class GenericServerTest(unittest.TestCase):
def test_get_video_url(self):
module = __import__('servers.%s' % self.name, fromlist=["servers.%s" % self.name])
page_url = self.server.url
print('testing ' + page_url)
self.assert_(hasattr(module, 'test_video_exists'), self.name + ' has no test_video_exists')
- try:
- if module.test_video_exists(page_url)[0]:
- urls = module.get_video_url(page_url)
- server_parameters = servertools.get_server_parameters(self.name)
- self.assertTrue(urls or server_parameters.get("premium"),
- self.name + ' scraper did not return direct urls for ' + page_url)
- print(urls)
- for u in urls:
- spl = u[1].split('|')
- if len(spl) == 2:
- directUrl, headersUrl = spl
- else:
- directUrl, headersUrl = spl[0], ''
- headers = {}
- if headersUrl:
- for name in headersUrl.split('&'):
- h, v = name.split('=')
- h = str(h)
- headers[h] = str(v)
- print(headers)
- if 'magnet:?' in directUrl: # check of magnet links not supported
- continue
- page = downloadpage(directUrl, headers=headers, only_headers=True, use_requests=True)
- self.assertTrue(page.success, self.name + ' scraper returned an invalid link')
- self.assertLess(page.code, 400, self.name + ' scraper returned a ' + str(page.code) + ' link')
- contentType = page.headers['Content-Type']
- self.assert_(contentType.startswith(
- 'video') or 'mpegurl' in contentType or 'octet-stream' in contentType or 'dash+xml' in contentType,
- self.name + ' scraper did not return valid url for link ' + page_url + '
Direct url: ' + directUrl + '
Content-Type: ' + contentType)
- except:
- import traceback
- logger.error(traceback.format_exc())
+
+ if module.test_video_exists(page_url)[0]:
+ urls = module.get_video_url(page_url)
+ server_parameters = servertools.get_server_parameters(self.name)
+ self.assertTrue(urls or server_parameters.get("premium"),
+ self.name + ' scraper did not return direct urls for ' + page_url)
+ print(urls)
+ for u in urls:
+ spl = u[1].split('|')
+ if len(spl) == 2:
+ directUrl, headersUrl = spl
+ else:
+ directUrl, headersUrl = spl[0], ''
+ headers = {}
+ if headersUrl:
+ for name in headersUrl.split('&'):
+ h, v = name.split('=')
+ h = str(h)
+ headers[h] = str(v)
+ print(headers)
+ if 'magnet:?' in directUrl: # check of magnet links not supported
+ continue
+ page = downloadpage(directUrl, headers=headers, only_headers=True, use_requests=True)
+ self.assertTrue(page.success, self.name + ' scraper returned an invalid link')
+ self.assertLess(page.code, 400, self.name + ' scraper returned a ' + str(page.code) + ' link')
+ contentType = page.headers['Content-Type']
+ self.assert_(contentType.startswith(
+ 'video') or 'mpegurl' in contentType or 'octet-stream' in contentType or 'dash+xml' in contentType,
+ self.name + ' scraper did not return valid url for link ' + page_url + '
Direct url: ' + directUrl + '
Content-Type: ' + contentType)
+ print('test passed')
if __name__ == '__main__':