More tests
This commit is contained in:
parent
585efb2c18
commit
e8652c37c8
@ -31,6 +31,8 @@ class IRCCore(object):
|
||||
self.rate_max = float(rate_max)
|
||||
self.rate_int = float(rate_int)
|
||||
|
||||
self.reconnect_delay = 3.0
|
||||
|
||||
self.connected = False
|
||||
"""If we're connected or not"""
|
||||
|
||||
@ -60,7 +62,7 @@ class IRCCore(object):
|
||||
self.initHooks()
|
||||
|
||||
self.outputq = asyncio.Queue()
|
||||
self._loop.call_soon(asyncio.ensure_future, self.outputqueue())
|
||||
self._loop.call_soon_threadsafe(asyncio.ensure_future, self.outputqueue())
|
||||
|
||||
async def loop(self, loop):
|
||||
while self.alive:
|
||||
@ -94,8 +96,8 @@ class IRCCore(object):
|
||||
self.writer.close()
|
||||
if self.alive:
|
||||
# TODO ramp down reconnect attempts
|
||||
logging.info("Reconnecting in 3s...")
|
||||
await asyncio.sleep(3)
|
||||
logging.info("Reconnecting in {}s...".format(self.reconnect_delay))
|
||||
await asyncio.sleep(self.reconnect_delay)
|
||||
|
||||
async def outputqueue(self):
|
||||
bucket = burstbucket(self.rate_max, self.rate_int)
|
||||
|
@ -13,7 +13,7 @@ from .common import load as pload
|
||||
from .common import messageHasCommand
|
||||
|
||||
|
||||
class ModuleBase:
|
||||
class ModuleBase(object):
|
||||
"""All modules will extend this class
|
||||
|
||||
:param bot: A reference to the main bot passed when this module is created
|
||||
|
@ -198,7 +198,7 @@ class Remind(ModuleBase):
|
||||
else:
|
||||
return zonestr
|
||||
|
||||
@info("after <duration> have the bot remind after", cmds=["after", "in"])
|
||||
@info("after <duration> <reminder> have the bot remind after", cmds=["after", "in"])
|
||||
@command("after", "in", allow_private=True)
|
||||
def remindin(self, msg, cmd):
|
||||
replyTo = msg.args[0]
|
||||
|
@ -64,13 +64,7 @@ class Connection:
|
||||
c = self.connection.cursor()
|
||||
return c
|
||||
|
||||
def escape(self, s):
|
||||
raise NotImplementedError
|
||||
|
||||
def ondisable(self):
|
||||
self.connection.close()
|
||||
|
||||
# Connects to the database server, and selects a database (Or attempts to create it if it doesn't exist yet)
|
||||
# Opens the sqlite database / attempts to create it if it doesn't exist yet
|
||||
def _connect(self):
|
||||
self.log.info("Sqlite: opening database %s" % self.master.getFilePath(self.dbname))
|
||||
self.connection = sqlite3.connect(self.master.getFilePath(self.dbname), check_same_thread=False)
|
||||
|
@ -1,3 +1,4 @@
|
||||
apipkg==1.4
|
||||
appdirs==1.4.3
|
||||
certifi==2017.4.17
|
||||
chardet==3.0.4
|
||||
@ -5,6 +6,7 @@ cheroot==5.9.1
|
||||
CherryPy==12.0.1
|
||||
coverage==4.4.2
|
||||
decorator==4.0.11
|
||||
execnet==1.5.0
|
||||
idna==2.5
|
||||
ipdb==0.10.3
|
||||
ipython==6.0.0
|
||||
@ -30,6 +32,8 @@ pyparsing==2.2.0
|
||||
PySocks==1.6.7
|
||||
pytest==3.2.5
|
||||
pytest-cov==2.5.1
|
||||
pytest-forked==0.2
|
||||
pytest-xdist==1.20.1
|
||||
pytz==2017.3
|
||||
pyzmq==16.0.2
|
||||
requests==2.18.1
|
||||
|
@ -3,4 +3,4 @@
|
||||
export PYTHONUNBUFFERED=1
|
||||
export PYTHONPATH=.
|
||||
|
||||
py.test --cov=pyircbot --cov-report html tests/
|
||||
py.test --cov=pyircbot --cov-report html -n 4 tests/
|
||||
|
89
tests/lib.py
89
tests/lib.py
@ -1,8 +1,9 @@
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
from random import randint
|
||||
from threading import Thread
|
||||
from random import randint
|
||||
from pyircbot import PyIRCBot
|
||||
from pyircbot.pyircbot import PrimitiveBot
|
||||
from pyircbot.irccore import IRCEvent, UserPrefix
|
||||
from unittest.mock import MagicMock
|
||||
@ -20,6 +21,7 @@ class FakeBaseBot(PrimitiveBot):
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
self.act_PRIVMSG = MagicMock()
|
||||
self._modules = []
|
||||
|
||||
def feed_line(self, trailing, cmd="PRIVMSG", args=["#test"], sender=("chatter", "root", "cia.gov")):
|
||||
"""
|
||||
@ -36,13 +38,27 @@ class FakeBaseBot(PrimitiveBot):
|
||||
if validation:
|
||||
hook.method(msg, validation)
|
||||
|
||||
def closeAllModules(self):
|
||||
for modname in self._modules:
|
||||
self.unloadmodule(modname)
|
||||
|
||||
def loadmodule(self, module_name):
|
||||
super().loadmodule(module_name)
|
||||
self._modules.append(module_name)
|
||||
|
||||
def unloadmodule(self, module_name):
|
||||
super().unloadmodule(module_name)
|
||||
self._modules.remove(module_name)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fakebot():
|
||||
def fakebot(tmpdir):
|
||||
# TODO copy data tree to isolated place so each fakebot() is isolated
|
||||
bot = FakeBaseBot({"bot": {"datadir": "./examples/data/"},
|
||||
os.mkdir(os.path.join(tmpdir, "data"))
|
||||
bot = FakeBaseBot({"bot": {"datadir": tmpdir},
|
||||
"module_configs": {}})
|
||||
yield bot
|
||||
bot.closeAllModules()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -79,3 +95,70 @@ def ircserver():
|
||||
server_t.start()
|
||||
yield port, server
|
||||
server.stop()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def livebot(ircserver, tmpdir):
|
||||
port, server = ircserver
|
||||
channel = "#test" + str(randint(100000, 1000000))
|
||||
nick = "testbot" + str(randint(100000, 1000000))
|
||||
config = {
|
||||
"bot": {
|
||||
"datadir": tmpdir,
|
||||
"rpcbind": "0.0.0.0",
|
||||
"rpcport": -1,
|
||||
"usermodules": []
|
||||
},
|
||||
"connection": {
|
||||
"servers": [
|
||||
["localhost", port]
|
||||
],
|
||||
"force_ipv6": False,
|
||||
"rate_limit": {
|
||||
"rate_max": 5.0,
|
||||
"rate_int": 1.1
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"PingResponder",
|
||||
"Services"
|
||||
],
|
||||
"module_configs": {
|
||||
"Services": {
|
||||
"user": {
|
||||
"nick": [
|
||||
nick,
|
||||
nick + "_",
|
||||
nick + "__"
|
||||
],
|
||||
"password": "nickservpassword",
|
||||
"username": "pyircbot3",
|
||||
"hostname": "pyircbot3.domain.com",
|
||||
"realname": "pyircbot3"
|
||||
},
|
||||
"ident": {
|
||||
"enable": "no",
|
||||
"to": "nickserv",
|
||||
"command": "identify %(password)s",
|
||||
"ghost": "no",
|
||||
"ghost_to": "nickserv",
|
||||
"ghost_cmd": "ghost %(nick)s %(password)s"
|
||||
},
|
||||
"channels": [
|
||||
channel
|
||||
],
|
||||
"privatechannels": {
|
||||
"to": "chanserv",
|
||||
"command": "invite %(channel)s",
|
||||
"list": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bot = PyIRCBot(config)
|
||||
bot_t = Thread(target=bot.run, daemon=True)
|
||||
# bot_t.start()
|
||||
yield port, server, bot, bot_t, channel, nick
|
||||
|
||||
bot.kill(message="bye", forever=True)
|
||||
|
@ -1,9 +1,20 @@
|
||||
import os
|
||||
import pytest
|
||||
from tests.lib import * # NOQA - fixtures
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def bot(fakebot):
|
||||
fakebot.botconfig["module_configs"]["ASCII"] = {
|
||||
"line_delay": 1.1,
|
||||
"allow_parallel": False,
|
||||
"allow_hilight": True,
|
||||
"list_max": 15
|
||||
}
|
||||
adir = os.path.join(fakebot.botconfig["bot"]["datadir"], "data", "ASCII")
|
||||
os.makedirs(adir, exist_ok=True)
|
||||
with open(os.path.join(adir, "test.txt"), "w") as f:
|
||||
f.write("hello world!")
|
||||
fakebot.loadmodule("ASCII")
|
||||
return fakebot
|
||||
|
||||
@ -11,3 +22,8 @@ def bot(fakebot):
|
||||
def test_ascii(bot):
|
||||
bot.feed_line(".ascii test")
|
||||
bot.act_PRIVMSG.assert_called_once_with('#test', 'hello world!')
|
||||
|
||||
|
||||
def test_listascii(bot):
|
||||
bot.feed_line(".listascii")
|
||||
bot.act_PRIVMSG.assert_called_once_with('#test', 'Avalable asciis: test')
|
||||
|
@ -15,13 +15,13 @@ def calcbot(fakebot):
|
||||
"delayCalcSpecific": 0,
|
||||
"delayMatch": 0}
|
||||
fakebot.loadmodule("SQLite")
|
||||
tables = ["calc_addedby", "calc_channels", "calc_definitions", "calc_words"]
|
||||
with closing(fakebot.moduleInstances["SQLite"].opendb("calc.db")) as db:
|
||||
for q in ["DROP TABLE calc_addedby;",
|
||||
"DROP TABLE calc_channels;",
|
||||
"DROP TABLE calc_definitions;",
|
||||
"DROP TABLE calc_words;"]:
|
||||
db.query(q)
|
||||
for t in tables:
|
||||
db.query("DROP TABLE IF EXISTS `{}`;".format(t))
|
||||
fakebot.loadmodule("Calc")
|
||||
for t in tables:
|
||||
assert fakebot.moduleInstances["Calc"].sql.tableExists("calc_addedby")
|
||||
return fakebot
|
||||
|
||||
|
||||
|
@ -19,10 +19,8 @@ def nickbot(fakebot):
|
||||
"delayMatch": 0}
|
||||
fakebot.loadmodule("SQLite")
|
||||
with closing(fakebot.moduleInstances["SQLite"].opendb("attributes.db")) as db:
|
||||
for q in ["DROP TABLE attribute;",
|
||||
"DROP TABLE items;",
|
||||
"DROP TABLE `values`;"]:
|
||||
db.query(q)
|
||||
for table in ["attribute", "items", "values"]:
|
||||
db.query("DROP TABLE IF EXISTS `{}`;".format(table))
|
||||
fakebot.loadmodule("AttributeStorageLite")
|
||||
fakebot.loadmodule("NickUser")
|
||||
return fakebot
|
||||
@ -37,7 +35,15 @@ def test_blind_login(nickbot):
|
||||
nickbot.act_PRIVMSG.assert_called_once_with('chatter', '.login: You must first set a password with .setpass')
|
||||
|
||||
|
||||
def test_no_pms(nickbot):
|
||||
nickbot.feed_line(".login foobar")
|
||||
nickbot.act_PRIVMSG.assert_not_called()
|
||||
|
||||
|
||||
def test_register(nickbot):
|
||||
pm(nickbot, ".setpass")
|
||||
nickbot.act_PRIVMSG.assert_called_once_with('chatter', '.setpass: usage: ".setpass newpass" or ".setpass oldpass newpass"')
|
||||
nickbot.act_PRIVMSG.reset_mock()
|
||||
pm(nickbot, ".setpass foobar")
|
||||
nickbot.act_PRIVMSG.assert_called_once_with('chatter', '.setpass: Your password has been set to "foobar".')
|
||||
nickbot.act_PRIVMSG.reset_mock()
|
||||
@ -45,6 +51,9 @@ def test_register(nickbot):
|
||||
|
||||
def test_register_login(nickbot):
|
||||
test_register(nickbot)
|
||||
pm(nickbot, ".login")
|
||||
nickbot.act_PRIVMSG.assert_called_once_with('chatter', '.login: usage: ".login password"')
|
||||
nickbot.act_PRIVMSG.reset_mock()
|
||||
pm(nickbot, ".login foobar")
|
||||
nickbot.act_PRIVMSG.assert_called_once_with('chatter', '.login: You have been logged in from: cia.gov')
|
||||
nickbot.act_PRIVMSG.reset_mock()
|
||||
|
41
tests/modules/test_remind.py
Normal file
41
tests/modules/test_remind.py
Normal file
@ -0,0 +1,41 @@
|
||||
import pytest
|
||||
from contextlib import closing
|
||||
from tests.lib import * # NOQA - fixtures
|
||||
from time import sleep
|
||||
import datetime
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def rbot(fakebot):
|
||||
"""
|
||||
Provide a bot loaded with the Calc module. Clear the database.
|
||||
"""
|
||||
fakebot.botconfig["module_configs"]["Remind"] = {"mytimezone": "US/Pacific", "precision": 0.2}
|
||||
fakebot.loadmodule("SQLite")
|
||||
with closing(fakebot.moduleInstances["SQLite"].opendb("remind.db")) as db:
|
||||
db.query("DROP TABLE IF EXISTS `reminders`;")
|
||||
fakebot.loadmodule("Remind")
|
||||
return fakebot
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_remind_in(rbot):
|
||||
rbot.feed_line(".in 3s frig off")
|
||||
rbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: Ok, talk to you in approx 0h0m')
|
||||
rbot.act_PRIVMSG.reset_mock()
|
||||
sleep(2.5)
|
||||
rbot.act_PRIVMSG.assert_not_called()
|
||||
sleep(1)
|
||||
rbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: Reminder: frig off')
|
||||
|
||||
|
||||
@pytest.mark.slow
|
||||
def test_remind_at(rbot):
|
||||
then = datetime.datetime.now() + datetime.timedelta(seconds=3)
|
||||
rbot.feed_line(".at {} frig off".format(then.strftime("%H:%M:%SPDT")))
|
||||
rbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: Ok, will do. Approx 0h0m to go.')
|
||||
rbot.act_PRIVMSG.reset_mock()
|
||||
sleep(2)
|
||||
rbot.act_PRIVMSG.assert_not_called()
|
||||
sleep(2)
|
||||
rbot.act_PRIVMSG.assert_called_once_with('#test', 'chatter: Reminder: frig off')
|
@ -11,7 +11,7 @@ def tellbot(fakebot):
|
||||
fakebot.botconfig["module_configs"]["Tell"] = {"max": 10, "maxage": 2678400}
|
||||
fakebot.loadmodule("SQLite")
|
||||
with closing(fakebot.moduleInstances["SQLite"].opendb("tell.db")) as db:
|
||||
db.query("DROP TABLE tells;")
|
||||
db.query("DROP TABLE IF EXISTS tells;")
|
||||
fakebot.loadmodule("Tell")
|
||||
return fakebot
|
||||
|
||||
|
87
tests/test_rpcclient.py
Normal file
87
tests/test_rpcclient.py
Normal file
@ -0,0 +1,87 @@
|
||||
from tests.lib import * # NOQA - fixtures
|
||||
|
||||
from unittest.mock import MagicMock, call
|
||||
from pyircbot.rpc import BotRPC
|
||||
from pyircbot.rpcclient import connect
|
||||
from random import randint
|
||||
from time import sleep
|
||||
|
||||
|
||||
def test_rpc(monkeypatch):
|
||||
port = randint(40000, 65000)
|
||||
m = MagicMock()
|
||||
m.botconfig = {"bot": {"rpcbind": "127.0.0.1", "rpcport": port}}
|
||||
server = BotRPC(m)
|
||||
sleep(0.05)
|
||||
|
||||
calltrack = MagicMock()
|
||||
|
||||
def fake(*args):
|
||||
calltrack(*args)
|
||||
return args
|
||||
|
||||
for k, v in server.server.funcs.items():
|
||||
server.server.funcs[k] = fake
|
||||
|
||||
methods = [["importModule", "foo"],
|
||||
["deportModule", "foo"],
|
||||
["loadModule", "foo"],
|
||||
["unloadModule", "foo"],
|
||||
["reloadModule", "foo"],
|
||||
["redoModule", "foo"],
|
||||
["getLoadedModules"],
|
||||
["pluginCommand", "foo", "foo", "foo"],
|
||||
["setPluginVar", "foo", "foo"],
|
||||
["getPluginVar", "foo", "foo", "foo"],
|
||||
["eval", "foo"],
|
||||
["exec", "foo"],
|
||||
["quit", "foo"]]
|
||||
|
||||
client = connect("127.0.0.1", port)
|
||||
|
||||
for test in methods:
|
||||
method = test[0]
|
||||
args = test[1:]
|
||||
server.server.funcs[method] = fake
|
||||
print("Calling {} with: {}".format(method, args))
|
||||
getattr(client, method)(*args)
|
||||
calltrack.assert_called_once_with(*args)
|
||||
calltrack.reset_mock()
|
||||
|
||||
|
||||
def test_rpc_internal(monkeypatch):
|
||||
port = randint(40000, 65000)
|
||||
m = MagicMock()
|
||||
m.botconfig = {"bot": {"rpcbind": "127.0.0.1", "rpcport": port}}
|
||||
server = BotRPC(m)
|
||||
|
||||
methods = [["importModule", "foo"],
|
||||
["deportModule", "foo"],
|
||||
["loadModule", "foo"],
|
||||
["unloadModule", "foo"],
|
||||
["redoModule", "foo"],]
|
||||
|
||||
for test in methods:
|
||||
method = test[0]
|
||||
args = test[1:]
|
||||
getattr(server, method)(*args)
|
||||
getattr(m, method.lower()).assert_called_once_with(*args)
|
||||
getattr(m, method.lower()).reset_mock()
|
||||
|
||||
m.moduleInstances = {"Foo": None, "Bar": None}
|
||||
assert server.getLoadedModules() == ["Foo", "Bar"]
|
||||
|
||||
m.reset_mock()
|
||||
|
||||
server.reloadModule("Foo")
|
||||
m.unloadmodule.assert_called_once_with("Foo")
|
||||
m.loadmodule.assert_called_once_with("Foo")
|
||||
|
||||
m.reset_mock()
|
||||
|
||||
# ["pluginCommand", "foo", "foo", "foo"],
|
||||
# ["setPluginVar", "foo", "foo"],
|
||||
# ["getPluginVar", "foo", "foo", "foo"]
|
||||
# ["eval", "foo"],
|
||||
# ["exec", "foo"],
|
||||
# ["quit", "foo"]]
|
Loading…
Reference in New Issue
Block a user