"Fossies" - the Fresh Open Source Software Archive

Member "fail2ban-0.11.1/fail2ban/tests/observertestcase.py" (11 Jan 2020, 22988 Bytes) of package /linux/misc/fail2ban-0.11.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
    2 # vi: set ft=python sts=4 ts=4 sw=4 noet :
    3 
    4 # This file is part of Fail2Ban.
    5 #
    6 # Fail2Ban is free software; you can redistribute it and/or modify
    7 # it under the terms of the GNU General Public License as published by
    8 # the Free Software Foundation; either version 2 of the License, or
    9 # (at your option) any later version.
   10 #
   11 # Fail2Ban is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with Fail2Ban; if not, write to the Free Software
   18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 
   20 # Author: Serg G. Brester (sebres)
   21 # 
   22 
   23 __author__ = "Serg G. Brester (sebres)"
   24 __copyright__ = "Copyright (c) 2014 Serg G. Brester"
   25 __license__ = "GPL"
   26 
   27 import os
   28 import sys
   29 import unittest
   30 import tempfile
   31 import time
   32 
   33 from ..server.mytime import MyTime
   34 from ..server.ticket import FailTicket, BanTicket
   35 from ..server.failmanager import FailManager
   36 from ..server.observer import Observers, ObserverThread
   37 from ..server.utils import Utils
   38 from .utils import LogCaptureTestCase
   39 from ..server.filter import Filter
   40 from .dummyjail import DummyJail
   41 
   42 from .databasetestcase import getFail2BanDb, Fail2BanDb
   43 
   44 
   45 class BanTimeIncr(LogCaptureTestCase):
   46 
   47     def setUp(self):
   48         """Call before every test case."""
   49         super(BanTimeIncr, self).setUp()
   50         self.__jail = DummyJail()
   51         self.__jail.calcBanTime = self.calcBanTime
   52         self.Observer = ObserverThread()
   53 
   54     def tearDown(self):
   55         super(BanTimeIncr, self).tearDown()
   56 
   57     def calcBanTime(self, banTime, banCount):
   58         return self.Observer.calcBanTime(self.__jail, banTime, banCount)
   59 
   60     def testDefault(self, multipliers = None):
   61         a = self.__jail;
   62         a.setBanTimeExtra('increment', 'true')
   63         self.assertEqual(a.getBanTimeExtra('increment'), True)
   64         a.setBanTimeExtra('maxtime', '1d')
   65         self.assertEqual(a.getBanTimeExtra('maxtime'), 24*60*60)
   66         a.setBanTimeExtra('rndtime', None)
   67         a.setBanTimeExtra('factor', None)
   68         # tests formulat or multipliers:
   69         a.setBanTimeExtra('multipliers', multipliers)
   70         # test algorithm and max time 24 hours :
   71         self.assertEqual(
   72             [a.calcBanTime(600, i) for i in xrange(1, 11)],
   73             [1200, 2400, 4800, 9600, 19200, 38400, 76800, 86400, 86400, 86400]
   74         )
   75         # with extra large max time (30 days):
   76         a.setBanTimeExtra('maxtime', '30d')
   77         # using formula the ban time grows always, but using multipliers the growing will stops with last one:
   78         arr = [1200, 2400, 4800, 9600, 19200, 38400, 76800, 153600, 307200, 614400]
   79         if multipliers is not None:
   80             multcnt = len(multipliers.split(' '))
   81             if multcnt < 11:
   82                 arr = arr[0:multcnt-1] + ([arr[multcnt-2]] * (11-multcnt))
   83         self.assertEqual(
   84             [a.calcBanTime(600, i) for i in xrange(1, 11)],
   85             arr
   86         )
   87         a.setBanTimeExtra('maxtime', '1d')
   88         # change factor :
   89         a.setBanTimeExtra('factor', '2');
   90         self.assertEqual(
   91             [a.calcBanTime(600, i) for i in xrange(1, 11)],
   92             [2400, 4800, 9600, 19200, 38400, 76800, 86400, 86400, 86400, 86400]
   93         )
   94         # factor is float :
   95         a.setBanTimeExtra('factor', '1.33');
   96         self.assertEqual(
   97             [int(a.calcBanTime(600, i)) for i in xrange(1, 11)],
   98             [1596, 3192, 6384, 12768, 25536, 51072, 86400, 86400, 86400, 86400]
   99         )
  100         a.setBanTimeExtra('factor', None);
  101         # change max time :
  102         a.setBanTimeExtra('maxtime', '12h')
  103         self.assertEqual(
  104             [a.calcBanTime(600, i) for i in xrange(1, 11)],
  105             [1200, 2400, 4800, 9600, 19200, 38400, 43200, 43200, 43200, 43200]
  106         )
  107         a.setBanTimeExtra('maxtime', '24h')
  108         ## test randomization - not possibe all 10 times we have random = 0:
  109         a.setBanTimeExtra('rndtime', '5m')
  110         self.assertTrue(
  111             False in [1200 in [a.calcBanTime(600, 1) for i in xrange(10)] for c in xrange(10)]
  112         )
  113         a.setBanTimeExtra('rndtime', None)
  114         self.assertFalse(
  115             False in [1200 in [a.calcBanTime(600, 1) for i in xrange(10)] for c in xrange(10)]
  116         )
  117         # restore default:
  118         a.setBanTimeExtra('multipliers', None)
  119         a.setBanTimeExtra('factor', None);
  120         a.setBanTimeExtra('maxtime', '24h')
  121         a.setBanTimeExtra('rndtime', None)
  122 
  123     def testMultipliers(self):
  124         # this multipliers has the same values as default formula, we test stop growing after count 9:
  125         self.testDefault('1 2 4 8 16 32 64 128 256')
  126         # this multipliers has exactly the same values as default formula, test endless growing (stops by count 31 only):
  127         self.testDefault(' '.join([str(1<<i) for i in xrange(31)]))
  128 
  129     def testFormula(self):
  130         a = self.__jail;
  131         a.setBanTimeExtra('maxtime', '24h')
  132         a.setBanTimeExtra('rndtime', None)
  133         ## use another formula:
  134         a.setBanTimeExtra('formula', 'ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)')
  135         a.setBanTimeExtra('factor', '2.0 / 2.885385')
  136         a.setBanTimeExtra('multipliers', None)
  137         # test algorithm and max time 24 hours :
  138         self.assertEqual(
  139             [int(a.calcBanTime(600, i)) for i in xrange(1, 11)],
  140             [1200, 2400, 4800, 9600, 19200, 38400, 76800, 86400, 86400, 86400]
  141         )
  142         # with extra large max time (30 days):
  143         a.setBanTimeExtra('maxtime', '30d')
  144         self.assertEqual(
  145             [int(a.calcBanTime(600, i)) for i in xrange(1, 11)],
  146             [1200, 2400, 4800, 9600, 19200, 38400, 76800, 153601, 307203, 614407]
  147         )
  148         a.setBanTimeExtra('maxtime', '24h')
  149         # change factor :
  150         a.setBanTimeExtra('factor', '1');
  151         self.assertEqual(
  152             [int(a.calcBanTime(600, i)) for i in xrange(1, 11)],
  153             [1630, 4433, 12051, 32758, 86400, 86400, 86400, 86400, 86400, 86400]
  154         )
  155         a.setBanTimeExtra('factor', '2.0 / 2.885385')
  156         # change max time :
  157         a.setBanTimeExtra('maxtime', '12h')
  158         self.assertEqual(
  159             [int(a.calcBanTime(600, i)) for i in xrange(1, 11)],
  160             [1200, 2400, 4800, 9600, 19200, 38400, 43200, 43200, 43200, 43200]
  161         )
  162         a.setBanTimeExtra('maxtime', '24h')
  163         ## test randomization - not possibe all 10 times we have random = 0:
  164         a.setBanTimeExtra('rndtime', '5m')
  165         self.assertTrue(
  166             False in [1200 in [int(a.calcBanTime(600, 1)) for i in xrange(10)] for c in xrange(10)]
  167         )
  168         a.setBanTimeExtra('rndtime', None)
  169         self.assertFalse(
  170             False in [1200 in [int(a.calcBanTime(600, 1)) for i in xrange(10)] for c in xrange(10)]
  171         )
  172         # restore default:
  173         a.setBanTimeExtra('factor', None);
  174         a.setBanTimeExtra('multipliers', None)
  175         a.setBanTimeExtra('factor', None);
  176         a.setBanTimeExtra('maxtime', '24h')
  177         a.setBanTimeExtra('rndtime', None)
  178 
  179 
  180 class BanTimeIncrDB(LogCaptureTestCase):
  181 
  182     def setUp(self):
  183         """Call before every test case."""
  184         super(BanTimeIncrDB, self).setUp()
  185         if Fail2BanDb is None and sys.version_info >= (2,7): # pragma: no cover
  186             raise unittest.SkipTest(
  187                 "Unable to import fail2ban database module as sqlite is not "
  188                 "available.")
  189         elif Fail2BanDb is None:
  190             return
  191         _, self.dbFilename = tempfile.mkstemp(".db", "fail2ban_")
  192         self.db = getFail2BanDb(self.dbFilename)
  193         self.jail = DummyJail()
  194         self.jail.database = self.db
  195         self.Observer = ObserverThread()
  196         Observers.Main = self.Observer
  197 
  198     def tearDown(self):
  199         """Call after every test case."""
  200         if Fail2BanDb is None: # pragma: no cover
  201             return
  202         # Cleanup
  203         self.Observer.stop()
  204         Observers.Main = None
  205         os.remove(self.dbFilename)
  206         super(BanTimeIncrDB, self).tearDown()
  207 
  208     def incrBanTime(self, ticket, banTime=None):
  209         jail = self.jail;
  210         if banTime is None:
  211             banTime = ticket.getBanTime(jail.actions.getBanTime())
  212         ticket.setBanTime(None)
  213         incrTime = self.Observer.incrBanTime(jail, banTime, ticket)
  214         #print("!!!!!!!!! banTime: %s, %s, incr: %s " % (banTime, ticket.getBanCount(), incrTime))
  215         return incrTime
  216 
  217 
  218     def testBanTimeIncr(self):
  219         if Fail2BanDb is None: # pragma: no cover
  220             return
  221         jail = self.jail
  222         self.db.addJail(jail)
  223         # we tests with initial ban time = 10 seconds:
  224         jail.actions.setBanTime(10)
  225         jail.setBanTimeExtra('increment', 'true')
  226         jail.setBanTimeExtra('multipliers', '1 2 4 8 16 32 64 128 256 512 1024 2048')
  227         ip = "127.0.0.2"
  228         # used as start and fromtime (like now but time independence, cause test case can run slow):
  229         stime = int(MyTime.time())
  230         ticket = FailTicket(ip, stime, [])
  231         # test ticket not yet found
  232         self.assertEqual(
  233             [self.incrBanTime(ticket, 10) for i in xrange(3)], 
  234             [10, 10, 10]
  235         )
  236         # add a ticket banned
  237         ticket.incrBanCount()
  238         self.db.addBan(jail, ticket)
  239         # get a ticket already banned in this jail:
  240         self.assertEqual(
  241             [(banCount, timeOfBan, lastBanTime) for banCount, timeOfBan, lastBanTime in self.db.getBan(ip, jail, None, False)],
  242             [(1, stime, 10)]
  243         )
  244         # incr time and ban a ticket again :
  245         ticket.setTime(stime + 15)
  246         self.assertEqual(self.incrBanTime(ticket, 10), 20)
  247         self.db.addBan(jail, ticket)
  248         # get a ticket already banned in this jail:
  249         self.assertEqual(
  250             [(banCount, timeOfBan, lastBanTime) for banCount, timeOfBan, lastBanTime in self.db.getBan(ip, jail, None, False)],
  251             [(2, stime + 15, 20)]
  252         )
  253         # get a ticket already banned in all jails:
  254         self.assertEqual(
  255             [(banCount, timeOfBan, lastBanTime) for banCount, timeOfBan, lastBanTime in self.db.getBan(ip, '', None, True)],
  256             [(2, stime + 15, 20)]
  257         )
  258         # check other optional parameters of getBan:
  259         self.assertEqual(
  260             [(banCount, timeOfBan, lastBanTime) for banCount, timeOfBan, lastBanTime in self.db.getBan(ip, forbantime=stime, fromtime=stime)],
  261             [(2, stime + 15, 20)]
  262         )
  263         # search currently banned and 1 day later (nothing should be found):
  264         self.assertEqual(
  265             self.db.getCurrentBans(forbantime=-24*60*60, fromtime=stime, correctBanTime=False),
  266             []
  267         )
  268         # search currently banned one ticket for ip:
  269         restored_tickets = self.db.getCurrentBans(ip=ip, correctBanTime=False)
  270         self.assertEqual(
  271             str(restored_tickets), 
  272             ('FailTicket: ip=%s time=%s bantime=20 bancount=2 #attempts=0 matches=[]' % (ip, stime + 15))
  273         )
  274         # search currently banned anywhere:
  275         restored_tickets = self.db.getCurrentBans(fromtime=stime, correctBanTime=False)
  276         self.assertEqual(
  277             str(restored_tickets),
  278             ('[FailTicket: ip=%s time=%s bantime=20 bancount=2 #attempts=0 matches=[]]' % (ip, stime + 15))
  279         )
  280         # search currently banned:
  281         restored_tickets = self.db.getCurrentBans(jail=jail, fromtime=stime, correctBanTime=False)
  282         self.assertEqual(
  283             str(restored_tickets), 
  284             ('[FailTicket: ip=%s time=%s bantime=20 bancount=2 #attempts=0 matches=[]]' % (ip, stime + 15))
  285         )
  286         # increase ban multiple times:
  287         lastBanTime = 20
  288         for i in xrange(10):
  289             ticket.setTime(stime + lastBanTime + 5)
  290             banTime = self.incrBanTime(ticket, 10)
  291             self.assertEqual(banTime, lastBanTime * 2)
  292             self.db.addBan(jail, ticket)
  293             lastBanTime = banTime
  294         # increase again, but the last multiplier reached (time not increased):
  295         ticket.setTime(stime + lastBanTime + 5)
  296         banTime = self.incrBanTime(ticket, 10)
  297         self.assertNotEqual(banTime, lastBanTime * 2)
  298         self.assertEqual(banTime, lastBanTime)
  299         self.db.addBan(jail, ticket)
  300         lastBanTime = banTime
  301         # add two tickets from yesterday: one unbanned (bantime already out-dated):
  302         ticket2 = FailTicket(ip+'2', stime-24*60*60, [])
  303         ticket2.setBanTime(12*60*60)
  304         ticket2.incrBanCount()
  305         self.db.addBan(jail, ticket2)
  306         # and one from yesterday also, but still currently banned :
  307         ticket2 = FailTicket(ip+'1', stime-24*60*60, [])
  308         ticket2.setBanTime(36*60*60)
  309         ticket2.incrBanCount()
  310         self.db.addBan(jail, ticket2)
  311         # search currently banned:
  312         restored_tickets = self.db.getCurrentBans(fromtime=stime, correctBanTime=False)
  313         self.assertEqual(len(restored_tickets), 2)
  314         self.assertEqual(
  315             str(restored_tickets[0]),
  316             'FailTicket: ip=%s time=%s bantime=%s bancount=13 #attempts=0 matches=[]' % (ip, stime + lastBanTime + 5, lastBanTime)
  317         )
  318         self.assertEqual(
  319             str(restored_tickets[1]),
  320             'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip+'1', stime-24*60*60, 36*60*60)
  321         )
  322         # search out-dated (give another fromtime now is -18 hours):
  323         restored_tickets = self.db.getCurrentBans(fromtime=stime-18*60*60, correctBanTime=False)
  324         self.assertEqual(len(restored_tickets), 3)
  325         self.assertEqual(
  326             str(restored_tickets[2]),
  327             'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip+'2', stime-24*60*60, 12*60*60)
  328         )
  329         # should be still banned
  330         self.assertFalse(restored_tickets[1].isTimedOut(stime))
  331         self.assertFalse(restored_tickets[1].isTimedOut(stime))
  332         # the last should be timed out now
  333         self.assertTrue(restored_tickets[2].isTimedOut(stime))
  334         self.assertFalse(restored_tickets[2].isTimedOut(stime-18*60*60))
  335 
  336         # test permanent, create timed out:
  337         ticket=FailTicket(ip+'3', stime-36*60*60, [])
  338         self.assertTrue(ticket.isTimedOut(stime, 600))
  339         # not timed out - permanent jail:
  340         self.assertFalse(ticket.isTimedOut(stime, -1))
  341         # not timed out - permanent ticket:
  342         ticket.setBanTime(-1)
  343         self.assertFalse(ticket.isTimedOut(stime, 600))
  344         self.assertFalse(ticket.isTimedOut(stime, -1))
  345         # timed out - permanent jail but ticket time (not really used behavior)
  346         ticket.setBanTime(600)
  347         self.assertTrue(ticket.isTimedOut(stime, -1))
  348 
  349         # get currently banned pis with permanent one:
  350         ticket.setBanTime(-1)
  351         ticket.incrBanCount()
  352         self.db.addBan(jail, ticket)
  353         restored_tickets = self.db.getCurrentBans(fromtime=stime, correctBanTime=False)
  354         self.assertEqual(len(restored_tickets), 3)
  355         self.assertEqual(
  356             str(restored_tickets[2]),
  357             'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip+'3', stime-36*60*60, -1)
  358         )
  359         # purge (nothing should be changed):
  360         self.db.purge()
  361         restored_tickets = self.db.getCurrentBans(fromtime=stime, correctBanTime=False)
  362         self.assertEqual(len(restored_tickets), 3)
  363         # set short time and purge again:
  364         ticket.setBanTime(600)
  365         ticket.incrBanCount()
  366         self.db.addBan(jail, ticket)
  367         self.db.purge()
  368         # this old ticket should be removed now:
  369         restored_tickets = self.db.getCurrentBans(fromtime=stime, correctBanTime=False)
  370         self.assertEqual(len(restored_tickets), 2)
  371         self.assertEqual(restored_tickets[0].getIP(), ip)
  372 
  373         # purge remove 1st ip
  374         self.db._purgeAge = -48*60*60
  375         self.db.purge()
  376         restored_tickets = self.db.getCurrentBans(fromtime=stime, correctBanTime=False)
  377         self.assertEqual(len(restored_tickets), 1)
  378         self.assertEqual(restored_tickets[0].getIP(), ip+'1')
  379 
  380         # this should purge all bans, bips and logs - nothing should be found now
  381         self.db._purgeAge = -240*60*60
  382         self.db.purge()
  383         restored_tickets = self.db.getCurrentBans(fromtime=stime, correctBanTime=False)
  384         self.assertEqual(restored_tickets, [])
  385 
  386         # two separate jails :
  387         jail1 = DummyJail(backend='polling')
  388         jail1.setBanTimeExtra('increment', 'true')
  389         jail1.database = self.db
  390         self.db.addJail(jail1)
  391         jail2 = DummyJail(name='DummyJail-2', backend='polling')
  392         jail2.database = self.db
  393         self.db.addJail(jail2)
  394         ticket1 = FailTicket(ip, stime, [])
  395         ticket1.setBanTime(6000)
  396         ticket1.incrBanCount()
  397         self.db.addBan(jail1, ticket1)
  398         ticket2 = FailTicket(ip, stime-6000, [])
  399         ticket2.setBanTime(12000)
  400         ticket2.setBanCount(1)
  401         ticket2.incrBanCount()
  402         self.db.addBan(jail2, ticket2)
  403         restored_tickets = self.db.getCurrentBans(jail=jail1, fromtime=stime, correctBanTime=False)
  404         self.assertEqual(len(restored_tickets), 1)
  405         self.assertEqual(
  406             str(restored_tickets[0]),
  407             'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip, stime, 6000)
  408         )
  409         restored_tickets = self.db.getCurrentBans(jail=jail2, fromtime=stime, correctBanTime=False)
  410         self.assertEqual(len(restored_tickets), 1)
  411         self.assertEqual(
  412             str(restored_tickets[0]),
  413             'FailTicket: ip=%s time=%s bantime=%s bancount=2 #attempts=0 matches=[]' % (ip, stime-6000, 12000)
  414         )
  415         # get last ban values for this ip separately for each jail:
  416         for row in self.db.getBan(ip, jail1):
  417             self.assertEqual(row, (1, stime, 6000))
  418             break
  419         for row in self.db.getBan(ip, jail2):
  420             self.assertEqual(row, (2, stime-6000, 12000))
  421             break
  422         # get max values for this ip (over all jails):
  423         for row in self.db.getBan(ip, overalljails=True):
  424             self.assertEqual(row, (3, stime, 18000))
  425             break
  426         # test restoring bans from database:
  427         jail1.restoreCurrentBans(correctBanTime=False)
  428         ticket = jail1.getFailTicket()
  429         self.assertTrue(ticket.restored)
  430         self.assertEqual(str(ticket), 
  431             'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip, stime, 6000)
  432         )
  433         # jail2 does not restore any bans (because all ban tickets should be already expired: stime-6000):
  434         jail2.restoreCurrentBans(correctBanTime=False)
  435         self.assertEqual(jail2.getFailTicket(), False)
  436         # test again, but now normally (with maximum ban-time of restored ticket = allowed 10m = 600):
  437         jail1.setBanTimeExtra('maxtime', '10m')
  438         jail1.restoreCurrentBans()
  439         ticket = jail1.getFailTicket()
  440         self.assertTrue(ticket.restored)
  441         # ticket restored, but it has new time = 600 (current ban-time of jail, as maximum):
  442         self.assertEqual(str(ticket), 
  443             'FailTicket: ip=%s time=%s bantime=%s bancount=1 #attempts=0 matches=[]' % (ip, stime, 600)
  444         )
  445         # jail2 does not restore any bans (because all ban tickets should be already expired: stime-6000):
  446         jail2.restoreCurrentBans()
  447         self.assertEqual(jail2.getFailTicket(), False)
  448 
  449     def testObserver(self):
  450         if Fail2BanDb is None: # pragma: no cover
  451             return
  452         jail = self.jail
  453         self.db.addJail(jail)
  454         # we tests with initial ban time = 10 seconds:
  455         jail.actions.setBanTime(10)
  456         jail.setBanTimeExtra('increment', 'true')
  457         # observer / database features:
  458         obs = Observers.Main
  459         obs.start()
  460         obs.db_set(self.db)
  461         # wait for start ready
  462         obs.add('nop')
  463         obs.wait_empty(5)
  464         # purge database right now, but using timer, to test it also:
  465         self.db._purgeAge = -240*60*60
  466         obs.add_named_timer('DB_PURGE', 0.001, 'db_purge')
  467         self.assertLogged("Purge database event occurred", wait=True); # wait for purge timer
  468         # wait for timer ready
  469         obs.wait_idle(0.025)
  470         # wait for ready
  471         obs.add('nop')
  472         obs.wait_empty(5)
  473 
  474         stime = int(MyTime.time())
  475         # completelly empty ?
  476         tickets = self.db.getBans()
  477         self.assertEqual(tickets, [])
  478 
  479         # add failure:
  480         ip = "127.0.0.2"
  481         ticket = FailTicket(ip, stime-120, [])
  482         failManager = FailManager()
  483         failManager.setMaxRetry(3)
  484         for i in xrange(3):
  485             failManager.addFailure(ticket)
  486             obs.add('failureFound', failManager, jail, ticket)
  487         obs.wait_empty(5)
  488         self.assertEqual(ticket.getBanCount(), 0)
  489         # check still not ban :
  490         self.assertTrue(not jail.getFailTicket())
  491         # add manually 4th times banned (added to bips - make ip bad):
  492         ticket.setBanCount(4)
  493         self.db.addBan(self.jail, ticket)
  494         restored_tickets = self.db.getCurrentBans(jail=jail, fromtime=stime-120, correctBanTime=False)
  495         self.assertEqual(len(restored_tickets), 1)
  496         # check again, new ticket, new failmanager:
  497         ticket = FailTicket(ip, stime, [])
  498         failManager = FailManager()
  499         failManager.setMaxRetry(3)
  500         # add once only - but bad - should be banned:
  501         failManager.addFailure(ticket)
  502         obs.add('failureFound', failManager, self.jail, ticket)
  503         obs.wait_empty(5)
  504         # wait until ticket transfered from failmanager into jail:
  505         ticket2 = Utils.wait_for(jail.getFailTicket, 10)
  506         # check ticket and failure count:
  507         self.assertTrue(ticket2)
  508         self.assertEqual(ticket2.getRetry(), failManager.getMaxRetry())
  509 
  510         # wrap FailTicket to BanTicket:
  511         failticket2 = ticket2
  512         ticket2 = BanTicket.wrap(failticket2)
  513         self.assertEqual(ticket2, failticket2)
  514         # add this ticket to ban (use observer only without ban manager):
  515         obs.add('banFound', ticket2, jail, 10)
  516         obs.wait_empty(5)
  517         # increased?
  518         self.assertEqual(ticket2.getBanTime(), 160)
  519         self.assertEqual(ticket2.getBanCount(), 5)
  520 
  521         # check prolonged in database also :
  522         restored_tickets = self.db.getCurrentBans(jail=jail, fromtime=stime, correctBanTime=False)
  523         self.assertEqual(len(restored_tickets), 1)
  524         self.assertEqual(restored_tickets[0].getBanTime(), 160)
  525         self.assertEqual(restored_tickets[0].getBanCount(), 5)
  526 
  527         # now using jail/actions:
  528         ticket = FailTicket(ip, stime-60, ['test-expired-ban-time'])
  529         jail.putFailTicket(ticket)
  530         self.assertFalse(jail.actions.checkBan())
  531 
  532         ticket = FailTicket(ip, MyTime.time(), ['test-actions'])
  533         jail.putFailTicket(ticket)
  534         self.assertTrue(jail.actions.checkBan())
  535 
  536         obs.wait_empty(5)
  537         restored_tickets = self.db.getCurrentBans(jail=jail, fromtime=stime, correctBanTime=False)
  538         self.assertEqual(len(restored_tickets), 1)
  539         self.assertEqual(restored_tickets[0].getBanTime(), 320)
  540         self.assertEqual(restored_tickets[0].getBanCount(), 6)
  541 
  542         # and permanent:
  543         ticket = FailTicket(ip+'1', MyTime.time(), ['test-permanent'])
  544         ticket.setBanTime(-1)
  545         jail.putFailTicket(ticket)
  546         self.assertTrue(jail.actions.checkBan())
  547 
  548         obs.wait_empty(5)
  549         ticket = FailTicket(ip+'1', MyTime.time(), ['test-permanent'])
  550         ticket.setBanTime(600)
  551         jail.putFailTicket(ticket)
  552         self.assertFalse(jail.actions.checkBan())
  553 
  554         obs.wait_empty(5)
  555         restored_tickets = self.db.getCurrentBans(jail=jail, fromtime=stime, correctBanTime=False)
  556         self.assertEqual(len(restored_tickets), 2)
  557         self.assertEqual(restored_tickets[1].getBanTime(), -1)
  558         self.assertEqual(restored_tickets[1].getBanCount(), 1)
  559 
  560         # stop observer
  561         obs.stop()
  562 
  563 class ObserverTest(LogCaptureTestCase):
  564 
  565     def setUp(self):
  566         """Call before every test case."""
  567         super(ObserverTest, self).setUp()
  568 
  569     def tearDown(self):
  570         """Call after every test case."""
  571         super(ObserverTest, self).tearDown()
  572 
  573     def testObserverBanTimeIncr(self):
  574         obs = ObserverThread()
  575         obs.start()
  576         # wait for idle
  577         obs.wait_idle(1)
  578         # observer will replace test set:
  579         o = set(['test'])
  580         obs.add('call', o.clear)
  581         obs.add('call', o.add, 'test2')
  582         # wait for observer ready:
  583         obs.wait_empty(1)
  584         self.assertFalse(obs.is_full)
  585         self.assertEqual(o, set(['test2']))
  586         # observer makes pause
  587         obs.paused = True
  588         # observer will replace test set, but first after pause ends:
  589         obs.add('call', o.clear)
  590         obs.add('call', o.add, 'test3')
  591         obs.wait_empty(10 * Utils.DEFAULT_SLEEP_TIME)
  592         self.assertTrue(obs.is_full)
  593         self.assertEqual(o, set(['test2']))
  594         obs.paused = False
  595         # wait running:
  596         obs.wait_empty(1)
  597         self.assertEqual(o, set(['test3']))
  598 
  599         self.assertTrue(obs.isActive())
  600         self.assertTrue(obs.isAlive())
  601         obs.stop()
  602         obs = None
  603 
  604     class _BadObserver(ObserverThread):
  605         def run(self):
  606             raise RuntimeError('run bad thread exception')
  607 
  608     def testObserverBadRun(self):
  609         obs = ObserverTest._BadObserver()
  610         # don't wait for empty by stop
  611         obs.wait_empty = lambda v:()
  612         # save previous hook, prevent write stderr and check hereafter __excepthook__ was executed
  613         prev_exchook = sys.__excepthook__
  614         x = []
  615         sys.__excepthook__ = lambda *args: x.append(args)
  616         try:
  617             obs.start()
  618             obs.stop()
  619             obs.join()
  620             self.assertTrue( Utils.wait_for( lambda: len(x) and self._is_logged("Unhandled exception"), 3) )
  621         finally:
  622             sys.__excepthook__ = prev_exchook
  623         self.assertLogged("Unhandled exception")
  624         self.assertEqual(len(x), 1)
  625         self.assertEqual(x[0][0], RuntimeError)
  626         self.assertEqual(str(x[0][1]), 'run bad thread exception')