mirror of
https://github.com/progval/irctest.git
synced 2025-04-07 15:59:49 +00:00
@ -1,5 +1,4 @@
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
from irctest.basecontrollers import NotImplementedByController
|
||||
@ -52,6 +51,7 @@ accounts:
|
||||
enabled-callbacks:
|
||||
- none # no verification needed, will instantly register successfully
|
||||
allow-multiple-per-connection: true
|
||||
bcrypt-cost: 4
|
||||
|
||||
authentication-enabled: true
|
||||
|
||||
|
@ -3,8 +3,6 @@
|
||||
"""
|
||||
|
||||
from irctest import cases
|
||||
from irctest.client_mock import NoMessageException
|
||||
from irctest.basecontrollers import NotImplementedByController
|
||||
|
||||
class AccountTagTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
|
||||
def connectRegisteredClient(self, nick):
|
||||
|
@ -1,5 +1,4 @@
|
||||
from irctest import cases
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
|
||||
class CapTestCase(cases.BaseServerTestCase):
|
||||
@cases.SpecificationSelector.requiredBySpecification('IRCv3.1')
|
||||
@ -96,3 +95,33 @@ class CapTestCase(cases.BaseServerTestCase):
|
||||
subcommand='ACK', subparams=['multi-prefix'],
|
||||
fail_msg='Expected “CAP ACK :multi-prefix” after '
|
||||
'sending “CAP REQ :multi-prefix”, but got {msg}.')
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('Oragono')
|
||||
def testCapRemovalByClient(self):
|
||||
"""Test CAP LIST and removal of caps via CAP REQ :-tagname."""
|
||||
self.addClient(1)
|
||||
self.sendLine(1, 'CAP LS 302')
|
||||
self.assertIn('multi-prefix', self.getCapLs(1))
|
||||
self.sendLine(1, 'CAP REQ :echo-message server-time')
|
||||
self.sendLine(1, 'nick bar')
|
||||
self.sendLine(1, 'user user 0 * realname')
|
||||
self.sendLine(1, 'CAP END')
|
||||
self.skipToWelcome(1)
|
||||
self.getMessages(1)
|
||||
|
||||
self.sendLine(1, 'CAP LIST')
|
||||
messages = self.getMessages(1)
|
||||
cap_list = [m for m in messages if m.command == 'CAP'][0]
|
||||
self.assertEqual(set(cap_list.params[2].split()), {'echo-message', 'server-time'})
|
||||
self.assertIn('time', cap_list.tags)
|
||||
|
||||
# remove the server-time cap
|
||||
self.sendLine(1, 'CAP REQ :-server-time')
|
||||
self.getMessages(1)
|
||||
|
||||
# server-time should be disabled
|
||||
self.sendLine(1, 'CAP LIST')
|
||||
messages = self.getMessages(1)
|
||||
cap_list = [m for m in messages if m.command == 'CAP'][0]
|
||||
self.assertEqual(set(cap_list.params[2].split()), {'echo-message'})
|
||||
self.assertNotIn('time', cap_list.tags)
|
||||
|
@ -7,7 +7,13 @@ from irctest import cases
|
||||
from irctest import client_mock
|
||||
from irctest import runner
|
||||
from irctest.irc_utils import ambiguities
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
|
||||
RPL_NOTOPIC = '331'
|
||||
RPL_NAMREPLY = '353'
|
||||
|
||||
ERR_NOSUCHCHANNEL = '403'
|
||||
ERR_NOTONCHANNEL = '442'
|
||||
ERR_CHANOPRIVSNEEDED = '482'
|
||||
|
||||
class JoinTestCase(cases.BaseServerTestCase):
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812',
|
||||
@ -228,6 +234,42 @@ class JoinTestCase(cases.BaseServerTestCase):
|
||||
# either 403 ERR_NOSUCHCHANNEL or 443 ERR_NOTONCHANNEL
|
||||
self.assertIn(m.command, ('403', '443'))
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC2812')
|
||||
def testUnsetTopicResponses(self):
|
||||
"""Test various cases related to RPL_NOTOPIC with set and unset topics."""
|
||||
self.connectClient('bar')
|
||||
self.sendLine(1, 'JOIN #test')
|
||||
messages = self.getMessages(1)
|
||||
# shouldn't send RPL_NOTOPIC for a new channel
|
||||
self.assertNotIn(RPL_NOTOPIC, [m.command for m in messages])
|
||||
|
||||
self.connectClient('baz')
|
||||
self.sendLine(2, 'JOIN #test')
|
||||
messages = self.getMessages(2)
|
||||
# topic is still unset, shouldn't send RPL_NOTOPIC on initial join
|
||||
self.assertNotIn(RPL_NOTOPIC, [m.command for m in messages])
|
||||
|
||||
self.sendLine(2, 'TOPIC #test')
|
||||
messages = self.getMessages(2)
|
||||
# explicit TOPIC should receive RPL_NOTOPIC
|
||||
self.assertIn(RPL_NOTOPIC, [m.command for m in messages])
|
||||
|
||||
self.sendLine(1, 'TOPIC #test :new topic')
|
||||
self.getMessages(1)
|
||||
# client 2 should get the new TOPIC line
|
||||
messages = [message for message in self.getMessages(2) if message.command == 'TOPIC']
|
||||
self.assertEqual(len(messages), 1)
|
||||
self.assertEqual(messages[0].params, ['#test', 'new topic'])
|
||||
|
||||
# unset the topic:
|
||||
self.sendLine(1, 'TOPIC #test :')
|
||||
self.getMessages(1)
|
||||
self.connectClient('qux')
|
||||
self.sendLine(3, 'join #test')
|
||||
messages = self.getMessages(3)
|
||||
# topic is once again unset, shouldn't send RPL_NOTOPIC on initial join
|
||||
self.assertNotIn(RPL_NOTOPIC, [m.command for m in messages])
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812')
|
||||
def testListEmpty(self):
|
||||
"""<https://tools.ietf.org/html/rfc1459#section-4.2.6>
|
||||
@ -296,8 +338,6 @@ class JoinTestCase(cases.BaseServerTestCase):
|
||||
|
||||
# TODO: check foo is an operator
|
||||
|
||||
import time
|
||||
time.sleep(0.1)
|
||||
self.getMessages(1)
|
||||
self.getMessages(2)
|
||||
self.getMessages(3)
|
||||
@ -318,6 +358,52 @@ class JoinTestCase(cases.BaseServerTestCase):
|
||||
self.assertMessageEqual(m, command='KICK',
|
||||
params=['#chan', 'bar', 'bye'])
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC2812')
|
||||
def testKickPrivileges(self):
|
||||
"""Test who has the ability to kick / what error codes are sent for invalid kicks."""
|
||||
self.connectClient('foo')
|
||||
self.sendLine(1, 'JOIN #chan')
|
||||
self.getMessages(1)
|
||||
|
||||
self.connectClient('bar')
|
||||
self.sendLine(2, 'JOIN #chan')
|
||||
|
||||
messages = self.getMessages(2)
|
||||
names = set()
|
||||
for message in messages:
|
||||
if message.command == RPL_NAMREPLY:
|
||||
names.update(set(message.params[-1].split()))
|
||||
# assert foo is opped
|
||||
self.assertIn('@foo', names, f'unexpected names: {names}')
|
||||
|
||||
self.connectClient('baz')
|
||||
|
||||
self.sendLine(3, 'KICK #chan bar')
|
||||
replies = set(m.command for m in self.getMessages(3))
|
||||
self.assertTrue(
|
||||
ERR_NOTONCHANNEL in replies or ERR_CHANOPRIVSNEEDED in replies or ERR_NOSUCHCHANNEL in replies,
|
||||
f'did not receive acceptable error code for kick from outside channel: {replies}')
|
||||
|
||||
self.joinChannel(3, '#chan')
|
||||
self.getMessages(3)
|
||||
self.sendLine(3, 'KICK #chan bar')
|
||||
replies = set(m.command for m in self.getMessages(3))
|
||||
# now we're a channel member so we should receive ERR_CHANOPRIVSNEEDED
|
||||
self.assertIn(ERR_CHANOPRIVSNEEDED, replies)
|
||||
|
||||
self.sendLine(1, 'MODE #chan +o baz')
|
||||
self.getMessages(1)
|
||||
# should be able to kick an unprivileged user:
|
||||
self.sendLine(3, 'KICK #chan bar')
|
||||
# should be able to kick an operator:
|
||||
self.sendLine(3, 'KICK #chan foo')
|
||||
baz_replies = set(m.command for m in self.getMessages(3))
|
||||
self.assertNotIn(ERR_CHANOPRIVSNEEDED, baz_replies)
|
||||
kick_targets = [m.params[1] for m in self.getMessages(1) if m.command == 'KICK']
|
||||
# foo should see bar and foo being kicked
|
||||
self.assertTrue(any(target.startswith('foo') for target in kick_targets), f'unexpected kick targets: {kick_targets}')
|
||||
self.assertTrue(any(target.startswith('bar') for target in kick_targets), f'unexpected kick targets: {kick_targets}')
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC2812')
|
||||
def testKickNonexistentChannel(self):
|
||||
"""“Kick command [...] Numeric replies: [...] ERR_NOSUCHCHANNEL."""
|
||||
@ -519,3 +605,26 @@ class InviteTestCase(cases.BaseServerTestCase):
|
||||
|
||||
# we were invited, so join should succeed now
|
||||
self.joinChannel(2, '#chan')
|
||||
|
||||
|
||||
class ChannelQuitTestCase(cases.BaseServerTestCase):
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC2812')
|
||||
def testQuit(self):
|
||||
"""“Once a user has joined a channel, he receives information about
|
||||
all commands his server receives affecting the channel. This
|
||||
includes [...] QUIT”
|
||||
<https://tools.ietf.org/html/rfc2812#section-3.2.1>
|
||||
"""
|
||||
self.connectClient('bar')
|
||||
self.joinChannel(1, '#chan')
|
||||
self.connectClient('qux')
|
||||
self.sendLine(2, 'JOIN #chan')
|
||||
|
||||
self.getMessages(1)
|
||||
self.sendLine(2, 'QUIT :qux out')
|
||||
self.getMessages(2)
|
||||
m = self.getMessage(1)
|
||||
self.assertEqual(m.command, 'QUIT')
|
||||
self.assertTrue(m.prefix.startswith('qux')) # nickmask of quitter
|
||||
self.assertIn('qux out', m.params[0])
|
||||
|
@ -4,9 +4,6 @@ Tests section 4.1 of RFC 1459.
|
||||
"""
|
||||
|
||||
from irctest import cases
|
||||
from irctest import authentication
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
from irctest.basecontrollers import NotImplementedByController
|
||||
from irctest.client_mock import ConnectionClosed
|
||||
|
||||
class PasswordedConnectionRegistrationTestCase(cases.BaseServerTestCase):
|
||||
@ -31,6 +28,16 @@ class PasswordedConnectionRegistrationTestCase(cases.BaseServerTestCase):
|
||||
self.assertNotEqual(m.command, '001',
|
||||
msg='Got 001 after NICK+USER but missing PASS')
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812')
|
||||
def testWrongPassword(self):
|
||||
self.addClient()
|
||||
self.sendLine(1, 'PASS {}'.format(self.password + "garbage"))
|
||||
self.sendLine(1, 'NICK foo')
|
||||
self.sendLine(1, 'USER username * * :Realname')
|
||||
m = self.getRegistrationMessage(1)
|
||||
self.assertNotEqual(m.command, '001',
|
||||
msg='Got 001 after NICK+USER but incorrect PASS')
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812')
|
||||
def testPassAfterNickuser(self):
|
||||
"""“The password can and must be set before any attempt to register
|
||||
|
@ -22,7 +22,7 @@ class EchoMessageTestCase(cases.BaseServerTestCase):
|
||||
# TODO: check also without this
|
||||
self.sendLine(1, 'CAP REQ :echo-message{}'.format(
|
||||
' server-time' if server_time else ''))
|
||||
m = self.getRegistrationMessage(1)
|
||||
self.getRegistrationMessage(1)
|
||||
# TODO: Remove this one the trailing space issue is fixed in Charybdis
|
||||
# and Mammon:
|
||||
#self.assertMessageEqual(m, command='CAP',
|
||||
|
@ -3,7 +3,6 @@
|
||||
"""
|
||||
|
||||
from irctest import cases
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
|
||||
class MetadataTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
|
||||
def connectRegisteredClient(self, nick):
|
||||
@ -41,7 +40,7 @@ class MetadataTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('IRCv3.1')
|
||||
@cases.OptionalityHelper.skipUnlessHasMechanism('PLAIN')
|
||||
def testNotLoggedIn(self):
|
||||
def testLoggedIn(self):
|
||||
self.connectClient('foo', capabilities=['extended-join'],
|
||||
skip_if_cap_nak=True)
|
||||
self.joinChannel(1, '#chan')
|
||||
|
@ -4,10 +4,6 @@ Section 3.2 of RFC 2812
|
||||
"""
|
||||
|
||||
from irctest import cases
|
||||
from irctest import client_mock
|
||||
from irctest import runner
|
||||
from irctest.irc_utils import ambiguities
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
|
||||
class PrivmsgTestCase(cases.BaseServerTestCase):
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC1459', 'RFC2812')
|
||||
|
@ -4,7 +4,6 @@ Tests METADATA features.
|
||||
"""
|
||||
|
||||
from irctest import cases
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
|
||||
class MetadataTestCase(cases.BaseServerTestCase):
|
||||
valid_metadata_keys = {'valid_key1', 'valid_key2'}
|
||||
|
@ -88,7 +88,7 @@ class EchoMessageTestCase(cases.BaseServerTestCase):
|
||||
self.assertMonoffline(1, 'bar')
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('IRCv3.2')
|
||||
def testMonitorOneConnection(self):
|
||||
def testMonitorOneConnectionWithQuit(self):
|
||||
self.connectClient('foo')
|
||||
self.check_server_support()
|
||||
self.connectClient('bar')
|
||||
|
@ -4,10 +4,6 @@ Tests multi-prefix.
|
||||
"""
|
||||
|
||||
from irctest import cases
|
||||
from irctest import client_mock
|
||||
from irctest import runner
|
||||
from irctest.irc_utils import ambiguities
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
|
||||
class MultiPrefixTestCase(cases.BaseServerTestCase):
|
||||
@cases.SpecificationSelector.requiredBySpecification('IRCv3.1')
|
||||
|
@ -1,7 +1,6 @@
|
||||
import base64
|
||||
|
||||
from irctest import cases
|
||||
from irctest.irc_utils.message_parser import Message
|
||||
|
||||
class RegistrationTestCase(cases.BaseServerTestCase):
|
||||
def testRegistration(self):
|
||||
|
@ -5,8 +5,36 @@ User commands as specified in Section 3.6 of RFC 2812:
|
||||
|
||||
from irctest import cases
|
||||
|
||||
RPL_WHOISUSER = '311'
|
||||
RPL_WHOISCHANNELS = '319'
|
||||
|
||||
class WhoisTestCase(cases.BaseServerTestCase):
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('RFC2812')
|
||||
def testWhoisUser(self):
|
||||
"""Test basic WHOIS behavior"""
|
||||
nick = 'myCoolNickname'
|
||||
username = 'myCoolUsername'
|
||||
realname = 'My Real Name'
|
||||
self.addClient()
|
||||
self.sendLine(1, f'NICK {nick}')
|
||||
self.sendLine(1, f'USER {username} 0 * :{realname}')
|
||||
self.skipToWelcome(1)
|
||||
|
||||
self.connectClient('otherNickname')
|
||||
self.getMessages(2)
|
||||
self.sendLine(2, 'WHOIS mycoolnickname')
|
||||
messages = self.getMessages(2)
|
||||
whois_user = messages[0]
|
||||
self.assertEqual(whois_user.command, RPL_WHOISUSER)
|
||||
# "<client> <nick> <username> <host> * :<realname>"
|
||||
self.assertEqual(whois_user.params[1], nick)
|
||||
self.assertEqual(whois_user.params[2], '~' + username)
|
||||
# dumb regression test for oragono/oragono#355:
|
||||
self.assertNotIn(whois_user.params[3], [nick, username, '~' + username, realname])
|
||||
self.assertEqual(whois_user.params[5], realname)
|
||||
|
||||
|
||||
class InvisibleTestCase(cases.BaseServerTestCase):
|
||||
|
||||
@cases.SpecificationSelector.requiredBySpecification('Oragono')
|
||||
|
Reference in New Issue
Block a user