From 0141a6dbe77888e41c863ed61c7d407b3c526983 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 27 Dec 2013 01:29:02 -0500 Subject: [PATCH 1/5] TST: add few more rudimentary tests for Regex to complete its coverage --- fail2ban-testcases | 1 + testcases/servertestcase.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/fail2ban-testcases b/fail2ban-testcases index c1191d0e..8034a4c6 100755 --- a/fail2ban-testcases +++ b/fail2ban-testcases @@ -153,6 +153,7 @@ else: # pragma: no cover #tests.addTest(unittest.makeSuite(servertestcase.StartStop)) tests.addTest(unittest.makeSuite(servertestcase.Transmitter)) tests.addTest(unittest.makeSuite(servertestcase.JailTests)) +tests.addTest(unittest.makeSuite(servertestcase.RegexTests)) tests.addTest(unittest.makeSuite(actiontestcase.ExecuteAction)) tests.addTest(unittest.makeSuite(actionstestcase.ExecuteActions)) # FailManager diff --git a/testcases/servertestcase.py b/testcases/servertestcase.py index 9a4dff11..34d5af0d 100644 --- a/testcases/servertestcase.py +++ b/testcases/servertestcase.py @@ -25,6 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" import unittest, socket, time, tempfile, os, sys +from server.failregex import Regex, FailRegex, RegexException from server.server import Server, logSys from server.jail import Jail from common.exceptions import UnknownJailException @@ -561,3 +562,30 @@ class JailTests(unittest.TestCase): longname = "veryveryverylongname" jail = Jail(longname) self.assertEqual(jail.getName(), longname) + +class RegexTests(unittest.TestCase): + + def testInit(self): + # Should raise an Exception upon empty regex + self.assertRaises(RegexException, Regex, '') + self.assertRaises(RegexException, Regex, ' ') + self.assertRaises(RegexException, Regex, '\t') + + def testStr(self): + # .replace just to guarantee uniform use of ' or " in the %r + self.assertEqual(str(Regex('a')).replace('"', "'"), "Regex('a')") + # Class name should be proper + self.assertTrue(str(FailRegex('')).startswith("FailRegex(")) + + def testHost(self): + self.assertRaises(RegexException, FailRegex, '') + # Testing obscure case when host group might be missing in the matched pattern, + # e.g. if we made it optional. + fr = FailRegex('%%?') + self.assertFalse(fr.hasMatched()) + fr.search("%%") + self.assertTrue(fr.hasMatched()) + self.assertRaises(RegexException, fr.getHost) + + + From 4e165c9692887db9ad7c85cdb0f5916dd4747a0e Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 27 Dec 2013 01:43:23 -0500 Subject: [PATCH 2/5] ENH: FilterReader - use the set methods (improve coverage), test getters, use os.path.join --- client/filterreader.py | 12 ++++++++---- testcases/samplestestcase.py | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/client/filterreader.py b/client/filterreader.py index 20af1533..34272b49 100644 --- a/client/filterreader.py +++ b/client/filterreader.py @@ -24,6 +24,7 @@ __author__ = "Cyril Jaquier" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" +import os import logging from configreader import ConfigReader @@ -34,23 +35,26 @@ class FilterReader(ConfigReader): def __init__(self, fileName, name, **kwargs): ConfigReader.__init__(self, **kwargs) - self.__file = fileName - self.__name = name + # Defer initialization to the set Methods + self.__file = self.__name = self.__opts = None + self.setFile(fileName) + self.setName(name) def setFile(self, fileName): self.__file = fileName + self.__opts = None def getFile(self): return self.__file def setName(self, name): self.__name = name - + def getName(self): return self.__name def read(self): - return ConfigReader.read(self, "filter.d/" + self.__file) + return ConfigReader.read(self, os.path.join("filter.d", self.__file)) def getOptions(self, pOpts): opts = [["string", "ignoreregex", ""], diff --git a/testcases/samplestestcase.py b/testcases/samplestestcase.py index 6b4d4530..0d1869c3 100644 --- a/testcases/samplestestcase.py +++ b/testcases/samplestestcase.py @@ -60,6 +60,8 @@ def testSampleRegexsFactory(name): # Check filter exists filterConf = FilterReader(name, "jail", basedir=CONFIG_DIR) + self.assertEqual(filterConf.getFile(), name) + self.assertEqual(filterConf.getName(), "jail") filterConf.read() filterConf.getOptions({}) From 952de51cf12d8164400d390a4685d2aacf3a6ea1 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 27 Dec 2013 01:47:15 -0500 Subject: [PATCH 3/5] ENH: per original discussion, and changes which followed, better not to ignore absent failregex -- all filters (but included common) should have it --- testcases/samplestestcase.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/testcases/samplestestcase.py b/testcases/samplestestcase.py index 0d1869c3..c27d0372 100644 --- a/testcases/samplestestcase.py +++ b/testcases/samplestestcase.py @@ -71,10 +71,6 @@ def testSampleRegexsFactory(name): elif opt[2] == "addignoreregex": self.filter.addIgnoreRegex(opt[3]) - if not self.filter.getFailRegex(): - # No fail regexs set: likely just common file for includes. - return - self.assertTrue( os.path.isfile(os.path.join(TEST_FILES_DIR, "logs", name)), "No sample log file available for '%s' filter" % name) From c6a7bc222175438fe845fdb4f8bfaa8aa269a3de Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 27 Dec 2013 01:54:54 -0500 Subject: [PATCH 4/5] BF(2.4): remove use of "with" for python 2.4 for now (since we list it as supported) --- testcases/servertestcase.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/testcases/servertestcase.py b/testcases/servertestcase.py index 34d5af0d..e05a7750 100644 --- a/testcases/servertestcase.py +++ b/testcases/servertestcase.py @@ -540,13 +540,19 @@ class TransmitterLogging(TransmitterBase): logSys.warn("After file moved") self.assertEqual(self.transm.proceed(["flushlogs"]), (0, "rolled over")) logSys.warn("After flushlogs") - with open(fn2,'r') as f: + # >py2.4: with open(fn2, 'r') as f: + f = open(fn2, 'r'); + if True: self.assertTrue(f.next().endswith("Before file moved\n")) self.assertTrue(f.next().endswith("After file moved\n")) self.assertRaises(StopIteration, f.next) - with open(fn,'r') as f: + f.close() + # >py2.4: with open(fn, 'r') as f: + f = open(fn, 'r'); + if True: self.assertTrue(f.next().endswith("After flushlogs\n")) self.assertRaises(StopIteration, f.next) + f.close() finally: os.remove(fn2) finally: From 68151906855b0b9dfb0dc7caaaa0d516c2f80f1a Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 27 Dec 2013 02:08:47 -0500 Subject: [PATCH 5/5] BF(2.4): omit date patterns containing %f (.subsec) for Python before 2.5 --- server/datedetector.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/server/datedetector.py b/server/datedetector.py index b12a8d46..61144ac9 100644 --- a/server/datedetector.py +++ b/server/datedetector.py @@ -21,7 +21,7 @@ __author__ = "Cyril Jaquier and Fail2Ban Contributors" __copyright__ = "Copyright (c) 2004 Cyril Jaquier" __license__ = "GPL" -import time, logging +import sys, time, logging from datetemplate import DateStrptime, DateTai64n, DateEpoch, DateISO8601 from threading import Lock @@ -46,12 +46,13 @@ class DateDetector: def addDefaultTemplate(self): self.__lock.acquire() try: - # asctime with subsecond - template = DateStrptime() - template.setName("WEEKDAY MONTH Day Hour:Minute:Second[.subsecond] Year") - template.setRegex("\S{3} \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}\.\d+ \d{4}") - template.setPattern("%a %b %d %H:%M:%S.%f %Y") - self._appendTemplate(template) + if sys.version_info >= (2, 5): # because of '%.f' + # asctime with subsecond + template = DateStrptime() + template.setName("WEEKDAY MONTH Day Hour:Minute:Second[.subsecond] Year") + template.setRegex("\S{3} \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}\.\d+ \d{4}") + template.setPattern("%a %b %d %H:%M:%S.%f %Y") + self._appendTemplate(template) # asctime without no subsecond template = DateStrptime() template.setName("WEEKDAY MONTH Day Hour:Minute:Second Year") @@ -101,13 +102,14 @@ class DateDetector: template.setRegex("\d{2}/\d{2}/\d{4}:\d{2}:\d{2}:\d{2}") template.setPattern("%m/%d/%Y:%H:%M:%S") self._appendTemplate(template) - # proftpd 2013-11-16 21:43:03,296 - # So like Exim below but with ,subsecond - template = DateStrptime() - template.setName("Year-Month-Day Hour:Minute:Second[,subsecond]") - template.setRegex("\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d+") - template.setPattern("%Y-%m-%d %H:%M:%S,%f") - self._appendTemplate(template) + if sys.version_info >= (2, 5): # because of '%.f' + # proftpd 2013-11-16 21:43:03,296 + # So like Exim below but with ,subsecond + template = DateStrptime() + template.setName("Year-Month-Day Hour:Minute:Second[,subsecond]") + template.setRegex("\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d+") + template.setPattern("%Y-%m-%d %H:%M:%S,%f") + self._appendTemplate(template) # Exim 2006-12-21 06:43:20 template = DateStrptime() template.setName("Year-Month-Day Hour:Minute:Second")