1
# -*- Encoding: utf-8 -*-
3
# Copyright (c) 2008-2010 Terence Simpson
4
# Copyright (c) 2010 Elián Hanisch
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of version 2 of the GNU General Public License as
8
# published by the Free Software Foundation.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
17
from supybot.test import *
19
import supybot.conf as conf
20
import supybot.ircmsgs as ircmsgs
21
import supybot.world as world
26
pluginConf = conf.supybot.plugins.Bantracker
27
pluginConf.enabled.setValue(True)
28
pluginConf.bansite.setValue('http://foo.bar.com')
29
pluginConf.database.setValue('bantracker-test.db')
31
def quiet(channel, hostmask, prefix='', msg=None):
32
"""Returns a MODE to quiet nick on channel."""
33
return ircmsgs.mode(channel, ('+q', hostmask), prefix, msg)
35
class BantrackerTestCase(ChannelPluginTestCase):
36
plugins = ('Bantracker',)
40
super(BantrackerTestCase, self).setUp()
41
pluginConf.request.setValue(False) # disable comments
42
pluginConf.request.ignore.set('')
43
pluginConf.request.forward.set('')
44
pluginConf.request.review.setValue(1.0/86400) # one second
45
# Bantracker for some reason doesn't use Supybot's own methods for check capabilities,
46
# so it doesn't have a clue about testing and screws my tests by default.
47
# This would fix it until I bring myself to take a look
48
cb = self.getCallback()
50
def test_check_auth(*args, **kwargs):
54
return f(*args, **kwargs)
55
cb.check_auth = test_check_auth
59
dbfile = os.path.join(os.curdir, pluginConf.database())
64
db = sqlite.connect(dbfile)
66
cursor.execute('CREATE TABLE bans ('
67
'id INTEGER PRIMARY KEY,'
68
'channel VARCHAR(30) NOT NULL,'
69
'mask VARCHAR(100) NOT NULL,'
70
'operator VARCHAR(30) NOT NULL,'
71
'time VARCHAR(300) NOT NULL,'
73
'removal_op VARCHAR(30),'
75
cursor.execute('CREATE TABLE comments ('
77
'who VARCHAR(100) NOT NULL,'
78
'comment MEDIUMTEXT NOT NULL,'
79
'time VARCHAR(300) NOT NULL)')
80
cursor.execute('CREATE TABLE sessions ('
81
'session_id VARCHAR(50) PRIMARY KEY,'
82
'user MEDIUMTEXT NOT NULL,'
84
cursor.execute('CREATE TABLE users ('
85
'username VARCHAR(50) PRIMARY KEY,'
87
'password VARCHAR(50))')
92
def getCallback(self):
93
for cb in self.irc.callbacks:
94
if cb.name() == 'Bantracker':
99
return self.getCallback().db
101
def query(self, query, parms=()):
102
cursor = self.getDb().cursor()
103
cursor.execute(query, parms)
104
return cursor.fetchall()
106
def feedBan(self, hostmask, prefix='', channel=None, mode='b'):
108
channel = self.channel
110
prefix = 'op!user@host.net'
112
ban = ircmsgs.ban(channel, hostmask, prefix=prefix)
114
ban = quiet(channel, hostmask, prefix=prefix)
116
ban = ircmsgs.kick(channel, hostmask, s='kthxbye!', prefix=prefix)
118
ban = ircmsgs.part(channel, prefix=hostmask,
119
s='requested by %s (kthxbye!)' %prefix[:prefix.find('!')])
120
self.irc.feedMsg(ban)
123
def testComment(self):
124
pluginConf.request.setValue(True)
126
self.feedBan('asd!*@*')
127
msg = self.irc.takeMsg()
128
self.assertEqual(str(msg).strip(),
129
"PRIVMSG op :Please comment on the ban of asd!*@* in #test, use: @comment 1"
132
self.feedBan('dude!*@*', mode='q')
133
msg = self.irc.takeMsg()
134
self.assertEqual(str(msg).strip(),
135
"PRIVMSG op :Please comment on the quiet of dude!*@* in #test, use: @comment 2"
138
self.feedBan('dude', mode='k')
139
msg = self.irc.takeMsg()
140
self.assertEqual(str(msg).strip(),
141
"PRIVMSG op :Please comment on the removal of dude in #test, use: @comment 3"
143
self.feedBan('dude!dude@trollpit.com', mode='p')
144
msg = self.irc.takeMsg()
145
self.assertEqual(str(msg).strip(),
146
"PRIVMSG op :Please comment on the removal of dude in #test, use: @comment 4"
149
def testCommentIgnore(self):
150
pluginConf.request.setValue(True)
151
pluginConf.request.ignore.set('FloodBot? FloodBotK?')
152
self.feedBan('asd!*@*', prefix='floodbotk1!bot@botpit.com')
153
msg = self.irc.takeMsg()
154
self.assertEqual(msg, None)
155
self.feedBan('dude!*@*', mode='q', prefix='FloodBot1!bot@botpit.com')
156
msg = self.irc.takeMsg()
157
self.assertEqual(msg, None)
158
self.feedBan('dude', mode='k', prefix='FloodBot2!bot@botbag.com')
159
msg = self.irc.takeMsg()
160
self.assertEqual(msg, None)
161
self.feedBan('dude!dude@trollpit.com', mode='p', prefix='FloodBotK2!bot@botbag.com')
162
msg = self.irc.takeMsg()
163
self.assertEqual(msg, None)
164
self.feedBan('asd!*@*')
165
msg = self.irc.takeMsg()
166
self.assertEqual(str(msg).strip(),
167
"PRIVMSG op :Please comment on the ban of asd!*@* in #test, use: @comment 5"
170
def testCommentForward(self):
171
pluginConf.request.setValue(True)
172
pluginConf.request.forward.set('bot')
173
pluginConf.request.forward.channels.set('#channel')
174
self.feedBan('qwe!*@*')
175
msg = self.irc.takeMsg()
176
self.assertEqual(str(msg).strip(),
177
"PRIVMSG op :Please comment on the ban of qwe!*@* in #test, use: @comment 1"
179
self.feedBan('zxc!*@*', prefix='bot!user@host.com')
180
msg = self.irc.takeMsg()
181
self.assertEqual(str(msg).strip(),
182
"NOTICE #channel :Please somebody comment on the ban of zxc!*@* in #test done by bot,"
183
" use: @comment 2 <comment>")
185
def testReview(self):
186
pluginConf.request.setValue(True)
187
cb = self.getCallback()
188
self.feedBan('asd!*@*')
189
self.irc.takeMsg() # ignore comment request comment
191
self.assertFalse(cb.pendingReviews)
192
print 'waiting 4 secs..'
196
self.assertTrue(cb.pendingReviews)
197
# send msg if a user with a matching host says something
198
self.feedMsg('Hi!', frm='op!user@fakehost.net')
199
msg = self.irc.takeMsg()
200
self.assertEqual(msg, None)
201
self.feedMsg('Hi!', frm='op_!user@host.net')
202
msg = self.irc.takeMsg()
203
self.assertEqual(str(msg).strip(),
204
"PRIVMSG op_ :Hi, please review the ban 'asd!*@*' that you set on %s in #test, link: "\
205
"%s/bans.cgi?log=1" %(cb.bans['#test'][0].ascwhen, pluginConf.bansite()))
208
self.assertFalse(cb.pendingReviews)
209
# test again with two ops
210
self.feedBan('asd2!*@*')
212
self.feedBan('qwe!*@*', prefix='otherop!user@home.net')
216
self.assertTrue(len(cb.pendingReviews) == 2)
217
self.feedMsg('Hi!', frm='op!user@fakehost.net')
218
msg = self.irc.takeMsg()
219
self.assertEqual(msg, None)
220
self.assertResponse('banreview', 'Pending ban reviews (2): otherop:1 op:1')
221
self.feedMsg('Hi!', frm='mynickissocreative!user@home.net')
222
msg = self.irc.takeMsg()
223
self.assertEqual(str(msg).strip(),
224
"PRIVMSG mynickissocreative :Hi, please review the ban 'qwe!*@*' that you set on %s in #test, link: "\
225
"%s/bans.cgi?log=3" %(cb.bans['#test'][2].ascwhen, pluginConf.bansite()))
226
self.feedMsg('ping', to='test', frm='op!user@host.net') # in a query
227
self.irc.takeMsg() # drop pong reply
228
msg = self.irc.takeMsg()
229
self.assertEqual(str(msg).strip(),
230
"PRIVMSG op :Hi, please review the ban 'asd2!*@*' that you set on %s in #test, link: "\
231
"%s/bans.cgi?log=2" %(cb.bans['#test'][1].ascwhen, pluginConf.bansite()))
233
def testReviewForward(self):
234
pluginConf.request.setValue(True)
235
pluginConf.request.forward.set('bot')
236
pluginConf.request.forward.channels.set('#channel')
237
cb = self.getCallback()
238
self.feedBan('asd!*@*', prefix='bot!user@host.net')
239
self.irc.takeMsg() # ignore comment request comment
240
cb.reviewBans(self.irc)
241
self.assertFalse(cb.pendingReviews)
242
print 'waiting 2 secs..'
244
cb.reviewBans(self.irc)
245
# since it's a forward, it was sent already
246
self.assertFalse(cb.pendingReviews)
247
msg = self.irc.takeMsg()
248
self.assertEqual(str(msg).strip(),
249
"NOTICE #channel :Hi, please somebody review the ban 'asd!*@*' set by bot on %s in #test, link: "\
250
"%s/bans.cgi?log=1" %(cb.bans['#test'][0].ascwhen, pluginConf.bansite()))
252
def testReviewIgnore(self):
253
pluginConf.request.setValue(True)
254
pluginConf.request.ignore.set('FloodBot? FloodBotK?')
255
cb = self.getCallback()
256
self.feedBan('asd!*@*', prefix='floodbotk1!bot@botpit.com')
257
cb.reviewBans(self.irc)
258
self.assertFalse(cb.pendingReviews)
259
print 'waiting 2 secs..'
261
cb.reviewBans(self.irc)
262
# since it's was ignored, it should not be queued
263
self.assertFalse(cb.pendingReviews)
265
def testReviewNickFallback(self):
266
"""If for some reason we don't have ops full hostmask, revert to nick match. This may be
267
needed in the future as hostmasks aren't stored in the db."""
268
pluginConf.request.setValue(True)
269
cb = self.getCallback()
270
self.feedBan('asd!*@*')
271
self.irc.takeMsg() # ignore comment request comment
272
cb.bans['#test'][0].who = 'op' # replace hostmask by nick
273
print 'waiting 2 secs..'
277
self.assertTrue(cb.pendingReviews)
278
self.assertResponse('banreview', 'Pending ban reviews (1): op:1')
279
# send msg if a user with a matching nick says something
280
self.feedMsg('Hi!', frm='op_!user@host.net')
281
msg = self.irc.takeMsg()
282
self.assertEqual(msg, None)
283
self.feedMsg('Hi!', frm='op!user@host.net')
284
msg = self.irc.takeMsg()
285
self.assertEqual(str(msg).strip(),
286
"PRIVMSG op :Hi, please review the ban 'asd!*@*' that you set on %s in #test, link: "\
287
"%s/bans.cgi?log=1" %(cb.bans['#test'][0].ascwhen, pluginConf.bansite()))
288
# check not pending anymore
289
self.assertFalse(cb.pendingReviews)
291
def testPersistentCache(self):
292
"""Save pending reviews and when bans were last checked. This is needed for plugin
294
msg1 = ircmsgs.privmsg('nick', 'Hello World')
295
msg2 = ircmsgs.privmsg('nick', 'Hello World') # duplicate msg, should be ignored
296
msg2 = ircmsgs.privmsg('nick', 'Hello World2')
297
msg3 = ircmsgs.notice('#chan', 'Hello World')
298
msg4 = ircmsgs.privmsg('nick_', 'Hello World')
299
pr = self.getCallback().pendingReviews
300
pr['host.net'] = [('op', msg1), ('op', msg2), ('op_', msg3)]
301
pr['home.net'] = [('dude', msg4)]
302
self.assertResponse('banreview', 'Pending ban reviews (4): op_:1 dude:1 op:2')
306
self.assertResponse('banreview', 'Pending ban reviews (4): op_:1 dude:1 op:2')
307
items = pr['host.net']
308
self.assertTrue(items[0][0] == 'op' and items[0][1] == msg1)
309
self.assertTrue(items[1][0] == 'op' and items[1][1] == msg2)
310
self.assertTrue(items[2][0] == 'op_' and items[2][1] == msg3)
311
items = pr['home.net']
312
self.assertTrue(items[0][0] == 'dude' and items[0][1] == msg4)
314
def testReviewBanreview(self):
315
pr = self.getCallback().pendingReviews
316
m = ircmsgs.privmsg('#test', 'asd')
317
pr['host.net'] = [('op', m), ('op_', m), ('op', m)]
318
pr['home.net'] = [('dude', m)]
319
self.assertResponse('banreview', 'Pending ban reviews (4): op_:1 dude:1 op:2')
322
self.feedBan('asd!*@*')
323
fetch = self.query("SELECT id,channel,mask,operator FROM bans")
324
self.assertEqual((1, '#test', 'asd!*@*', 'op'), fetch[0])
327
self.feedBan('asd!*@*', mode='q')
328
fetch = self.query("SELECT id,channel,mask,operator FROM bans")
329
self.assertEqual((1, '#test', '%asd!*@*', 'op'), fetch[0])
332
self.feedBan('troll', mode='k')
333
fetch = self.query("SELECT id,channel,mask,operator FROM bans")
334
self.assertEqual((1, '#test', 'troll', 'op'), fetch[0])
337
self.feedBan('troll!user@trollpit.net', mode='p')
338
fetch = self.query("SELECT id,channel,mask,operator FROM bans")
339
self.assertEqual((1, '#test', 'troll', 'op'), fetch[0])