1 | // |
2 | // FileChannelTest.cpp |
3 | // |
4 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
5 | // and Contributors. |
6 | // |
7 | // SPDX-License-Identifier: BSL-1.0 |
8 | // |
9 | |
10 | |
11 | #include "FileChannelTest.h" |
12 | #include "Poco/CppUnit/TestCaller.h" |
13 | #include "Poco/CppUnit/TestSuite.h" |
14 | #include "Poco/FileChannel.h" |
15 | #include "Poco/Message.h" |
16 | #include "Poco/AutoPtr.h" |
17 | #include "Poco/TemporaryFile.h" |
18 | #include "Poco/Thread.h" |
19 | #include "Poco/File.h" |
20 | #include "Poco/Path.h" |
21 | #include "Poco/Timestamp.h" |
22 | #include "Poco/DateTime.h" |
23 | #include "Poco/LocalDateTime.h" |
24 | #include "Poco/DateTimeFormatter.h" |
25 | #include "Poco/DateTimeFormat.h" |
26 | #include "Poco/NumberFormatter.h" |
27 | #include "Poco/DirectoryIterator.h" |
28 | #include "Poco/Exception.h" |
29 | #include <vector> |
30 | |
31 | |
32 | using Poco::FileChannel; |
33 | using Poco::Message; |
34 | using Poco::AutoPtr; |
35 | using Poco::TemporaryFile; |
36 | using Poco::Thread; |
37 | using Poco::File; |
38 | using Poco::Path; |
39 | using Poco::Timestamp; |
40 | using Poco::NumberFormatter; |
41 | using Poco::DateTime; |
42 | using Poco::LocalDateTime; |
43 | using Poco::DateTimeFormatter; |
44 | using Poco::DateTimeFormat; |
45 | using Poco::DirectoryIterator; |
46 | using Poco::InvalidArgumentException; |
47 | |
48 | |
49 | FileChannelTest::FileChannelTest(const std::string& rName): CppUnit::TestCase(rName) |
50 | { |
51 | } |
52 | |
53 | |
54 | FileChannelTest::~FileChannelTest() |
55 | { |
56 | } |
57 | |
58 | |
59 | void FileChannelTest::testRotateBySize() |
60 | { |
61 | std::string name = filename(); |
62 | try |
63 | { |
64 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
65 | pChannel->setProperty(FileChannel::PROP_ROTATION, "2 K" ); |
66 | pChannel->open(); |
67 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
68 | for (int i = 0; i < 200; ++i) |
69 | { |
70 | pChannel->log(msg); |
71 | } |
72 | File f(name + ".0" ); |
73 | assertTrue (f.exists()); |
74 | f = name + ".1" ; |
75 | assertTrue (f.exists()); |
76 | f = name + ".2" ; |
77 | assertTrue (!f.exists()); |
78 | } |
79 | catch (...) |
80 | { |
81 | remove(name); |
82 | throw; |
83 | } |
84 | remove(name); |
85 | } |
86 | |
87 | |
88 | void FileChannelTest::testRotateByAge() |
89 | { |
90 | std::string name = filename(); |
91 | try |
92 | { |
93 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
94 | pChannel->setProperty(FileChannel::PROP_ROTATION, "2 seconds" ); |
95 | pChannel->open(); |
96 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
97 | for (int i = 0; i < 15; ++i) |
98 | { |
99 | pChannel->log(msg); |
100 | Thread::sleep(300); |
101 | } |
102 | File f(name + ".0" ); |
103 | assertTrue (f.exists()); |
104 | f = name + ".1" ; |
105 | assertTrue (f.exists()); |
106 | } |
107 | catch (...) |
108 | { |
109 | remove(name); |
110 | throw; |
111 | } |
112 | remove(name); |
113 | } |
114 | |
115 | |
116 | void FileChannelTest::testRotateAtTimeDayUTC() |
117 | { |
118 | std::string name = filename(); |
119 | try |
120 | { |
121 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
122 | pChannel->setProperty(FileChannel::PROP_TIMES, "utc" ); |
123 | pChannel->setProperty(FileChannel::PROP_ROTATION, rotation<DateTime>(DAY_HOUR_MIN)); |
124 | pChannel->open(); |
125 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
126 | int min = DateTime().minute(); |
127 | while (DateTime().minute() == min) |
128 | { |
129 | pChannel->log(msg); |
130 | Thread::sleep(1000); |
131 | } |
132 | pChannel->log(msg); |
133 | File f(name + ".0" ); |
134 | assertTrue (f.exists()); |
135 | } |
136 | catch (...) |
137 | { |
138 | remove(name); |
139 | throw; |
140 | } |
141 | remove(name); |
142 | } |
143 | |
144 | |
145 | void FileChannelTest::testRotateAtTimeDayLocal() |
146 | { |
147 | std::string name = filename(); |
148 | try |
149 | { |
150 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
151 | pChannel->setProperty(FileChannel::PROP_TIMES, "local" ); |
152 | pChannel->setProperty(FileChannel::PROP_ROTATION, rotation<LocalDateTime>(DAY_HOUR_MIN)); |
153 | pChannel->open(); |
154 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
155 | int min = DateTime().minute(); |
156 | while (DateTime().minute() == min) |
157 | { |
158 | pChannel->log(msg); |
159 | Thread::sleep(1000); |
160 | } |
161 | pChannel->log(msg); |
162 | File f(name + ".0" ); |
163 | assertTrue (f.exists()); |
164 | } |
165 | catch (...) |
166 | { |
167 | remove(name); |
168 | throw; |
169 | } |
170 | remove(name); |
171 | } |
172 | |
173 | |
174 | void FileChannelTest::testRotateAtTimeHourUTC() |
175 | { |
176 | std::string name = filename(); |
177 | try |
178 | { |
179 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
180 | pChannel->setProperty(FileChannel::PROP_TIMES, "utc" ); |
181 | pChannel->setProperty(FileChannel::PROP_ROTATION, rotation<DateTime>(HOUR_MIN)); |
182 | pChannel->open(); |
183 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
184 | int min = DateTime().minute(); |
185 | while (DateTime().minute() == min) |
186 | { |
187 | pChannel->log(msg); |
188 | Thread::sleep(1000); |
189 | } |
190 | pChannel->log(msg); |
191 | File f(name + ".0" ); |
192 | assertTrue (f.exists()); |
193 | } |
194 | catch (...) |
195 | { |
196 | remove(name); |
197 | throw; |
198 | } |
199 | remove(name); |
200 | } |
201 | |
202 | |
203 | void FileChannelTest::testRotateAtTimeHourLocal() |
204 | { |
205 | std::string name = filename(); |
206 | try |
207 | { |
208 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
209 | pChannel->setProperty(FileChannel::PROP_TIMES, "local" ); |
210 | pChannel->setProperty(FileChannel::PROP_ROTATION, rotation<LocalDateTime>(HOUR_MIN)); |
211 | pChannel->open(); |
212 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
213 | int min = DateTime().minute(); |
214 | while (DateTime().minute() == min) |
215 | { |
216 | pChannel->log(msg); |
217 | Thread::sleep(1000); |
218 | } |
219 | pChannel->log(msg); |
220 | File f(name + ".0" ); |
221 | assertTrue (f.exists()); |
222 | } |
223 | catch (...) |
224 | { |
225 | remove(name); |
226 | throw; |
227 | } |
228 | remove(name); |
229 | } |
230 | |
231 | |
232 | void FileChannelTest::testRotateAtTimeMinUTC() |
233 | { |
234 | std::string name = filename(); |
235 | try |
236 | { |
237 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
238 | pChannel->setProperty(FileChannel::PROP_TIMES, "utc" ); |
239 | pChannel->setProperty(FileChannel::PROP_ROTATION, rotation<DateTime>(MIN)); |
240 | pChannel->open(); |
241 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
242 | int min = DateTime().minute(); |
243 | while (DateTime().minute() == min) |
244 | { |
245 | pChannel->log(msg); |
246 | Thread::sleep(1000); |
247 | } |
248 | pChannel->log(msg); |
249 | File f(name + ".0" ); |
250 | assertTrue (f.exists()); |
251 | } |
252 | catch (...) |
253 | { |
254 | remove(name); |
255 | throw; |
256 | } |
257 | remove(name); |
258 | } |
259 | |
260 | |
261 | void FileChannelTest::testRotateAtTimeMinLocal() |
262 | { |
263 | std::string name = filename(); |
264 | try |
265 | { |
266 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
267 | pChannel->setProperty(FileChannel::PROP_TIMES, "local" ); |
268 | pChannel->setProperty(FileChannel::PROP_ROTATION, rotation<LocalDateTime>(MIN)); |
269 | pChannel->open(); |
270 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
271 | int min = DateTime().minute(); |
272 | while (DateTime().minute() == min) |
273 | { |
274 | pChannel->log(msg); |
275 | Thread::sleep(1000); |
276 | } |
277 | pChannel->log(msg); |
278 | File f(name + ".0" ); |
279 | assertTrue (f.exists()); |
280 | } |
281 | catch (...) |
282 | { |
283 | remove(name); |
284 | throw; |
285 | } |
286 | remove(name); |
287 | } |
288 | |
289 | |
290 | void FileChannelTest::testArchive() |
291 | { |
292 | std::string name = filename(); |
293 | try |
294 | { |
295 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
296 | pChannel->setProperty(FileChannel::PROP_ROTATION, "2 K" ); |
297 | pChannel->setProperty(FileChannel::PROP_ARCHIVE, "number" ); |
298 | pChannel->open(); |
299 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
300 | for (int i = 0; i < 200; ++i) |
301 | { |
302 | pChannel->log(msg); |
303 | } |
304 | File f(name + ".0" ); |
305 | assertTrue (f.exists()); |
306 | } |
307 | catch (...) |
308 | { |
309 | remove(name); |
310 | throw; |
311 | } |
312 | remove(name); |
313 | } |
314 | |
315 | |
316 | void FileChannelTest::testCompress() |
317 | { |
318 | std::string name = filename(); |
319 | try |
320 | { |
321 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
322 | pChannel->setProperty(FileChannel::PROP_ROTATION, "1 K" ); |
323 | pChannel->setProperty(FileChannel::PROP_ARCHIVE, "number" ); |
324 | pChannel->setProperty(FileChannel::PROP_COMPRESS, "true" ); |
325 | pChannel->open(); |
326 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
327 | for (int i = 0; i < 200; ++i) |
328 | { |
329 | pChannel->log(msg); |
330 | } |
331 | Thread::sleep(3000); // allow time for background compression |
332 | File f0(name + ".0.gz" ); |
333 | assertTrue (f0.exists()); |
334 | File f1(name + ".1.gz" ); |
335 | assertTrue (f1.exists()); |
336 | } |
337 | catch (...) |
338 | { |
339 | remove(name); |
340 | throw; |
341 | } |
342 | remove(name); |
343 | } |
344 | |
345 | |
346 | void FileChannelTest::purgeAge(const std::string& pa) |
347 | { |
348 | std::string name = filename(); |
349 | try |
350 | { |
351 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
352 | pChannel->setProperty(FileChannel::PROP_ROTATION, "1 K" ); |
353 | pChannel->setProperty(FileChannel::PROP_ARCHIVE, "number" ); |
354 | pChannel->setProperty(FileChannel::PROP_PURGEAGE, pa); |
355 | pChannel->open(); |
356 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
357 | for (int i = 0; i < 200; ++i) |
358 | { |
359 | pChannel->log(msg); |
360 | } |
361 | File f0(name + ".0" ); |
362 | assertTrue (f0.exists()); |
363 | File f1(name + ".1" ); |
364 | assertTrue (f1.exists()); |
365 | File f2(name + ".2" ); |
366 | assertTrue (f2.exists()); |
367 | |
368 | Thread::sleep(5000); |
369 | for (int i = 0; i < 50; ++i) |
370 | { |
371 | pChannel->log(msg); |
372 | } |
373 | |
374 | assertTrue (!f2.exists()); |
375 | } |
376 | catch (...) |
377 | { |
378 | remove(name); |
379 | throw; |
380 | } |
381 | remove(name); |
382 | } |
383 | |
384 | |
385 | void FileChannelTest::noPurgeAge(const std::string& npa) |
386 | { |
387 | std::string name = filename(); |
388 | |
389 | try |
390 | { |
391 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
392 | pChannel->setProperty(FileChannel::PROP_ROTATION, "1 K" ); |
393 | pChannel->setProperty(FileChannel::PROP_ARCHIVE, "number" ); |
394 | pChannel->setProperty(FileChannel::PROP_PURGEAGE, npa); |
395 | pChannel->open(); |
396 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
397 | for (int i = 0; i < 200; ++i) |
398 | { |
399 | pChannel->log(msg); |
400 | } |
401 | File f0(name + ".0" ); |
402 | assertTrue (f0.exists()); |
403 | File f1(name + ".1" ); |
404 | assertTrue (f1.exists()); |
405 | File f2(name + ".2" ); |
406 | assertTrue (f2.exists()); |
407 | |
408 | Thread::sleep(5000); |
409 | for (int i = 0; i < 50; ++i) |
410 | { |
411 | pChannel->log(msg); |
412 | } |
413 | |
414 | assertTrue (f2.exists()); |
415 | } |
416 | catch (...) |
417 | { |
418 | remove(name); |
419 | throw; |
420 | } |
421 | remove(name); |
422 | } |
423 | |
424 | |
425 | void FileChannelTest::testPurgeAge() |
426 | { |
427 | purgeAge("5 seconds" ); |
428 | try |
429 | { |
430 | noPurgeAge("0 seconds" ); |
431 | fail ("must fail" ); |
432 | } catch (InvalidArgumentException&) |
433 | { |
434 | } |
435 | |
436 | noPurgeAge("" ); |
437 | noPurgeAge("none" ); |
438 | } |
439 | |
440 | |
441 | void FileChannelTest::purgeCount(const std::string& pc) |
442 | { |
443 | std::string name = filename(); |
444 | try |
445 | { |
446 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
447 | pChannel->setProperty(FileChannel::PROP_ROTATION, "1 K" ); |
448 | pChannel->setProperty(FileChannel::PROP_ARCHIVE, "number" ); |
449 | pChannel->setProperty(FileChannel::PROP_PURGECOUNT, pc); |
450 | pChannel->open(); |
451 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
452 | for (int i = 0; i < 200; ++i) |
453 | { |
454 | pChannel->log(msg); |
455 | Thread::sleep(50); |
456 | } |
457 | File f0(name + ".0" ); |
458 | assertTrue (f0.exists()); |
459 | File f1(name + ".1" ); |
460 | assertTrue (f1.exists()); |
461 | File f2(name + ".2" ); |
462 | assertTrue (!f2.exists()); |
463 | } catch (...) |
464 | { |
465 | remove(name); |
466 | throw; |
467 | } |
468 | remove(name); |
469 | } |
470 | |
471 | |
472 | void FileChannelTest::noPurgeCount(const std::string& npc) |
473 | { |
474 | std::string name = filename(); |
475 | try |
476 | { |
477 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
478 | pChannel->setProperty(FileChannel::PROP_ROTATION, "1 K" ); |
479 | pChannel->setProperty(FileChannel::PROP_ARCHIVE, "number" ); |
480 | pChannel->setProperty(FileChannel::PROP_PURGECOUNT, npc); |
481 | pChannel->open(); |
482 | Message msg("source" , "This is a log file entry" , Message::PRIO_INFORMATION); |
483 | for (int i = 0; i < 200; ++i) |
484 | { |
485 | pChannel->log(msg); |
486 | Thread::sleep(50); |
487 | } |
488 | File f0(name + ".0" ); |
489 | assertTrue (f0.exists()); |
490 | File f1(name + ".1" ); |
491 | assertTrue (f1.exists()); |
492 | File f2(name + ".2" ); |
493 | assertTrue (f2.exists()); |
494 | } catch (...) |
495 | { |
496 | remove(name); |
497 | throw; |
498 | } |
499 | remove(name); |
500 | } |
501 | |
502 | |
503 | void FileChannelTest::testPurgeCount() |
504 | { |
505 | purgeCount("2" ); |
506 | try |
507 | { |
508 | noPurgeCount("0" ); |
509 | fail("must fail" ); |
510 | } catch (InvalidArgumentException&) |
511 | { |
512 | } |
513 | |
514 | noPurgeCount("" ); |
515 | noPurgeCount("none" ); |
516 | } |
517 | |
518 | |
519 | void FileChannelTest::testWrongPurgeOption() |
520 | { |
521 | std::string name = filename(); |
522 | AutoPtr<FileChannel> pChannel = new FileChannel(name); |
523 | pChannel->setProperty(FileChannel::PROP_PURGEAGE, "5 seconds" ); |
524 | |
525 | try |
526 | { |
527 | pChannel->setProperty(FileChannel::PROP_PURGEAGE, "peace" ); |
528 | fail("must fail" ); |
529 | } catch (InvalidArgumentException) |
530 | { |
531 | assertTrue (pChannel->getProperty(FileChannel::PROP_PURGEAGE) == "5 seconds" ); |
532 | } |
533 | |
534 | try |
535 | { |
536 | pChannel->setProperty(FileChannel::PROP_PURGECOUNT, "peace" ); |
537 | fail("must fail" ); |
538 | } catch (InvalidArgumentException) |
539 | { |
540 | assertTrue (pChannel->getProperty(FileChannel::PROP_PURGEAGE) == "5 seconds" ); |
541 | } |
542 | |
543 | remove(name); |
544 | } |
545 | |
546 | |
547 | void FileChannelTest::setUp() |
548 | { |
549 | } |
550 | |
551 | |
552 | void FileChannelTest::tearDown() |
553 | { |
554 | } |
555 | |
556 | |
557 | void FileChannelTest::remove(const std::string& baseName) |
558 | { |
559 | DirectoryIterator it(Path::current()); |
560 | DirectoryIterator end; |
561 | std::vector<std::string> files; |
562 | while (it != end) |
563 | { |
564 | if (it.name().find(baseName) == 0) |
565 | { |
566 | files.push_back(it.name()); |
567 | } |
568 | ++it; |
569 | } |
570 | for (std::vector<std::string>::iterator it = files.begin(); it != files.end(); ++it) |
571 | { |
572 | try |
573 | { |
574 | File f(*it); |
575 | f.remove(); |
576 | } catch (...) |
577 | { |
578 | } |
579 | } |
580 | } |
581 | |
582 | |
583 | std::string FileChannelTest::filename() const |
584 | { |
585 | std::string name = "log_" ; |
586 | name.append(DateTimeFormatter::format(Timestamp(), "%Y%m%d%H%M%S" )); |
587 | name.append(".log" ); |
588 | return name; |
589 | } |
590 | |
591 | |
592 | template <class DT> |
593 | std::string FileChannelTest::rotation(TimeRotation rtype) const |
594 | { |
595 | DT now; |
596 | std::string rotation; |
597 | |
598 | int day = now.dayOfWeek(); |
599 | int min = now.minute(); |
600 | int hour = now.hour(); |
601 | if (++min == 60) |
602 | { |
603 | ++hour; |
604 | min = 0; |
605 | } |
606 | if (hour == 24) |
607 | { |
608 | hour = 0; |
609 | ++day; |
610 | day %= 7; |
611 | } |
612 | |
613 | switch (rtype) |
614 | { |
615 | case DAY_HOUR_MIN: // day,hh:m, |
616 | rotation = DateTimeFormat::WEEKDAY_NAMES[day]; |
617 | rotation += ',' + NumberFormatter::format0(hour, 2) + ':' + NumberFormatter::format0(min, 2); |
618 | break; |
619 | case HOUR_MIN: // hh:mm |
620 | rotation = NumberFormatter::format0(hour, 2) + ':' + NumberFormatter::format0(min, 2); |
621 | break; |
622 | case MIN: // mm |
623 | rotation = ':' + NumberFormatter::format0(min, 2); |
624 | break; |
625 | default: |
626 | rotation = "" ; |
627 | break; |
628 | } |
629 | return rotation; |
630 | } |
631 | |
632 | |
633 | CppUnit::Test* FileChannelTest::suite() |
634 | { |
635 | CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("FileChannelTest" ); |
636 | |
637 | CppUnit_addTest(pSuite, FileChannelTest, testRotateBySize); |
638 | CppUnit_addTest(pSuite, FileChannelTest, testRotateByAge); |
639 | CppUnit_addTest(pSuite, FileChannelTest, testRotateAtTimeDayUTC); |
640 | CppUnit_addTest(pSuite, FileChannelTest, testRotateAtTimeDayLocal); |
641 | CppUnit_addTest(pSuite, FileChannelTest, testRotateAtTimeHourUTC); |
642 | CppUnit_addTest(pSuite, FileChannelTest, testRotateAtTimeHourLocal); |
643 | CppUnit_addTest(pSuite, FileChannelTest, testRotateAtTimeMinUTC); |
644 | CppUnit_addTest(pSuite, FileChannelTest, testRotateAtTimeMinLocal); |
645 | CppUnit_addTest(pSuite, FileChannelTest, testArchive); |
646 | CppUnit_addTest(pSuite, FileChannelTest, testCompress); |
647 | CppUnit_addTest(pSuite, FileChannelTest, testPurgeAge); |
648 | CppUnit_addTest(pSuite, FileChannelTest, testPurgeCount); |
649 | CppUnit_addTest(pSuite, FileChannelTest, testWrongPurgeOption); |
650 | |
651 | return pSuite; |
652 | } |
653 | |