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
32using Poco::FileChannel;
33using Poco::Message;
34using Poco::AutoPtr;
35using Poco::TemporaryFile;
36using Poco::Thread;
37using Poco::File;
38using Poco::Path;
39using Poco::Timestamp;
40using Poco::NumberFormatter;
41using Poco::DateTime;
42using Poco::LocalDateTime;
43using Poco::DateTimeFormatter;
44using Poco::DateTimeFormat;
45using Poco::DirectoryIterator;
46using Poco::InvalidArgumentException;
47
48
49FileChannelTest::FileChannelTest(const std::string& rName): CppUnit::TestCase(rName)
50{
51}
52
53
54FileChannelTest::~FileChannelTest()
55{
56}
57
58
59void 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
88void 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
116void 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
145void 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
174void 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
203void 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
232void 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
261void 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
290void 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
316void 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
346void 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
385void 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
425void 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
441void 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
472void 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
503void 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
519void 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
547void FileChannelTest::setUp()
548{
549}
550
551
552void FileChannelTest::tearDown()
553{
554}
555
556
557void 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
583std::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
592template <class DT>
593std::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
633CppUnit::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