mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-01 09:19:23 +01:00
Tests for FMODE/FJOIN, and bugfixes
This commit is contained in:
parent
87781abc82
commit
2cbd6fd851
33
main.py
33
main.py
@ -8,11 +8,11 @@ import sys
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from log import log
|
from log import log
|
||||||
from conf import conf
|
import conf
|
||||||
import classes
|
import classes
|
||||||
|
|
||||||
class Irc():
|
class Irc():
|
||||||
def __init__(self, proto):
|
def __init__(self, proto, conf):
|
||||||
# Initialize some variables
|
# Initialize some variables
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.name = conf['server']['netname']
|
self.name = conf['server']['netname']
|
||||||
@ -26,21 +26,30 @@ class Irc():
|
|||||||
self.cmodes = {'op': 'o', 'secret': 's', 'private': 'p',
|
self.cmodes = {'op': 'o', 'secret': 's', 'private': 'p',
|
||||||
'noextmsg': 'n', 'moderated': 'm', 'inviteonly': 'i',
|
'noextmsg': 'n', 'moderated': 'm', 'inviteonly': 'i',
|
||||||
'topiclock': 't', 'limit': 'l', 'ban': 'b',
|
'topiclock': 't', 'limit': 'l', 'ban': 'b',
|
||||||
'voice': 'v', 'key': 'k'}
|
'voice': 'v', 'key': 'k',
|
||||||
|
# Type A, B, and C modes
|
||||||
|
'*A': 'b',
|
||||||
|
'*B': 'k',
|
||||||
|
'*C': 'l',
|
||||||
|
'*D': 'imnpstr'}
|
||||||
self.umodes = {'invisible': 'i', 'snomask': 's', 'wallops': 'w',
|
self.umodes = {'invisible': 'i', 'snomask': 's', 'wallops': 'w',
|
||||||
'oper': 'o'}
|
'oper': 'o',
|
||||||
|
'*A': '', '*B': '', '*C': 's', '*D': 'iow'}
|
||||||
self.maxnicklen = 30
|
self.maxnicklen = 30
|
||||||
|
self.prefixmodes = 'ov'
|
||||||
|
|
||||||
self.serverdata = conf['server']
|
self.serverdata = conf['server']
|
||||||
|
self.sid = self.serverdata["sid"]
|
||||||
|
self.proto = proto
|
||||||
|
self.connect()
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
ip = self.serverdata["ip"]
|
ip = self.serverdata["ip"]
|
||||||
port = self.serverdata["port"]
|
port = self.serverdata["port"]
|
||||||
self.sid = self.serverdata["sid"]
|
|
||||||
log.info("Connecting to network %r on %s:%s", self.name, ip, port)
|
log.info("Connecting to network %r on %s:%s", self.name, ip, port)
|
||||||
|
|
||||||
self.socket = socket.socket()
|
self.socket = socket.socket()
|
||||||
self.socket.connect((ip, port))
|
self.socket.connect((ip, port))
|
||||||
self.proto = proto
|
self.proto.connect(self)
|
||||||
proto.connect(self)
|
|
||||||
self.loaded = []
|
self.loaded = []
|
||||||
self.load_plugins()
|
self.load_plugins()
|
||||||
self.connected = True
|
self.connected = True
|
||||||
@ -70,7 +79,7 @@ class Irc():
|
|||||||
self.socket.send(data)
|
self.socket.send(data)
|
||||||
|
|
||||||
def load_plugins(self):
|
def load_plugins(self):
|
||||||
to_load = conf['plugins']
|
to_load = conf.conf['plugins']
|
||||||
plugins_folder = [os.path.join(os.getcwd(), 'plugins')]
|
plugins_folder = [os.path.join(os.getcwd(), 'plugins')]
|
||||||
# Here, we override the module lookup and import the plugins
|
# Here, we override the module lookup and import the plugins
|
||||||
# dynamically depending on which were configured.
|
# dynamically depending on which were configured.
|
||||||
@ -87,11 +96,11 @@ class Irc():
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
log.info('PyLink starting...')
|
log.info('PyLink starting...')
|
||||||
if conf['login']['password'] == 'changeme':
|
if conf.conf['login']['password'] == 'changeme':
|
||||||
log.critical("You have not set the login details correctly! Exiting...")
|
log.critical("You have not set the login details correctly! Exiting...")
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
protoname = conf['server']['protocol']
|
protoname = conf.conf['server']['protocol']
|
||||||
protocols_folder = [os.path.join(os.getcwd(), 'protocols')]
|
protocols_folder = [os.path.join(os.getcwd(), 'protocols')]
|
||||||
try:
|
try:
|
||||||
moduleinfo = imp.find_module(protoname, protocols_folder)
|
moduleinfo = imp.find_module(protoname, protocols_folder)
|
||||||
@ -103,4 +112,4 @@ if __name__ == '__main__':
|
|||||||
log.critical('Failed to load protocol module: import error %s', protoname, str(e))
|
log.critical('Failed to load protocol module: import error %s', protoname, str(e))
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
else:
|
else:
|
||||||
irc_obj = Irc(proto)
|
irc_obj = Irc(proto, conf.conf)
|
||||||
|
@ -8,31 +8,24 @@ import classes
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
class FakeIRC(main.Irc):
|
global testconf
|
||||||
def __init__(self, proto):
|
testconf = {'server':
|
||||||
self.connected = False
|
{'netname': 'fakeirc',
|
||||||
self.users = {}
|
|
||||||
self.channels = defaultdict(classes.IrcChannel)
|
|
||||||
self.name = 'fakeirc'
|
|
||||||
self.servers = {}
|
|
||||||
self.proto = proto
|
|
||||||
|
|
||||||
self.serverdata = {'netname': 'fakeirc',
|
|
||||||
'ip': '0.0.0.0',
|
'ip': '0.0.0.0',
|
||||||
'port': 7000,
|
'port': 7000,
|
||||||
'recvpass': "abcd",
|
'recvpass': "abcd",
|
||||||
'sendpass': "abcd",
|
'sendpass': "abcd",
|
||||||
'protocol': "testingonly",
|
'protocol': "null",
|
||||||
'hostname': "pylink.unittest",
|
'hostname': "pylink.unittest",
|
||||||
'sid': "9PY",
|
'sid': "9PY",
|
||||||
'channels': ["#pylink"],
|
'channels': ["#pylink"],
|
||||||
}
|
}
|
||||||
self.conf = {'server': self.serverdata}
|
}
|
||||||
ip = self.serverdata["ip"]
|
|
||||||
port = self.serverdata["port"]
|
class FakeIRC(main.Irc):
|
||||||
self.sid = self.serverdata["sid"]
|
def connect(self):
|
||||||
self.socket = None
|
|
||||||
self.messages = []
|
self.messages = []
|
||||||
|
self.socket = None
|
||||||
|
|
||||||
def run(self, data):
|
def run(self, data):
|
||||||
"""Queues a message to the fake IRC server."""
|
"""Queues a message to the fake IRC server."""
|
||||||
|
@ -11,7 +11,7 @@ import utils
|
|||||||
|
|
||||||
class TestInspIRCdProtocol(unittest.TestCase):
|
class TestInspIRCdProtocol(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.irc = test_proto_common.FakeIRC(inspircd)
|
self.irc = test_proto_common.FakeIRC(inspircd, test_proto_common.testconf)
|
||||||
self.proto = self.irc.proto
|
self.proto = self.irc.proto
|
||||||
self.sdata = self.irc.serverdata
|
self.sdata = self.irc.serverdata
|
||||||
# This is to initialize ourself as an internal PseudoServer, so we can spawn clients
|
# This is to initialize ourself as an internal PseudoServer, so we can spawn clients
|
||||||
@ -153,20 +153,70 @@ class TestInspIRCdProtocol(unittest.TestCase):
|
|||||||
|
|
||||||
def testHandleKill(self):
|
def testHandleKill(self):
|
||||||
self.irc.takeMsgs() # Ignore the initial connect messages
|
self.irc.takeMsgs() # Ignore the initial connect messages
|
||||||
self.irc.run(':9PYAAAAAA KILL 9PYAAAAAA :killed')
|
olduid = self.irc.pseudoclient.uid
|
||||||
|
self.irc.run(':{u} KILL {u} :killed'.format(u=olduid))
|
||||||
msgs = self.irc.takeMsgs()
|
msgs = self.irc.takeMsgs()
|
||||||
commands = self.irc.takeCommands(msgs)
|
commands = self.irc.takeCommands(msgs)
|
||||||
# Make sure we're respawning our PseudoClient when its killed
|
# Make sure we're respawning our PseudoClient when its killed
|
||||||
self.assertIn('UID', commands)
|
self.assertIn('UID', commands)
|
||||||
self.assertIn('FJOIN', commands)
|
self.assertIn('FJOIN', commands)
|
||||||
|
# Also make sure that we're updating the irc.pseudoclient field
|
||||||
|
self.assertNotEqual(self.irc.pseudoclient.uid, olduid)
|
||||||
|
|
||||||
def testHandleKick(self):
|
def testHandleKick(self):
|
||||||
self.irc.takeMsgs() # Ignore the initial connect messages
|
self.irc.takeMsgs() # Ignore the initial connect messages
|
||||||
self.irc.run(':9PYAAAAAA KICK #pylink 9PYAAAAAA :kicked')
|
self.irc.run(':{u} KICK #pylink {u} :kicked'.format(u=self.irc.pseudoclient.uid))
|
||||||
# Ditto above
|
# Ditto above
|
||||||
msgs = self.irc.takeMsgs()
|
msgs = self.irc.takeMsgs()
|
||||||
commands = self.irc.takeCommands(msgs)
|
commands = self.irc.takeCommands(msgs)
|
||||||
self.assertIn('FJOIN', commands)
|
self.assertIn('FJOIN', commands)
|
||||||
|
|
||||||
|
def testHandleFjoinUsers(self):
|
||||||
|
self.irc.run(':70M FJOIN #Chat 1423790411 + :,10XAAAAAA ,10XAAAAAB')
|
||||||
|
self.assertEqual({'10XAAAAAA', '10XAAAAAB'}, self.irc.channels['#chat'].users)
|
||||||
|
# self.assertIn('10XAAAAAB', self.irc.channels['#chat'].users)
|
||||||
|
# Sequential FJOINs must NOT remove existing users
|
||||||
|
self.irc.run(':70M FJOIN #Chat 1423790412 + :,10XAAAAAC')
|
||||||
|
# Join list can be empty too, in the case of permanent channels with 0 users.
|
||||||
|
self.irc.run(':70M FJOIN #Chat 1423790413 +nt :')
|
||||||
|
|
||||||
|
def testHandleFjoinModes(self):
|
||||||
|
self.irc.run(':70M FJOIN #Chat 1423790411 +nt :,10XAAAAAA ,10XAAAAAB')
|
||||||
|
self.assertEqual({('+n', None), ('+t', None)}, self.irc.channels['#chat'].modes)
|
||||||
|
# Sequential FJOINs must NOT remove existing modes
|
||||||
|
self.irc.run(':70M FJOIN #Chat 1423790412 + :,10XAAAAAC')
|
||||||
|
self.assertEqual({('+n', None), ('+t', None)}, self.irc.channels['#chat'].modes)
|
||||||
|
|
||||||
|
def testHandleFjoinModesWithArgs(self):
|
||||||
|
self.irc.run(':70M FJOIN #Chat 1423790414 +nlks 10 t0psekrit :,10XAAAAAA ,10XAAAAAB')
|
||||||
|
self.assertEqual({('+n', None), ('+s', None), ('+l', '10'), ('+k', 't0psekrit')},
|
||||||
|
self.irc.channels['#chat'].modes)
|
||||||
|
|
||||||
|
def testHandleFjoinPrefixes(self):
|
||||||
|
self.irc.run(':70M FJOIN #Chat 1423790418 +nt :ov,10XAAAAAA v,10XAAAAAB ,10XAAAAAC')
|
||||||
|
self.assertEqual({('+n', None), ('+t', None)}, self.irc.channels['#chat'].modes)
|
||||||
|
self.assertEqual({'10XAAAAAA', '10XAAAAAB', '10XAAAAAC'}, self.irc.channels['#chat'].users)
|
||||||
|
self.assertIn('10XAAAAAA', self.irc.channels['#chat'].prefixmodes['ops'])
|
||||||
|
self.assertEqual({'10XAAAAAA', '10XAAAAAB'}, self.irc.channels['#chat'].prefixmodes['voices'])
|
||||||
|
|
||||||
|
def testHandleFmode(self):
|
||||||
|
self.irc.run(':70M FJOIN #pylink 1423790411 +n :o,10XAAAAAA ,10XAAAAAB')
|
||||||
|
self.irc.run(':70M FMODE #pylink 1423790412 +ikl herebedragons 100')
|
||||||
|
self.assertEqual({('+i', None), ('+k', 'herebedragons'), ('+l', '100'), ('+n', None)}, self.irc.channels['#pylink'].modes)
|
||||||
|
self.irc.run(':70M FMODE #pylink 1423790413 -ilk+m herebedragons')
|
||||||
|
self.assertEqual({('+m', None), ('+n', None)}, self.irc.channels['#pylink'].modes)
|
||||||
|
|
||||||
|
def testHandleFmodeWithPrefixes(self):
|
||||||
|
self.irc.run(':70M FJOIN #pylink 1423790411 +n :o,10XAAAAAA ,10XAAAAAB')
|
||||||
|
# Prefix modes are stored separately, so they should never show up in .modes
|
||||||
|
self.assertNotIn(('+o', '10XAAAAAA'), self.irc.channels['#pylink'].modes)
|
||||||
|
self.assertEqual({'10XAAAAAA'}, self.irc.channels['#pylink'].prefixmodes['ops'])
|
||||||
|
self.irc.run(':70M FMODE #pylink 1423790412 +lot 50 %s' % self.u)
|
||||||
|
self.assertIn(self.u, self.irc.channels['#pylink'].prefixmodes['ops'])
|
||||||
|
modes = {('+l', '50'), ('+n', None), ('+t', None)}
|
||||||
|
self.assertEqual(modes, self.irc.channels['#pylink'].modes)
|
||||||
|
self.irc.run(':70M FMODE #pylink 1423790413 -o %s' % self.u)
|
||||||
|
self.assertEqual(modes, self.irc.channels['#pylink'].modes)
|
||||||
|
self.assertNotIn(self.u, self.irc.channels['#pylink'].prefixmodes['ops'])
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
15
utils.py
15
utils.py
@ -111,6 +111,7 @@ def parseModes(irc, target, args):
|
|||||||
prefix = mode
|
prefix = mode
|
||||||
else:
|
else:
|
||||||
arg = None
|
arg = None
|
||||||
|
log.debug('Current mode: %s%s; args left: %s', prefix, mode, args)
|
||||||
if mode in (supported_modes['*A'] + supported_modes['*B']):
|
if mode in (supported_modes['*A'] + supported_modes['*B']):
|
||||||
# Must have parameter.
|
# Must have parameter.
|
||||||
log.debug('Mode %s: This mode must have parameter.', mode)
|
log.debug('Mode %s: This mode must have parameter.', mode)
|
||||||
@ -150,16 +151,24 @@ def applyModes(irc, target, changedmodes):
|
|||||||
log.debug('(%s) Final prefixmodes list: %s', irc.name, irc.channels[target].prefixmodes)
|
log.debug('(%s) Final prefixmodes list: %s', irc.name, irc.channels[target].prefixmodes)
|
||||||
if mode[0][1] in irc.prefixmodes:
|
if mode[0][1] in irc.prefixmodes:
|
||||||
# Ignore other prefix modes such as InspIRCd's +Yy
|
# Ignore other prefix modes such as InspIRCd's +Yy
|
||||||
|
log.debug('(%s) Not adding mode %s to IrcChannel.modes because it\'s a prefix mode', irc.name, str(mode))
|
||||||
continue
|
continue
|
||||||
if mode[0][0] == '+':
|
if mode[0][0] == '+':
|
||||||
# We're adding a mode
|
# We're adding a mode
|
||||||
modelist.add(mode)
|
modelist.add(mode)
|
||||||
log.debug('(%s) Adding mode %r on %s', irc.name, mode, target)
|
log.debug('(%s) Adding mode %r on %s', irc.name, mode, target)
|
||||||
else:
|
else:
|
||||||
# We're removing a mode
|
|
||||||
mode[0] = mode[0].replace('-', '+')
|
|
||||||
modelist.discard(mode)
|
|
||||||
log.debug('(%s) Removing mode %r on %s', irc.name, mode, target)
|
log.debug('(%s) Removing mode %r on %s', irc.name, mode, target)
|
||||||
|
# We're removing a mode
|
||||||
|
if mode[1] is None:
|
||||||
|
# We're removing a mode that only takes arguments when setting.
|
||||||
|
for oldmode in modelist.copy():
|
||||||
|
if oldmode[0][1] == mode[0][1]:
|
||||||
|
modelist.discard(oldmode)
|
||||||
|
else:
|
||||||
|
# Swap the - for a + and then remove it from the list.
|
||||||
|
mode = ('+' + mode[0][1], mode[1])
|
||||||
|
modelist.discard(mode)
|
||||||
log.debug('(%s) Final modelist: %s', irc.name, modelist)
|
log.debug('(%s) Final modelist: %s', irc.name, modelist)
|
||||||
|
|
||||||
def joinModes(modes):
|
def joinModes(modes):
|
||||||
|
Loading…
Reference in New Issue
Block a user