diff --git a/config.py b/config.py index 03c5fab5..2fe5cbba 100644 --- a/config.py +++ b/config.py @@ -111,3 +111,12 @@ 'LabHub:*': {'allowprivate': False}} AUTOINSTALL_DEPS = True + +DEFAULT_CONFIG = { + 'LabHub': { + 'GH_TOKEN': os.environ.get('GH_TOKEN'), + 'GL_TOKEN': os.environ.get('GL_TOKEN'), + 'GH_ORG_NAME': os.environ.get('GH_ORG_NAME', 'coala'), + 'GL_ORG_NAME': os.environ.get('GL_ORG_NAME', 'coala'), + }, +} diff --git a/plugins/constants.py b/plugins/constants.py index c85f0529..91eebcc7 100644 --- a/plugins/constants.py +++ b/plugins/constants.py @@ -1,10 +1,6 @@ -import os API_DOCS = 'http://api.coala.io/en/latest' USER_DOCS = 'http://docs.coala.io/en/latest' -GH_ORG_NAME = os.environ.get('GH_ORG_NAME', 'coala') -GL_ORG_NAME = os.environ.get('GL_ORG_NAME', 'coala') - MAX_MSG_LEN = 1000 MAX_LINES = 20 diff --git a/plugins/labhub.py b/plugins/labhub.py index 8e1e51e4..67babc44 100644 --- a/plugins/labhub.py +++ b/plugins/labhub.py @@ -1,5 +1,4 @@ import datetime -import os import re import time @@ -10,8 +9,8 @@ from errbot.templating import tenv from functools import wraps -from plugins import constants from utils.backends import message_link +from utils.mixin import DefaultConfigMixin def members_only(func): @@ -33,18 +32,22 @@ def wrapper(*args, **kwargs): return wrapper -class LabHub(BotPlugin): +class LabHub(DefaultConfigMixin, BotPlugin): """GitHub and GitLab utilities""" # Ignore QuotesBear - GH_ORG_NAME = constants.GH_ORG_NAME - GL_ORG_NAME = constants.GL_ORG_NAME + CONFIG_TEMPLATE = { + 'GH_ORG_NAME': None, + 'GH_TOKEN': None, + 'GL_ORG_NAME': None, + 'GL_TOKEN': None, + } - def __init__(self, bot, name=None): - super().__init__(bot, name) + def activate(self): + super().activate() teams = dict() try: - gh = github3.login(token=os.environ.get('GH_TOKEN')) + gh = github3.login(token=self.config['GH_TOKEN']) assert gh is not None except AssertionError: self.log.error('Cannot create github object, please check GH_TOKEN') @@ -55,8 +58,8 @@ def __init__(self, bot, name=None): self._teams = teams - self.IGH = GitHub(GitHubToken(os.environ.get('GH_TOKEN'))) - self.IGL = GitLab(GitLabPrivateToken(os.environ.get('GL_TOKEN'))) + self.IGH = GitHub(GitHubToken(self.config['GH_TOKEN'])) + self.IGL = GitLab(GitLabPrivateToken(self.config['GL_TOKEN'])) self.REPOS = dict() @@ -65,7 +68,7 @@ def __init__(self, bot, name=None): filter(lambda x: (x.full_name.split('/')[0] == self.GH_ORG_NAME), self.IGH.write_repositories)} - except RuntimeError: + except RuntimeError: # pragma: no cover, for logging self.log.exception('Something went wrong in fetching github repos.') else: self.REPOS.update(self.gh_repos) @@ -82,6 +85,14 @@ def __init__(self, bot, name=None): self.hello_world_users = set() + @property + def GH_ORG_NAME(self): + return self.config['GH_ORG_NAME'] + + @property + def GL_ORG_NAME(self): + return self.config['GL_ORG_NAME'] + @property def TEAMS(self): return self._teams @@ -368,7 +379,7 @@ def newcomer_issue_check(user, iss): search_query = 'user:coala assignee:{} ' \ 'label:difficulty/newcomer'.format(user) result = GitHub.raw_search(GitHubToken( - os.environ.get('GH_TOKEN')), search_query) + self.config['GH_TOKEN']), search_query) return not (sum(1 for _ in result) >= 1) else: return True diff --git a/tests/answer_test.py b/tests/answer_test.py index a230c8a5..dd5e15fb 100644 --- a/tests/answer_test.py +++ b/tests/answer_test.py @@ -1,22 +1,15 @@ import os -import logging - -from errbot.backends.test import FullStackTest import vcr import requests_mock import plugins.answer +from tests.isolated_testcase import IsolatedTestCase -class TestAnswer(FullStackTest): +class TestAnswer(IsolatedTestCase): - def setUp(self, - extra_plugin_dir=None, - extra_test_file=None, - loglevel=logging.DEBUG, - extra_config=None): - super().setUp(extra_plugin_dir='plugins', - loglevel=logging.ERROR) + def setUp(self): + super().setUp() # Ignore InvalidLinkBear self.answer_end_point = 'http://0.0.0.0:8000' os.environ['ANSWER_END'] = self.answer_end_point diff --git a/tests/coala_lowercase_c_test.py b/tests/coala_lowercase_c_test.py index 65238036..cd9fa14e 100644 --- a/tests/coala_lowercase_c_test.py +++ b/tests/coala_lowercase_c_test.py @@ -1,13 +1,12 @@ -pytest_plugins = ['errbot.backends.test'] +from tests.isolated_testcase import IsolatedTestCase -extra_plugin_dir = 'plugins' +class CoalaLowercaseTest(IsolatedTestCase): -def test_coala_lowercase(testbot): - testbot.assertCommand('what is Coala?', - 'coala is always written with a lower case c') + def test_coala_lowercase(self): + self.assertCommand('what is Coala?', + 'coala is always written with a lower case c') - -def test_cep(testbot): - testbot.assertCommand('what is a CEP?', - 'cEP is always written with a lower case c') + def test_cep(self): + self.assertCommand('what is a CEP?', + 'cEP is always written with a lower case c') diff --git a/tests/coatils_test.py b/tests/coatils_test.py index cf3ad1da..3b97492a 100644 --- a/tests/coatils_test.py +++ b/tests/coatils_test.py @@ -1,21 +1,12 @@ -import logging import queue -from errbot.backends.test import FullStackTest +from tests.isolated_testcase import IsolatedTestCase import vcr from plugins.coatils import Coatils -class TestCoatils(FullStackTest): - - def setUp(self, - extra_plugin_dir=None, - extra_test_file=None, - loglevel=logging.DEBUG, - extra_config=None): - super().setUp(extra_plugin_dir='plugins', - loglevel=logging.ERROR) +class TestCoatils(IsolatedTestCase): @vcr.use_cassette('tests/cassettes/coatils_total_bears.yaml') def test_total_bears(self): diff --git a/tests/corobo_test_case.py b/tests/corobo_test_case.py index d56a366d..ec9fe2ed 100644 --- a/tests/corobo_test_case.py +++ b/tests/corobo_test_case.py @@ -28,10 +28,14 @@ def load_plugin_templates(self, klass): self.plug_files[klass.__name__] = plug_info add_plugin_templates_path(plug_info) - def load_plugin(self, plugin_name: str, mock_dict=False): + def load_plugin(self, + plugin_name: str, + mock_dict=False, + plugin_config=None): """Load plugin manually""" klass = self.klasses[plugin_name] plugin = klass(self.bot, plugin_name) + plugin.configure(plugin_config) self.plugins[plugin_name] = plugin self.bot.plugin_manager.plugins[plugin_name] = plugin plug_file = self.plug_files[plugin_name] diff --git a/tests/deprecate_bot_prefixes_test.py b/tests/deprecate_bot_prefixes_test.py index 4b6f67c0..f4bf9778 100644 --- a/tests/deprecate_bot_prefixes_test.py +++ b/tests/deprecate_bot_prefixes_test.py @@ -1,8 +1,9 @@ -pytest_plugins = ['errbot.backends.test'] -extra_plugin_dir = 'plugins' +from tests.isolated_testcase import IsolatedTestCase -def test_deprecated_prefixes_other(testbot): - testbot.bot_config.BOT_DEPRECATED_PREFIXES = ('oldbot', 'deprecatedbot') - testbot.assertCommand('oldbot just a test', 'has been deprecated') - testbot.assertCommand('deprecatedbot just a test', 'has been deprecated') +class DeprecateBotPrefixesTest(IsolatedTestCase): + + def test_deprecated_prefixes_other(self): + self.bot_config.BOT_DEPRECATED_PREFIXES = ('oldbot', 'deprecatedbot') + self.assertCommand('oldbot just a test', 'has been deprecated') + self.assertCommand('deprecatedbot just a test', 'has been deprecated') diff --git a/tests/explain_test.py b/tests/explain_test.py index 5645692d..724f24b4 100644 --- a/tests/explain_test.py +++ b/tests/explain_test.py @@ -1,20 +1,20 @@ import errbot.rendering +from tests.isolated_testcase import IsolatedTestCase from plugins.explain import Explain -pytest_plugins = ['errbot.backends.test'] - -extra_plugin_dir = 'plugins' text = errbot.rendering.text() -def test_explain(testbot): - testbot.assertCommand("!explain REView", 'For a good review,') - testbot.assertCommand("!explain gOOgle", 'use google') - testbot.assertCommand("!explain not_found", - text.convert(Explain.ERROR_MSG)) - testbot.assertCommand("!explain review to @meet", - '@meet') - testbot.assertCommand("!please explain review", - "Command \"please\" / \"please explain\" not found.") +class ExplainTest(IsolatedTestCase): + + def test_explain(self): + self.assertCommand('!explain REView', 'For a good review,') + self.assertCommand('!explain gOOgle', 'use google') + self.assertCommand('!explain not_found', + text.convert(Explain.ERROR_MSG)) + self.assertCommand('!explain review to @meet', + '@meet') + self.assertCommand('!please explain review', + 'Command \"please\" / \"please explain\" not found.') diff --git a/tests/ghetto_test.py b/tests/ghetto_test.py index 8e7dbda5..de460918 100644 --- a/tests/ghetto_test.py +++ b/tests/ghetto_test.py @@ -1,15 +1,15 @@ import requests_mock import vcr -pytest_plugins = ['errbot.backends.test'] +from tests.isolated_testcase import IsolatedTestCase -extra_plugin_dir = 'plugins' +class GhettoTest(IsolatedTestCase): -@vcr.use_cassette('tests/cassettes/ghetto.yaml') -def test_ghetto(testbot): - testbot.assertCommand("!ghetto hi, whats up?", "hi, wassup?") - with requests_mock.Mocker() as m: - m.register_uri('POST', 'http://www.gizoogle.net/textilizer.php', - text='test text which will not match with the regex') - testbot.assertCommand("!ghetto ...", "Shiznit happens!") + @vcr.use_cassette('tests/cassettes/ghetto.yaml') + def test_ghetto(self): + self.assertCommand('!ghetto hi, whats up?', 'hi, wassup?') + with requests_mock.Mocker() as m: + m.register_uri('POST', 'http://www.gizoogle.net/textilizer.php', + text='test text which will not match with the regex') + self.assertCommand('!ghetto ...', 'Shiznit happens!') diff --git a/tests/isolated_testcase.py b/tests/isolated_testcase.py new file mode 100644 index 00000000..a2a181b8 --- /dev/null +++ b/tests/isolated_testcase.py @@ -0,0 +1,24 @@ +import logging +import os + +from errbot.backends.test import FullStackTest +from pathlib import Path + + +class IsolatedTestCase(FullStackTest): + + file_path = Path(__file__).parent / '..' / 'plugins' / 'labhub.plug' + renamed_file_path = Path(__file__).parent / '..' / 'plugins' / 'hidden' + + @classmethod + def setUpClass(cls, extra_config=None): + os.rename(cls.file_path, cls.renamed_file_path) + + @classmethod + def tearDownClass(cls): + os.rename(cls.renamed_file_path, cls.file_path) + + def setUp(self, extra_config=None): + super().setUp(extra_plugin_dir='plugins', + loglevel=logging.ERROR, + extra_config=extra_config) diff --git a/tests/labhub_test.py b/tests/labhub_test.py index d29fdebc..e5a0ca8f 100644 --- a/tests/labhub_test.py +++ b/tests/labhub_test.py @@ -27,7 +27,13 @@ def setUp(self): }, '_teams': self.teams, } - self.labhub = self.load_plugin('LabHub', self.global_mocks) + configs = { + 'GH_TOKEN': None, + 'GL_TOKEN': None, + 'GH_ORG_NAME': 'coala', + 'GL_ORG_NAME': 'coala', + } + self.labhub = self.load_plugin('LabHub', self.global_mocks, configs) def test_invite_cmd(self): mock_team_newcomers = create_autospec(github3.orgs.Team) @@ -45,8 +51,6 @@ def test_invite_cmd(self): self.inject_mocks('LabHub', mock_dict) testbot = self - plugins.labhub.os.environ['GH_TOKEN'] = 'patched?' - self.assertEqual(self.labhub.TEAMS, self.teams) mock_dict['is_room_member'].return_value = False @@ -304,7 +308,6 @@ def test_assign_cmd(self): # no assignee, newcomer, difficulty medium mock_dict = { - 'GH_ORG_NAME': 'not-coala', 'TEAMS': { 'not-coala newcomers': self.mock_team, 'not-coala developers': mock_dev_team, @@ -312,10 +315,11 @@ def test_assign_cmd(self): }, } self.inject_mocks('LabHub', mock_dict) + self.labhub.config['GH_ORG_NAME'] = 'not-coala' testbot.assertCommand(cmd.format('coala', 'a', '23'), 'assigned') - mock_dict['GH_ORG_NAME'] = 'coala' + self.labhub.config['GH_ORG_NAME'] = 'coala' mock_dict['TEAMS'] = self.teams self.inject_mocks('LabHub', mock_dict) @@ -472,3 +476,12 @@ def test_alive(self): '!pr stats 3hours', 'You need to be a member of this organization ' 'to use this command.', timeout=100) + + def test_invalid_token(self): + plugins.labhub.github3.login.return_value = None + with self.assertLogs() as cm: + self.labhub.activate() + self.assertIn( + 'ERROR:errbot.plugins.LabHub:Cannot create github object,' + ' please check GH_TOKEN', + cm.output) diff --git a/tests/lmgtfy_test.py b/tests/lmgtfy_test.py index 9445383f..ccbba236 100644 --- a/tests/lmgtfy_test.py +++ b/tests/lmgtfy_test.py @@ -1,13 +1,12 @@ import errbot.rendering from plugins.lmgtfy import Lmgtfy - -pytest_plugins = ['errbot.backends.test'] - -extra_plugin_dir = 'plugins' +from tests.isolated_testcase import IsolatedTestCase text = errbot.rendering.text() -def test_lmgtfy(testbot): - testbot.assertCommand("!lmgtfy py c", "https://www.lmgtfy.com/?q=py c") +class LmgtfyTest(IsolatedTestCase): + + def test_lmgtfy(self): + self.assertCommand('!lmgtfy py c', 'https://www.lmgtfy.com/?q=py c') diff --git a/tests/nevermind_test.py b/tests/nevermind_test.py index d982519d..1a712905 100644 --- a/tests/nevermind_test.py +++ b/tests/nevermind_test.py @@ -1,15 +1,15 @@ -pytest_plugins = ['errbot.backends.test'] +from tests.isolated_testcase import IsolatedTestCase -extra_plugin_dir = ['plugins'] +class NevermindTest(IsolatedTestCase): -def test_nevermind(testbot): - testbot.assertCommand("!nevermind", "I'm sorry :(") - testbot.assertCommand("!nm", "I'm sorry :(") - testbot.assertCommand("!nEverMINd", "I'm sorry :(") - testbot.assertCommand("!nM", "I'm sorry :(") - testbot.assertCommand("!nmxyz", 'Command "nmxyz" not found.') - testbot.assertCommand("!hey nM", 'Command "hey" / "hey nM" not found.') - testbot.assertCommand("!nevermindxyz", 'Command "nevermindxyz" not found.') - testbot.assertCommand( - "!hey nEverMINd", 'Command "hey" / "hey nEverMINd" not found.') + def test_nevermind(self): + self.assertCommand('!nevermind', 'I\'m sorry :(') + self.assertCommand('!nm', 'I\'m sorry :(') + self.assertCommand('!nEverMINd', 'I\'m sorry :(') + self.assertCommand('!nM', 'I\'m sorry :(') + self.assertCommand('!nmxyz', 'Command "nmxyz" not found.') + self.assertCommand('!hey nM', 'Command "hey" / "hey nM" not found.') + self.assertCommand('!nevermindxyz', 'Command "nevermindxyz" not found.') + self.assertCommand('!hey nEverMINd', + 'Command "hey" / "hey nEverMINd" not found.') diff --git a/tests/pitchfork_test.py b/tests/pitchfork_test.py index e14380f6..dad2fee4 100644 --- a/tests/pitchfork_test.py +++ b/tests/pitchfork_test.py @@ -1,9 +1,10 @@ -pytest_plugins = ['errbot.backends.test'] -extra_plugin_dir = 'plugins' +from tests.isolated_testcase import IsolatedTestCase -def test(testbot): - testbot.assertCommand('!pitchfork @meet', 'being pitchforked') - testbot.assertCommand('!pitchfork @meet down to hell', 'being pitchforked') - testbot.assertCommand('!pitchfork meet to hell', 'being pitchforked') - testbot.assertCommand('!pitchfork', 'Usage') +class PitchForkTest(IsolatedTestCase): + + def test(self): + self.assertCommand('!pitchfork @meet', 'being pitchforked') + self.assertCommand('!pitchfork @meet down to hell', 'being pitchforked') + self.assertCommand('!pitchfork meet to hell', 'being pitchforked') + self.assertCommand('!pitchfork', 'Usage') diff --git a/tests/searchdocs_test.py b/tests/searchdocs_test.py index beb0e10d..5fd752e4 100644 --- a/tests/searchdocs_test.py +++ b/tests/searchdocs_test.py @@ -1,14 +1,14 @@ -pytest_plugins = ['errbot.backends.test'] +from tests.isolated_testcase import IsolatedTestCase -extra_plugin_dir = 'plugins' +class SearchDocsTest(IsolatedTestCase): -def test_search_cmd(testbot): - testbot.assertCommand( - '!search api this is search string', - 'http://api.coala.io/en/latest/search.html?q=this+is+search+string') - testbot.assertCommand( - '!search user this is search string', - 'http://docs.coala.io/en/latest/search.html?q=this+is+search+string') - testbot.assertCommand('!search not matching', - 'Invalid syntax') + def test_search_cmd(self): + self.assertCommand( + '!search api search string', + 'http://api.coala.io/en/latest/search.html?q=search+string') + self.assertCommand( + '!search user search string', + 'http://docs.coala.io/en/latest/search.html?q=search+string') + self.assertCommand('!search not matching', + 'Invalid syntax') diff --git a/tests/ship_it_test.py b/tests/ship_it_test.py index 75c48888..46fd959f 100644 --- a/tests/ship_it_test.py +++ b/tests/ship_it_test.py @@ -1,10 +1,10 @@ import errbot.rendering -pytest_plugins = ['errbot.backends.test'] +from tests.isolated_testcase import IsolatedTestCase -extra_plugin_dir = 'plugins' +class ShipItTest(IsolatedTestCase): -def test_ship_it(testbot): - text = errbot.rendering.text() - testbot.assertCommand("!shipit", text.convert("![ship it!]()")) + def test_ship_it(self): + text = errbot.rendering.text() + self.assertCommand('!shipit', text.convert('![ship it!]()')) diff --git a/tests/spam_test.py b/tests/spam_test.py index 6dc793fd..658c1a73 100644 --- a/tests/spam_test.py +++ b/tests/spam_test.py @@ -1,19 +1,13 @@ -import logging import queue -import unittest -from errbot.backends.test import TestBot +from tests.isolated_testcase import IsolatedTestCase -class TestSpam(unittest.TestCase): +class TestSpam(IsolatedTestCase): def setUp(self): - self.testbot = TestBot(extra_plugin_dir='plugins', - loglevel=logging.ERROR) - self.testbot.start() - - def tearDown(self): - self.testbot.stop() + super().setUp() + self.testbot = self def test_spam_callback(self): self.testbot.assertCommand('c'*1001, 'you\'re spamming') @@ -32,7 +26,7 @@ def test_spam_configuration(self): '{\'MAX_LINES\': 20, \'MAX_MSG_LEN\': 200}') -class TestSpamExtraConfig(unittest.TestCase): +class TestSpamExtraConfig(IsolatedTestCase): def setUp(self): extra_config = { @@ -43,13 +37,8 @@ def setUp(self): } } } - self.testbot = TestBot(extra_plugin_dir='plugins', - loglevel=logging.ERROR, - extra_config=extra_config) - self.testbot.start() - - def tearDown(self): - self.testbot.stop() + super().setUp(extra_config=extra_config) + self.testbot = self def test_spam_extra_config_callback(self): self.testbot.assertCommand('c'*501, 'you\'re spamming') diff --git a/tests/the_rules_test.py b/tests/the_rules_test.py index 28fde0a7..7be104b6 100644 --- a/tests/the_rules_test.py +++ b/tests/the_rules_test.py @@ -1,11 +1,10 @@ from plugins.the_rules import The_rules +from tests.isolated_testcase import IsolatedTestCase -pytest_plugins = ['errbot.backends.test'] -extra_plugin_dir = 'plugins' +class TheRulesTest(IsolatedTestCase): - -def test_the_rules(testbot): - testbot.assertCommand('!the rules', 'A robot may not harm humanity') - testbot.assertCommand('!the rules', 'A robot may not injure a human') - testbot.assertCommand('!THE RUles', 'A robot must obey any orders') + def test_the_rules(self): + self.assertCommand('!the rules', 'A robot may not harm humanity') + self.assertCommand('!the rules', 'A robot may not injure a human') + self.assertCommand('!THE RUles', 'A robot must obey any orders') diff --git a/tests/wolfram_alpha_test.py b/tests/wolfram_alpha_test.py index e415cd2b..6f4efdac 100755 --- a/tests/wolfram_alpha_test.py +++ b/tests/wolfram_alpha_test.py @@ -1,23 +1,13 @@ -import logging - import vcr -from errbot.backends.test import FullStackTest from plugins.wolfram_alpha import WolframAlpha +from tests.isolated_testcase import IsolatedTestCase my_vcr = vcr.VCR(match_on=['method', 'scheme', 'host', 'port', 'path'], filter_query_parameters=['appid']) -class WolframAlphaTest(FullStackTest): - - def setUp(self, - extra_plugin_dir=None, - extra_test_file=None, - loglevel=logging.DEBUG, - extra_config=None): - super().setUp(extra_plugin_dir='plugins', - loglevel=logging.ERROR) +class WolframAlphaTest(IsolatedTestCase): @my_vcr.use_cassette('tests/cassettes/wa.yaml') def test_wa(self):