Commit | Line | Data |
---|---|---|
3237d2a6 CH |
1 | # The software in this package is distributed under the GNU General |
2 | # Public License version 2 (with a special exception described below). | |
3 | # | |
4 | # A copy of GNU General Public License (GPL) is included in this distribution, | |
5 | # in the file COPYING.GPL. | |
6 | # | |
7 | # As a special exception, if other files instantiate templates or use macros | |
8 | # or inline functions from this file, or you compile this file and link it | |
9 | # with other works to produce a work based on this file, this file | |
10 | # does not by itself cause the resulting work to be covered | |
11 | # by the GNU General Public License. | |
12 | # | |
13 | # However the source code for this file must still be made available | |
14 | # in accordance with section (3) of the GNU General Public License. | |
15 | # | |
16 | # This exception does not invalidate any other reasons why a work based | |
17 | # on this file might be covered by the GNU General Public License. | |
f365f614 CH |
18 | # |
19 | # Copyright (c) 2016-2018 Intra2net AG <info@intra2net.com> | |
3237d2a6 | 20 | |
e7d49180 CH |
21 | """ Unittests for log_read |
22 | ||
23 | Creates own thread to write data to a log file | |
e7d49180 CH |
24 | """ |
25 | ||
26 | import unittest | |
27 | from threading import Thread | |
28 | from tempfile import mkstemp | |
29 | import os | |
30 | import time | |
31 | import logging | |
ea8b01a3 | 32 | from warnings import warn |
e7d49180 | 33 | |
0dd2fb19 | 34 | from src.log_read import * |
e7d49180 | 35 | |
59281ef9 | 36 | # get best clock |
7628bc48 | 37 | perf_counter = time.perf_counter |
59281ef9 | 38 | |
7c00b0af CH |
39 | DEBUG = False |
40 | ||
e7d49180 CH |
41 | |
42 | class LogFileWriter(Thread): | |
43 | """ thread that creates and writes to given file """ | |
44 | ||
45 | def __init__(self, file_name, text_pattern, n_writes=None, | |
46 | pause_time=0.1, do_encode=None, use_logging=True): | |
0dd2fb19 | 47 | """ creates thread, daemon is True |
e7d49180 CH |
48 | |
49 | if n_writes is None, will write indefinitely; else writes text_pattern | |
01fe1580 | 50 | n_writes times, formatted with (counter, perf_counter) |
e7d49180 CH |
51 | If do_encode is True, will encode text to bytes and open file handle |
52 | in 'wb' mode; otherwise opens in 'wt' mode and writes unicode text. | |
53 | If use_logging is False, will open file and run file_handle.write; | |
54 | If use_logging is True, will create logger that logs to file and use | |
55 | logging.info (no file_handle.write) | |
56 | """ | |
01fe1580 CH |
57 | super(LogFileWriter, self).__init__() |
58 | self.daemon = True | |
e7d49180 CH |
59 | self.file_name = file_name |
60 | self.text_pattern = text_pattern | |
61 | self.n_writes = n_writes | |
62 | self.pause_time = pause_time | |
63 | self.do_encode = do_encode | |
64 | self.use_logging = use_logging | |
65 | ||
66 | def run(self): | |
67 | counter = 0 | |
68 | if self.do_encode: | |
69 | mode = 'wb' | |
70 | buffering = 0 # no buffering -- only allowed for byte mode | |
71 | else: | |
72 | mode = 'wt' | |
73 | buffering = 1 # line buffering -- only allowed for text mode | |
74 | ||
75 | if self.use_logging: | |
76 | logging.basicConfig(filename=self.file_name, level=logging.INFO, | |
77 | format='%(msg)s') | |
78 | while True: | |
79 | if self.n_writes is not None and counter >= self.n_writes: | |
80 | break | |
81 | self.write_and_sleep(logging.info, counter) | |
82 | counter += 1 | |
83 | else: | |
84 | with open(self.file_name, mode=mode, buffering=buffering) \ | |
85 | as file_handle: | |
86 | while True: | |
87 | if self.n_writes is not None and counter >= self.n_writes: | |
88 | break | |
89 | self.write_and_sleep(file_handle.write, counter) | |
90 | counter += 1 | |
91 | ||
92 | def write_and_sleep(self, write_func, counter): | |
d910eba5 CH |
93 | """ format text, write it using given function and sleep """ |
94 | if isinstance(self.text_pattern, (list, tuple)): | |
95 | text = self.text_pattern[counter] | |
96 | else: | |
97 | text = self.text_pattern | |
01fe1580 | 98 | text = text.format(counter, perf_counter()) |
d910eba5 | 99 | |
e7d49180 CH |
100 | if self.do_encode: |
101 | text = text.encode(self.do_encode) | |
102 | write_func(text) | |
e7d49180 CH |
103 | time.sleep(self.pause_time) |
104 | ||
105 | ||
106 | class LogReadTester(unittest.TestCase): | |
107 | """ class with all the tests """ | |
108 | ||
109 | def setUp(self): | |
110 | """ called before each test """ | |
7c00b0af CH |
111 | if DEBUG: |
112 | print('setup test') | |
e7d49180 CH |
113 | temp_handle, temp_name = mkstemp() |
114 | os.close(temp_handle) | |
115 | self.temp_file = temp_name | |
7c00b0af CH |
116 | if DEBUG: |
117 | print('created temp file ' + self.temp_file) | |
e7d49180 CH |
118 | |
119 | def tearDown(self): | |
120 | """ called after each test """ | |
7c00b0af CH |
121 | if DEBUG: |
122 | print('tear down test') | |
e7d49180 | 123 | if os.path.isfile(self.temp_file): |
7c00b0af CH |
124 | if DEBUG: |
125 | print('delete temp file' + self.temp_file) | |
e7d49180 CH |
126 | os.unlink(self.temp_file) |
127 | ||
d910eba5 CH |
128 | def helper_test_len(self, reader, n_expected): |
129 | """ helper function that tests length of vars in reader """ | |
130 | self.assertEqual(reader.n_sources(), n_expected) | |
131 | self.assertEqual(len(reader.file_objs), n_expected) | |
3e0b3965 | 132 | self.assertEqual(len(reader.file_handles), n_expected) |
d910eba5 CH |
133 | self.assertEqual(len(reader.descriptions), n_expected) |
134 | self.assertEqual(len(reader.ignore), n_expected) | |
135 | self.assertEqual(len(reader.last_sizes), n_expected) | |
e7d49180 CH |
136 | |
137 | def test_args(self): | |
138 | self.assertRaises(TypeError, IterativeReader) # no args | |
139 | self.assertRaises(ValueError, IterativeReader, [], 'test') | |
140 | self.assertRaises(ValueError, IterativeReader, [], ['test', ]) | |
141 | self.assertRaises(ValueError, IterativeReader, self.temp_file) | |
142 | self.assertRaises(ValueError, IterativeReader, [self.temp_file, ]) | |
143 | with open(self.temp_file, 'rt') as file_handle: | |
144 | reader = IterativeReader(file_handle) | |
d910eba5 | 145 | self.helper_test_len(reader, 1) |
e7d49180 | 146 | reader = IterativeReader([file_handle, ]) |
d910eba5 | 147 | self.helper_test_len(reader, 1) |
e7d49180 | 148 | reader = IterativeReader(file_handle, 'desc') |
d910eba5 | 149 | self.helper_test_len(reader, 1) |
e7d49180 | 150 | reader = IterativeReader([file_handle, ], ['desc', ]) |
d910eba5 | 151 | self.helper_test_len(reader, 1) |
e7d49180 | 152 | reader = IterativeReader(file_handle, ['desc', ]) |
d910eba5 | 153 | self.helper_test_len(reader, 1) |
e7d49180 CH |
154 | self.assertRaises(ValueError, IterativeReader, |
155 | [file_handle, ], 'desc', ) | |
156 | reader = IterativeReader([file_handle, file_handle], | |
157 | ['desc1', 'desc2']) | |
d910eba5 | 158 | self.helper_test_len(reader, 2) |
0dd2fb19 | 159 | reader = IterativeReader((file_handle for _ in range(5))) |
d910eba5 | 160 | self.helper_test_len(reader, 5) |
e7d49180 CH |
161 | self.assertRaises(ValueError, IterativeReader, |
162 | (file_handle for idx in range(5)), | |
163 | tuple('desc' for idx in range(4))) | |
164 | self.assertRaises(ValueError, IterativeReader, | |
165 | (file_handle for idx in range(5)), | |
166 | ('desc' for idx in range(6))) | |
167 | ||
168 | def test_simple_read(self): | |
169 | """ write fixed number of lines, see how fast they are retrieved """ | |
170 | ||
171 | # need newline only when writing text (because of write buffering) | |
172 | param_combinations = ('{0}:{1}\n', None, False), \ | |
173 | ('{0}:{1}\n', 'ascii', False), \ | |
174 | ('{0}:{1} ' , 'ascii', False) | |
175 | #('{0}:{1}\n', None , True), \ logging seems | |
176 | #('{0}:{1}\n', 'ascii', True), \ to buffer writes | |
177 | #('{0}:{1} ' , None , True), \ to files | |
178 | #('{0}:{1} ' , 'ascii', True) | |
179 | ||
180 | n_texts = 10 | |
181 | pause_time = 0.01 # 100 tps (texts per second) | |
182 | ||
183 | for text_pattern, encoding, use_logging in param_combinations: | |
184 | LogFileWriter(self.temp_file, text_pattern, n_writes=n_texts, | |
185 | pause_time=pause_time, do_encode=encoding, | |
186 | use_logging=use_logging).start() | |
7c00b0af CH |
187 | if DEBUG: |
188 | print('testing with log file {0}'.format(self.temp_file)) | |
189 | print('encoding is {0}, use logging = {1}'.format(encoding, | |
190 | use_logging)) | |
e7d49180 CH |
191 | time_diffs = [] |
192 | ||
193 | with open(self.temp_file, 'rt') as file_handle: | |
545f3458 | 194 | reader = IterativeReader(file_handle, keep_watching=True) |
d910eba5 | 195 | self.helper_test_len(reader, 1) |
ea8b01a3 | 196 | counter = -1 # we may have to adapt this manually |
aef38def | 197 | for desc, text, source_idx in reader: |
01fe1580 | 198 | receive_time = perf_counter() |
f75cc662 | 199 | self.assertEqual(desc, self.temp_file) |
aef38def | 200 | self.assertEqual(source_idx, 0) |
ea8b01a3 | 201 | counter += 1 |
e7d49180 | 202 | text = text.strip() |
7c00b0af CH |
203 | if DEBUG: |
204 | print('{1}: received text "{0}" at {2}' | |
205 | .format(text, counter, receive_time)) | |
ea8b01a3 CH |
206 | if counter == 0 and not text: |
207 | # if reader runs stat() before we write, we might get | |
208 | # a warning and one empty read here | |
209 | counter -= 1 | |
210 | warn('Got an empty read, you should have seen another ' | |
211 | 'warning about file shrinking', | |
212 | category=LogReadWarning) | |
213 | continue | |
e7d49180 CH |
214 | index = text.index(':') |
215 | count_text = int(text[:index].strip()) | |
216 | self.assertEqual(count_text, counter) | |
217 | write_time = float(text[index+1:].strip()) | |
58347979 | 218 | time_diffs.append((receive_time - write_time)*1000.) |
e7d49180 | 219 | if counter == n_texts-1: |
7c00b0af CH |
220 | if DEBUG: |
221 | print('stop since have {0} reads'.format(counter)) | |
e7d49180 | 222 | break |
7c00b0af CH |
223 | if DEBUG: |
224 | print('time diffs in ms: {0}'.format(time_diffs)) | |
58347979 CH |
225 | self.assertTrue(max(time_diffs) < 100., |
226 | 'read took more than 100ms (max was {0:.3f}ms)!' | |
6ab9df9b | 227 | .format(max(time_diffs))) |
e7d49180 | 228 | |
d910eba5 CH |
229 | def test_line_read(self): |
230 | """ write partial lines, full lines and multiple lines """ | |
231 | ||
232 | pause_time = 0.01 # 100 tps (texts per second) | |
233 | encoding = None | |
234 | use_logging = False | |
235 | texts = ['line0\n', 'line1\n', 'li', 'ne2\n', 'line3\n', | |
236 | 'line4\nline5\n', 'li', 'ne6\nli', 'ne7\nl', 'i', 'n', 'e', | |
237 | '8', '\n', 'l', 'ine9\nline10\nline1', '1', '\n', '\n', '\n', | |
238 | 'end\n', '\nend\n', '\n\nend\n\n'] | |
0dd2fb19 | 239 | lines_expected = ['line{0}'.format(idx) for idx in range(12)] + ['', '', ''] |
d910eba5 CH |
240 | |
241 | # create writer | |
242 | LogFileWriter(self.temp_file, texts, n_writes=len(texts), | |
243 | pause_time=pause_time, do_encode=encoding, | |
244 | use_logging=use_logging).start() | |
245 | ||
246 | # read | |
d910eba5 | 247 | with open(self.temp_file, 'rt') as file_handle: |
545f3458 | 248 | reader = LineReader(file_handle, keep_watching=True) |
d910eba5 CH |
249 | self.helper_test_len(reader, 1) |
250 | ||
aef38def | 251 | for line_expected, (_, line_read, _) in zip(lines_expected, reader): |
d910eba5 CH |
252 | if 'end' in line_read: |
253 | break | |
254 | else: | |
7c00b0af CH |
255 | if DEBUG: |
256 | print('expect "{0}", read "{1}"'.format(line_expected, | |
257 | line_read)) | |
d910eba5 CH |
258 | self.assertEqual(line_expected, line_read) |
259 | ||
077e8fa9 CH |
260 | def test_parse_syslog_lines(self): |
261 | """Test parsing a few fixed lines of syslog""" | |
262 | syslog_lines = """ | |
263 | Nov 8 08:10:01 system-name rsyslogd: [origin software="rsyslogd" swVersion="8.39.0" x-pid="1968" x-info="http://www.rsyslog.com"] rsyslogd was HUPed | |
264 | Nov 8 08:10:12 system-name squid[2762]: Starting new redirector helpers...#012 current master transaction: master58 | |
265 | Nov 8 08:10:28 system-name pop30[3922]: counts: retr=<0> top=<0> dele=<0> | |
266 | Nov 8 08:10:43 system-name pop3loc[3923]: counts: retr=<0> top=<0> dele=<0> | |
267 | Nov 8 08:10:44 system-name pingcheck[3004]: Status (0 down, limit=4, notify up now): report link up? | |
268 | Nov 8 08:10:44 system-name connd[2917]: [subsys_pingcheck] received notification that connection for id 1 is online | |
269 | Nov 8 08:10:44 system-name connd[2917]: [subsys_pingcheck] Connection [ConnInfo P1 (connection name): online] was confirmed online | |
270 | Nov 8 08:10:44 system-name connd[2917]: [connection_manager] Confirm that provider "P1" is online | |
271 | Nov 8 08:11:01 system-name mon[3563]: failure for intranator dirwatchd 1667891461 (NO SUMMARY) | |
272 | Nov 8 08:11:04 system-name lmtpunix[3962]: Delivered: <cmu-lmtpd-3962-1667891464-0@system-name.m.i2n> to mailbox: user.cyrus as uid: 49792 | |
273 | Nov 8 08:11:04 system-name lmtpunix[3962]: USAGE cyrus user: 0.000000 sys: 0.006803 | |
274 | Nov 8 08:11:20 system-name pop30[3982]: counts: retr=<0> top=<0> dele=<0> | |
275 | Oct 21 07:52:39 system-name avupdate[3671]: successfully installed new antivirus database | |
276 | Oct 21 07:52:39 system-name savapi_version_info[3973]: AVE=8.3.64.214, VDF=8.19.26.110, Released=21.10.2022 05:39 | |
277 | Oct 21 07:52:39 system-name connd[3180]: [connection_manager] online mode set to always online | |
278 | Oct 21 07:52:47 system-name kernel: REJECT local IN=eth0 OUT= MACSRC=68:4f:64:75:7b:82 MACDST=01:00:5e:00:00:01 MACPROTO=0800 SRC=123.45.67.89 DST=224.0.0.1 LEN=36 TOS=0x00 PREC=0x00 TTL=1 ID=34431 PROTO=ICMP TYPE=9 CODE=0 | |
279 | Oct 21 07:52:54 system-name lmtpunix[2715]: Delivered: <cmu-lmtpd-2715-1666331574-0@system-name.m.i2n> to mailbox: user.cyrus as uid: 46558 | |
280 | Oct 21 07:52:54 system-name lmtpunix[2715]: USAGE cyrus user: 0.010564 sys: 0.000000 | |
281 | Oct 21 07:53:08 system-name pop30[2703]: counts: retr=<0> top=<0> dele=<0> | |
282 | Oct 21 07:53:08 system-name pop3loc[2701]: counts: retr=<0> top=<0> dele=<0> | |
283 | Oct 21 07:53:30 system-name ntpd[3701]: adjusting local clock by -0.943974s | |
284 | Oct 21 07:54:15 system-name keymakerd[3206]: [acmeautorenew] Starting auto renew check. @acmeautorenew#285 | |
285 | Oct 21 07:54:15 system-name keymakerd[3206]: [acmeautorenew] Finishing auto renew thread. @acmeautorenew#206 | |
286 | Oct 21 07:54:23 system-name pop3loc[2701]: counts: retr=<0> top=<0> dele=<0> | |
287 | Oct 21 07:54:41 system-name pop30[2703]: counts: retr=<0> top=<0> dele=<0> | |
288 | Oct 21 07:54:51 system-name squid[3025]: Starting new redirector helpers...#012 current master transaction: master54 | |
289 | Oct 21 07:54:55 system-name lmtpunix[3997]: Delivered: <cmu-lmtpd-3997-1666331695-0@system-name.m.i2n> to mailbox: user.cyrus as uid: 46559 | |
290 | Oct 21 07:54:55 system-name lmtpunix[3997]: USAGE cyrus user: 0.002022 sys: 0.005926 | |
291 | """ | |
292 | lines = [line.lstrip() for line in syslog_lines.splitlines() if line.lstrip()] | |
293 | LogFileWriter(self.temp_file, lines, n_writes=len(lines)).start() | |
294 | with open(self.temp_file, 'rt') as file_handle: | |
295 | parser = LogParser(file_handle, SYS_LOG_PATTERN) | |
296 | for _, data, _ in parser: | |
297 | self.assertIsNotNone(data, f"Failed to parse {parser.last_unparsed_line}") | |
298 | ||
299 | def test_parse_proxy_lines(self): | |
300 | proxy_lines = """ | |
301 | 1667901672.645 0 127.0.0.1 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- - - | |
302 | 1667901792.812 0 127.0.0.1 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- - - | |
303 | 1667901912.997 0 127.0.0.1 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- - - | |
304 | 1667902032.168 0 127.0.0.1 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- - - | |
305 | 1667902055.130 571 192.168.1.1 TCP_TUNNEL/200 10403 CONNECT apod.nasa.gov:443 - HIER_DIRECT/apod.nasa.gov - - | |
306 | 1667902063.333 969 192.168.1.1 TCP_TUNNEL/200 174425 CONNECT www.startpage.com:443 - HIER_DIRECT/www.startpage.com - - | |
307 | 1667902063.352 17 192.168.1.1 TCP_TUNNEL/200 39 CONNECT www.startpage.com:443 - HIER_DIRECT/www.startpage.com - - | |
308 | 1667902063.539 24 192.168.1.1 TCP_TUNNEL/200 39 CONNECT www.startpage.com:443 - HIER_DIRECT/www.startpage.com - - | |
309 | 1667902063.545 207 192.168.1.1 TCP_TUNNEL/200 1720 CONNECT www.startpage.com:443 - HIER_DIRECT/www.startpage.com - - | |
310 | 1667902064.141 611 192.168.1.1 TCP_TUNNEL/200 10100 CONNECT www.startpage.com:443 - HIER_DIRECT/www.startpage.com - - | |
311 | 1667902072.816 974 192.168.1.1 TCP_MISS/200 981 POST http://r3.o.lencr.org/ - FIRSTUP_PARENT/127.0.0.1 application/ocsp-response - | |
312 | 1667902089.338 16331 192.168.1.1 TCP_TUNNEL/200 103739 CONNECT www.roma-pizza-tuebingen.de:443 - HIER_DIRECT/www.roma-pizza-tuebingen.de - - | |
313 | 1667902089.339 16332 192.168.1.1 TCP_TUNNEL/200 49795 CONNECT www.roma-pizza-tuebingen.de:443 - HIER_DIRECT/www.roma-pizza-tuebingen.de - - | |
314 | 1667902089.339 16330 192.168.1.1 TCP_TUNNEL/200 24641 CONNECT www.roma-pizza-tuebingen.de:443 - HIER_DIRECT/www.roma-pizza-tuebingen.de - - | |
315 | 1667902105.718 0 192.168.1.1 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- - - | |
316 | 1667902152.347 0 127.0.0.1 NONE_NONE/000 0 - error:transaction-end-before-headers - HIER_NONE/- - - | |
317 | """ | |
318 | lines = [line.lstrip() for line in proxy_lines.splitlines() if line.lstrip()] | |
319 | LogFileWriter(self.temp_file, lines, n_writes=len(lines)).start() | |
320 | with open(self.temp_file, 'rt') as file_handle: | |
321 | parser = LogParser(file_handle, PROXY_LOG_PATTERN) | |
322 | for _, data, _ in parser: | |
323 | self.assertIsNotNone(data, f"Failed to parse {parser.last_unparsed_line}") | |
324 | ||
325 | def test_parse_maillog_lines(self): | |
326 | mail_lines = """ | |
327 | Nov 7 10:07:33 system-name amavis[1]: SA info: rules: meta test I2N_RAZOR_ADJUST_4 has dependency 'RAZOR2_CF_RANGE_E8_51_100' with a zero score | |
328 | Nov 7 10:07:33 system-name amavis[1]: SpamControl: init_pre_fork on SpamAssassin done | |
329 | Nov 7 10:07:35 system-name quarantined[3574]: quarantined version 0.15 (build Jun 28 2022 17:26:39) up and running | |
330 | Nov 7 10:07:52 system-name mailreconfig[3713]: called by sh[3712]|generate[3663], mode update, changed files: aliases,recipients | |
331 | Nov 7 10:07:53 system-name postfix/postfix-script[3724]: refreshing the Postfix mail system | |
332 | Nov 7 10:07:53 system-name postfix/master[2548]: reload -- version 3.3.22, configuration /etc/postfix | |
333 | Nov 7 10:08:07 system-name mailreconfig[3851]: called by sh[3850]|generate[3804], mode update, changed files: aliases,recipients | |
334 | Nov 7 10:08:07 system-name postfix/postfix-script[3862]: refreshing the Postfix mail system | |
335 | Nov 7 10:08:07 system-name postfix/master[2548]: reload -- version 3.3.22, configuration /etc/postfix | |
336 | Nov 7 10:08:11 system-name postfix/smtpd[3933]: connect from system-name.net.lan[127.0.0.1] | |
337 | Nov 7 10:08:11 system-name postfix/smtpd[3933]: D9C626B: client=system-name.net.lan[127.0.0.1] | |
338 | Nov 7 10:08:11 system-name postfix/cleanup[3936]: D9C626B: message-id=<20221107090811.D9C626B@system-name.net.lan> | |
339 | Nov 7 10:08:11 system-name postfix/qmgr[3868]: D9C626B: from=<test-sender@system-name.net.lan>, size=10888, nrcpt=1 (queue active) | |
340 | Nov 7 10:08:11 system-name postfix/smtpd[3933]: disconnect from system-name.net.lan[127.0.0.1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5 | |
341 | Nov 7 10:08:11 system-name postfix/smtpd[3933]: connect from system-name.net.lan[127.0.0.1] | |
342 | Nov 7 10:08:11 system-name postfix/smtpd[3933]: E59146D: client=system-name.net.lan[127.0.0.1] | |
343 | Nov 7 10:08:11 system-name postfix/cleanup[3936]: E59146D: message-id=<20221107090811.E59146D@system-name.net.lan> | |
344 | Nov 7 10:08:11 system-name amavis[11]: (00011-01) LMTP::10024 /var/spool/vscan/amavis/tmp/amavis-20221107T100811-00011: <test-sender@system-name.net.lan> -> <test-recipient@system-name.net.lan> SIZE=10888 Received: from system-name.net.lan ([127.0.0.1]) by localhost (system-name.net.lan [127.0.0.1]) (amavisd-new, port 10024) with LMTP for <test-recipient@system-name.net.lan>; Mon, 7 Nov 2022 10:08:11 +0100 (CET) | |
345 | Nov 7 10:08:12 system-name postfix/qmgr[3868]: E59146D: from=<test-sender@system-name.net.lan>, size=9472, nrcpt=1 (queue active) | |
346 | Nov 7 10:08:12 system-name postfix/smtpd[3933]: disconnect from system-name.net.lan[127.0.0.1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5 | |
347 | Nov 7 10:08:12 system-name postfix/smtpd[3933]: connect from system-name.net.lan[127.0.0.1] | |
348 | Nov 7 10:08:12 system-name amavis[11]: (00011-01) Checking: q4eVqFn169Kq [127.0.0.1] <test-sender@system-name.net.lan> -> <test-recipient@system-name.net.lan> | |
349 | Nov 7 10:08:12 system-name amavis[11]: (00011-01) p.path BANNED:1 test-recipient@system-name.net.lan: "P=p003,L=1,M=multipart/mixed | P=p002,L=1/2,M=application/x-msdownload,T=exe,T=exe-ms,N=cloudcar.exe", matching_key="(?^i:\\.exe$)" | |
350 | Nov 7 10:08:12 system-name postfix/qmgr[3868]: 4B0CF70: from=<test-sender@system-name.net.lan>, size=164391, nrcpt=1 (queue active) | |
351 | """ | |
352 | lines = [line.lstrip() for line in mail_lines.splitlines() if line.lstrip()] | |
353 | LogFileWriter(self.temp_file, lines, n_writes=len(lines)).start() | |
354 | with open(self.temp_file, 'rt') as file_handle: | |
355 | parser = LogParser(file_handle, SYS_LOG_PATTERN) | |
356 | for _, data, _ in parser: | |
357 | self.assertIsNotNone(data, f"Failed to parse {parser.last_unparsed_line}") | |
358 | ||
0dd2fb19 CH |
359 | @unittest.skipIf(not os.access('/var/log/messages', os.R_OK), |
360 | "messages not accessible") | |
361 | def test_parse_messages(self): | |
362 | """Try parsing first 100 lines of messages if running on linux""" | |
363 | with LogParser.create_for('/var/log/messages', SYS_LOG_PATTERN) as parser: | |
364 | for line_count, (_, data, _) in enumerate(parser): | |
365 | if line_count > 100: | |
366 | break | |
367 | self.assertIsNotNone(data, f"Failed to parse {parser.last_unparsed_line}") | |
368 | ||
369 | @unittest.skipIf(not os.access('/var/log/syslog', os.R_OK), | |
370 | "syslog not accessible") | |
371 | def test_parse_syslog(self): | |
372 | """Try parsing first 100 lines of syslog if running on linux""" | |
373 | with LogParser.create_for('/var/log/syslog', SYS_LOG_PATTERN) as parser: | |
374 | for line_count, (_, data, _) in enumerate(parser): | |
375 | if line_count > 100: | |
376 | break | |
377 | self.assertIsNotNone(data, f"Failed to parse {parser.last_unparsed_line}") | |
378 | ||
379 | @unittest.skipIf(not os.access('/var/log/maillog', os.R_OK), | |
380 | "maillog not accessible") | |
381 | def test_parse_maillog(self): | |
382 | """Try parsing first 100 lines of maillog if running on linux""" | |
383 | with LogParser.create_for('/var/log/maillog', SYS_LOG_PATTERN) as parser: | |
384 | for line_count, (_, data, _) in enumerate(parser): | |
385 | if line_count > 100: | |
386 | break | |
387 | self.assertIsNotNone(data, f"Failed to parse {parser.last_unparsed_line}") | |
388 | ||
389 | @unittest.skipIf(not os.access('/var/log/squid/access.log', os.R_OK), | |
390 | "proxy log not accessible") | |
391 | def test_parse_proxy_log(self): | |
392 | """Try parsing first 100 lines of proxy log if running on linux""" | |
393 | with LogParser.create_for('/var/log/squid/access.log', PROXY_LOG_PATTERN) as parser: | |
394 | for line_count, (_, data, _) in enumerate(parser): | |
395 | if line_count > 100: | |
396 | break | |
397 | self.assertIsNotNone(data, f"Failed to parse {parser.last_unparsed_line}") | |
398 | ||
d910eba5 | 399 | |
e7d49180 CH |
400 | if __name__ == '__main__': |
401 | unittest.main() |