Skip to content

Commit

Permalink
Add ability to issue raw commands on connect (closes #120)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmaguire committed Dec 11, 2020
1 parent 096ce79 commit d326219
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 8 deletions.
1 change: 1 addition & 0 deletions cardinal.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def setup_logging(config=None):
spec.add_option('network', basestring, 'irc.freenode.net')
spec.add_option('port', int, 6667)
spec.add_option('server_password', basestring, None)
spec.add_option('server_commands', list, [])
spec.add_option('ssl', bool, False)
spec.add_option('storage', basestring, os.path.join(
os.path.dirname(os.path.realpath(sys.argv[0])),
Expand Down
10 changes: 10 additions & 0 deletions cardinal/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ def signedOn(self):
self.factory.plugins,
self.factory.blacklist)

if self.factory.server_commands:
self.logger.info("Sending server commands")
for command in self.factory.server_commands:
self.send(command)

# Attempt to identify with NickServ, if a password was given
if self.factory.password:
self.logger.info("Attempting to identify with NickServ")
Expand Down Expand Up @@ -559,6 +564,7 @@ def reactor(self):
def __init__(self,
network,
server_password=None,
server_commands=None,
channels=None,
nickname='Cardinal',
password=None,
Expand All @@ -580,6 +586,9 @@ def __init__(self,
storage -- A string containing path to storage directory.
"""

if server_commands is None:
server_commands = []

if plugins is None:
plugins = []

Expand All @@ -592,6 +601,7 @@ def __init__(self,
self.logger = logging.getLogger(__name__)
self.network = network.lower()
self.server_password = server_password
self.server_commands = server_commands
self.channels = channels
self.nickname = nickname
self.password = password
Expand Down
51 changes: 43 additions & 8 deletions cardinal/test_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

from cardinal import exceptions, plugins
from cardinal.bot import (
LOCKED,
UNLOCKED,
CardinalBot,
CardinalBotFactory,
user_info,
Expand Down Expand Up @@ -122,6 +120,7 @@ def test_signedOn_sets_bot_mode_joins_and_instantiates_plugin_manager(
channels = ['#channel1', '#channel2']

mock_factory = self.cardinal.factory = Mock()
mock_factory.server_commands = []
mock_factory.channels = channels
mock_factory.password = None

Expand Down Expand Up @@ -152,6 +151,7 @@ def test_signedOn_messages_nickserv(
mock_join,
):
mock_factory = self.cardinal.factory = Mock()
mock_factory.server_commands = []
mock_factory.channels = []
mock_factory.password = 'password'

Expand All @@ -166,6 +166,38 @@ def test_signedOn_messages_nickserv(
assert isinstance(self.cardinal.uptime, datetime)
assert self.cardinal.booted == mock_factory.booted

@patch.object(CardinalBot, 'msg')
@patch.object(CardinalBot, 'send')
@patch('cardinal.bot.PluginManager', autospec=True)
def test_signedOn_sends_server_commands(
self,
mock_plugin_manager,
mock_send,
_mock_msg,
):
command1 = 'AUTH foobar'
command2 = 'PING'

mock_factory = self.cardinal.factory = Mock()
mock_factory.nickname = 'Cardinal'
mock_factory.server_commands = [
command1,
command2,
]
mock_factory.channels = []
mock_factory.password = None

self.cardinal.signedOn()

mock_send.assert_has_calls([
call(command1),
call(command2),
call('MODE {} +B'.format(mock_factory.nickname))
])

assert isinstance(self.cardinal.uptime, datetime)
assert self.cardinal.booted == mock_factory.booted

def test_joined(self):
# this just logs, and I'm not interested in testing log messages
self.cardinal.joined('#channel')
Expand All @@ -183,7 +215,7 @@ def test_lineReceived(self, mock_parent_linereceived):

@patch('cardinal.bot.irc.IRCClient.lineReceived')
def test_lineReceived_non_utf8(self, mock_parent_linereceived):
line = b":irc-us-east-2.darkscience.net 332 Cardinal #pirates :\x031 \x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0311,10[\x031]\x03\x0311,6\x030 Pirates Game! - Welcome aboard Dark Sails, Season 4, Mod: Pauper Privateers! - \x1dJoin wit\' !Pirates\x1d - \x0311\x1fwww.piratesirc.com\x1f \x0311,6\x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2"
line = b":irc-us-east-2.darkscience.net 332 Cardinal #pirates :\x031 \x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0311,10[\x031]\x03\x0311,6\x030 Pirates Game! - Welcome aboard Dark Sails, Season 4, Mod: Pauper Privateers! - \x1dJoin wit\' !Pirates\x1d - \x0311\x1fwww.piratesirc.com\x1f \x0311,6\x0311,10[\x031]\x031,1\x1f\xc3\x82\xc2\xaf\x1f\x0313,6[\x031]\x031,1\x1f\xc3\x82\xc2" # noqa: E501
expected_line = line.decode('utf-8', 'replace')

self.cardinal.lineReceived(line)
Expand Down Expand Up @@ -566,8 +598,6 @@ def test_get_db(self):

assert len(self.cardinal.db_locks) == 1
db_path = list(self.cardinal.db_locks.keys())[0]
lock = self.cardinal.db_locks[db_path]
assert lock == UNLOCKED
assert db_path.endswith(os.path.join(
'database', 'test-{}.json'.format(network)))

Expand All @@ -580,7 +610,7 @@ def test_get_db_not_network_specific(self):
with tempdir('database') as database_path:
mock_factory.storage_path = os.path.dirname(database_path)

db = self.cardinal.get_db('test', network_specific=False)
self.cardinal.get_db('test', network_specific=False)

assert len(self.cardinal.db_locks) == 1
db_path = list(self.cardinal.db_locks.keys())[0]
Expand Down Expand Up @@ -635,7 +665,7 @@ def test_db_contextmanager_exception(self):
db = self.cardinal.get_db('test', network_specific=False)

try:
with db() as db_ob:
with db() as db_obj:
assert db_obj == {}
db_obj['x'] = True
raise Exception()
Expand Down Expand Up @@ -680,6 +710,7 @@ def test_constructor_args_defaults(self):

assert self.factory.network == 'irc.testnet.test'
assert self.factory.server_password is None
assert self.factory.server_commands == []
assert self.factory.password is None
assert self.factory.channels == []
assert self.factory.nickname == 'Cardinal'
Expand All @@ -699,7 +730,9 @@ def test_constructor_args_defaults(self):
assert self.factory.last_reconnection_wait is None

def test_constructor_args_non_default(self):
network = 'IrC.TeStNeT.TeSt'
server_password = 's3rv3r_p4ssw0rd'
server_commands = ['AUTH password', 'MODE +b foobar']
channels = ['#channel1', '#channel2']
nickname = 'Cardinal|unit-test'
password = 'p4ssw0rd'
Expand All @@ -712,8 +745,9 @@ def test_constructor_args_non_default(self):
storage = '/path/to/storage'

factory = CardinalBotFactory(
'IrC.TeStNeT.TeSt',
network,
server_password,
server_commands,
channels,
nickname,
password,
Expand All @@ -725,6 +759,7 @@ def test_constructor_args_non_default(self):
)

assert factory.network == 'irc.testnet.test'
assert factory.server_commands == server_commands
assert factory.server_password == server_password
assert factory.password == password
assert factory.channels == channels
Expand Down

0 comments on commit d326219

Please sign in to comment.