From a3818cc84d688675920a1c1327529ca03dbe3502 Mon Sep 17 00:00:00 2001 From: mac12m99 Date: Sat, 25 Jul 2020 14:59:59 +0200 Subject: [PATCH] refactor tests --- .github/workflows/tests.yml | 41 ++++++ core/support.py | 11 +- platformcode/logger.py | 10 +- platformcode/platformtools.py | 3 +- tests.py | 246 +++++++++++++++++++--------------- 5 files changed, 199 insertions(+), 112 deletions(-) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..32495281 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,41 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + workflow_dispatch: + schedule: + - cron: '30 17 * * *' + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + tests: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: 2.7 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install sakee + pip install html-testRunner + + - name: Run tests + run: python test.py + + - uses: actions/upload-artifact@v2 + with: + name: report + path: reports/report.html \ No newline at end of file diff --git a/core/support.py b/core/support.py index deac3df6..179c9104 100755 --- a/core/support.py +++ b/core/support.py @@ -1207,8 +1207,13 @@ def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=Tru checklinks_number = config.get_setting('checklinks_number') verifiedItemlist = servertools.check_list_links(verifiedItemlist, checklinks_number) - if AutoPlay and not 'downloads' in inspect.stack()[3][1] or not 'downloads' in inspect.stack()[3][1] or not inspect.stack()[4][1]: - autoplay.start(verifiedItemlist, item) + try: + if AutoPlay and not 'downloads' in inspect.stack()[3][1] or not 'downloads' in inspect.stack()[3][1] or not inspect.stack()[4][1]: + autoplay.start(verifiedItemlist, item) + except: + import traceback + logger.error(traceback.format_exc()) + pass if Videolibrary and item.contentChannel != 'videolibrary': videolibrary(verifiedItemlist, item) @@ -1247,7 +1252,7 @@ def log(*args): def channel_config(item, itemlist): - from channelselector import get_thumb + from channelselector import get_thumb itemlist.append( Item(channel='setting', action="channel_config", diff --git a/platformcode/logger.py b/platformcode/logger.py index 785dd5cf..8a30ccaa 100644 --- a/platformcode/logger.py +++ b/platformcode/logger.py @@ -13,7 +13,12 @@ PY3 = False if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int loggeractive = (config.get_setting("debug") == True) - +try: + xbmc.KodiStub() + testMode = True + import cgi +except: + testMode = False def log_enable(active): global loggeractive @@ -39,6 +44,9 @@ def encode_log(message=""): else: message = str(message) + if testMode: + message = cgi.escape(message) + return message diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py index da206259..9aa5e459 100644 --- a/platformcode/platformtools.py +++ b/platformcode/platformtools.py @@ -15,7 +15,7 @@ else: import os, xbmc, xbmcgui, xbmcplugin from past.utils import old_div from channelselector import get_thumb -from core import trakt_tools, scrapertools +from core import scrapertools from core.item import Item from platformcode import logger, config @@ -920,6 +920,7 @@ def set_player(item, xlistitem, mediaurl, view, strm, nfo_path=None, head_nfo=No # Reproduce xbmc_player.play(playlist, xlistitem) if config.get_setting('trakt_sync'): + from core import trakt_tools trakt_tools.wait_for_update_trakt() elif player_mode == 1: diff --git a/tests.py b/tests.py index 1681125b..5cf24e23 100644 --- a/tests.py +++ b/tests.py @@ -2,9 +2,11 @@ import os import sys import unittest + +import HtmlTestRunner import parameterized -from platformcode import config +from platformcode import config, logger config.set_setting('tmdb_active', False) @@ -105,124 +107,69 @@ chNumRis = { }, } +servers = [] +channels = [] -def getChannels(): - channel_list = channelselector.filterchannels("all") - ret = [] - for chItem in channel_list: +channel_list = channelselector.filterchannels("all")[:1] +ret = [] +for chItem in channel_list: + try: ch = chItem.channel if ch not in chBlackList: - ret.append({'ch': ch}) - return ret + module = __import__('channels.%s' % ch, fromlist=["channels.%s" % ch]) + hasChannelConfig = False + mainlist = module.mainlist(Item()) + menuItemlist = {} + serversFound = {} + for it in mainlist: + print 'preparing ' + ch + ' -> ' + it.title + serversFound[it.title] = [] -from specials import news + if it.action == 'channel_config': + hasChannelConfig = True + continue + if it.action == 'search': # channel-specific + continue + itemlist = getattr(module, it.action)(it) + menuItemlist[it.title] = itemlist -dictNewsChannels, any_active = news.get_channels_list() + # some sites might have no link inside, but if all results are without servers, there's something wrong + for resIt in itemlist: + if hasattr(module, resIt.action): + serversFound[it.title] = getattr(module, resIt.action)(resIt) + else: + serversFound[it.title] = [resIt] -servers_found = [] - - -def getServers(): - ret = [] - for srv in servers_found: - ret.append({'item': srv}) - return ret - - -@parameterized.parameterized_class(getChannels()) -class GenericChannelTest(unittest.TestCase): - def __init__(self, *args): - self.module = __import__('channels.%s' % self.ch, fromlist=["channels.%s" % self.ch]) - super(GenericChannelTest, self).__init__(*args) - - def test_menuitems(self): - hasChannelConfig = False - mainlist = self.module.mainlist(Item()) - self.assertTrue(mainlist, 'channel ' + self.ch + ' has no menu') - - for it in mainlist: - print 'testing ' + self.ch + ' -> ' + it.title - if it.action == 'channel_config': - hasChannelConfig = True - continue - if it.action == 'search': # channel-specific - continue - itemlist = getattr(self.module, it.action)(it) - self.assertTrue(itemlist, 'channel ' + self.ch + ' -> ' + it.title + ' is empty') - if self.ch in chNumRis: # i know how much results should be - for content in chNumRis[self.ch]: - if content in it.title: - risNum = len([i for i in itemlist if not i.nextPage]) # not count nextpage - self.assertEqual(chNumRis[self.ch][content], risNum, - 'channel ' + self.ch + ' -> ' + it.title + ' returned wrong number of results') + if serversFound[it.title]: + servers.extend( + {'name': srv.server.lower(), 'server': srv} for srv in serversFound[it.title] if srv.server) break - for resIt in itemlist: - self.assertLess(len(resIt.fulltitle), 110, - 'channel ' + self.ch + ' -> ' + it.title + ' might contain wrong titles\n' + resIt.fulltitle) - if resIt.url: - self.assertIsInstance(resIt.url, str, 'channel ' + self.ch + ' -> ' + it.title + ' -> ' + resIt.title + ' contain non-string url') - self.assertIsNotNone(re.match(validUrlRegex, resIt.url), - 'channel ' + self.ch + ' -> ' + it.title + ' -> ' + resIt.title + ' might contain wrong url\n' + resIt.url) - if 'year' in resIt.infoLabels and resIt.infoLabels['year']: - msgYear = 'channel ' + self.ch + ' -> ' + it.title + ' might contain wrong infolabels year\n' + str( - resIt.infoLabels['year']) - self.assert_(type(resIt.infoLabels['year']) is int or resIt.infoLabels['year'].isdigit(), msgYear) - self.assert_(int(resIt.infoLabels['year']) > 1900 and int(resIt.infoLabels['year']) < 2100, msgYear) + channels.append( + {'ch': ch, 'hasChannelConfig': hasChannelConfig, 'mainlist': mainlist, 'menuItemlist': menuItemlist, + 'serversFound': serversFound, 'module': module}) + except: + import traceback + logger.error(traceback.format_exc()) - if resIt.title == typo(config.get_localized_string(30992), 'color kod bold'): # next page - nextPageItemlist = getattr(self.module, resIt.action)(resIt) - self.assertTrue(nextPageItemlist, - 'channel ' + self.ch + ' -> ' + it.title + ' has nextpage not working') +from specials import news +dictNewsChannels, any_active = news.get_channels_list() - # some sites might have no link inside, but if all results are without servers, there's something wrong - servers = [] - for resIt in itemlist: - if hasattr(self.module, resIt.action): - servers = getattr(self.module, resIt.action)(resIt) - else: - servers = [resIt] +# only 1 server item for single server +serverNames = [] +serversFinal = [] +for s in servers: + if not s['name'] in serverNames: + serverNames.append(s['name']) + serversFinal.append(s) - if servers: - break - self.assertTrue(servers, 'channel ' + self.ch + ' -> ' + it.title + ' has no servers on all results') - for server in servers: - srv = server.server.lower() - if not srv: - continue - module = __import__('servers.%s' % srv, fromlist=["servers.%s" % srv]) - page_url = server.url - print 'testing ' + page_url - self.assert_(hasattr(module, 'test_video_exists'), srv + ' has no test_video_exists') - if module.test_video_exists(page_url)[0]: - urls = module.get_video_url(page_url) - server_parameters = servertools.get_server_parameters(srv) - self.assertTrue(urls or server_parameters.get("premium"), srv + ' 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, srv + ' scraper returned an invalid link') - self.assertLess(page.code, 400, srv + ' 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, - srv + ' scraper did not return valid url for link ' + page_url + '\nDirect url: ' + directUrl + '\nContent-Type: ' + contentType) - self.assertTrue(hasChannelConfig, 'channel ' + self.ch + ' has no channel config') +@parameterized.parameterized_class(channels) +class GenericChannelTest(unittest.TestCase): + def test_mainlist(self): + self.assertTrue(self.mainlist, 'channel ' + self.ch + ' has no mainlist') + self.assertTrue(self.hasChannelConfig, 'channel ' + self.ch + ' has no channel config') def test_newest(self): for cat in dictNewsChannels: @@ -233,5 +180,90 @@ class GenericChannelTest(unittest.TestCase): break +@parameterized.parameterized_class( + [{'ch': ch['ch'], 'title': title, 'itemlist': itemlist, 'serversFound': ch['serversFound'][title]} for ch in channels for + title, itemlist in ch['menuItemlist'].items()]) +class GenericChannelMenuItemTest(unittest.TestCase): + def test_menu(self): + print 'testing ' + self.ch + ' --> ' + title + self.assertTrue(itemlist, 'channel ' + self.ch + ' -> ' + title + ' is empty') + self.assertTrue(self.serversFound, + 'channel ' + self.ch + ' -> ' + title + ' has no servers on all results') + + if self.ch in chNumRis: # i know how much results should be + for content in chNumRis[self.ch]: + if content in title: + risNum = len([i for i in itemlist if not i.nextPage]) # not count nextpage + self.assertEqual(chNumRis[self.ch][content], risNum, + 'channel ' + self.ch + ' -> ' + title + ' returned wrong number of results') + break + + for resIt in itemlist: + print resIt.title + ' -> ' + resIt.url + self.assertLess(len(resIt.fulltitle), 110, + 'channel ' + self.ch + ' -> ' + title + ' might contain wrong titles\n' + resIt.fulltitle) + if resIt.url: + self.assertIsInstance(resIt.url, str, + 'channel ' + self.ch + ' -> ' + title + ' -> ' + resIt.title + ' contain non-string url') + self.assertIsNotNone(re.match(validUrlRegex, resIt.url), + 'channel ' + self.ch + ' -> ' + title + ' -> ' + resIt.title + ' might contain wrong url\n' + resIt.url) + if 'year' in resIt.infoLabels and resIt.infoLabels['year']: + msgYear = 'channel ' + self.ch + ' -> ' + title + ' might contain wrong infolabels year\n' + str( + resIt.infoLabels['year']) + self.assert_(type(resIt.infoLabels['year']) is int or resIt.infoLabels['year'].isdigit(), + msgYear) + self.assert_(int(resIt.infoLabels['year']) > 1900 and int(resIt.infoLabels['year']) < 2100, + msgYear) + + if resIt.title == typo(config.get_localized_string(30992), 'color kod bold'): # next page + nextPageItemlist = getattr(self.module, resIt.action)(resIt) + self.assertTrue(nextPageItemlist, + 'channel ' + self.ch + ' -> ' + title + ' has nextpage not working') + + print '\ntest passed' + + +@parameterized.parameterized_class(serversFinal) +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 + '\nDirect url: ' + directUrl + '\nContent-Type: ' + contentType) + except: + import traceback + logger.error(traceback.format_exc()) + + if __name__ == '__main__': - unittest.main() + unittest.main(testRunner=HtmlTestRunner.HTMLTestRunner(report_name='report', add_timestamp=False, + combine_reports=True, report_title='KoD Test Suite'))