1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.io.input;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertNull;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24 import static org.junit.jupiter.api.Assertions.fail;
25
26 import java.io.BufferedOutputStream;
27 import java.io.BufferedReader;
28 import java.io.File;
29 import java.io.FileNotFoundException;
30 import java.io.IOException;
31 import java.io.InputStreamReader;
32 import java.io.OutputStreamWriter;
33 import java.io.RandomAccessFile;
34 import java.io.Writer;
35 import java.nio.charset.Charset;
36 import java.nio.charset.StandardCharsets;
37 import java.nio.file.Files;
38 import java.nio.file.StandardOpenOption;
39 import java.nio.file.attribute.FileTime;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.concurrent.CountDownLatch;
45 import java.util.concurrent.Executor;
46 import java.util.concurrent.Executors;
47 import java.util.concurrent.ScheduledThreadPoolExecutor;
48 import java.util.concurrent.TimeUnit;
49
50 import org.apache.commons.io.FileUtils;
51 import org.apache.commons.io.IOUtils;
52 import org.apache.commons.io.RandomAccessFileMode;
53 import org.apache.commons.io.TestResources;
54 import org.apache.commons.io.test.TestUtils;
55 import org.junit.jupiter.api.Test;
56 import org.junit.jupiter.api.io.TempDir;
57
58
59
60
61 public class TailerTest {
62
63 private static final class NonStandardTailable implements Tailer.Tailable {
64
65 private final File file;
66
67 public NonStandardTailable(final File file) {
68 this.file = file;
69 }
70
71 @Override
72 public Tailer.RandomAccessResourceBridge getRandomAccess(final String mode) throws FileNotFoundException {
73 return new Tailer.RandomAccessResourceBridge() {
74
75 private final RandomAccessFile randomAccessFile = new RandomAccessFile(file, mode);
76
77 @Override
78 public void close() throws IOException {
79 randomAccessFile.close();
80 }
81
82 @Override
83 public long getPointer() throws IOException {
84 return randomAccessFile.getFilePointer();
85 }
86
87 @Override
88 public int read(final byte[] b) throws IOException {
89 return randomAccessFile.read(b);
90 }
91
92 @Override
93 public void seek(final long position) throws IOException {
94 randomAccessFile.seek(position);
95 }
96 };
97 }
98
99 @Override
100 public boolean isNewer(final FileTime fileTime) throws IOException {
101 return FileUtils.isFileNewer(file, fileTime);
102 }
103
104 @Override
105 public FileTime lastModifiedFileTime() throws IOException {
106 return FileUtils.lastModifiedFileTime(file);
107 }
108
109 @Override
110 public long size() {
111 return file.length();
112 }
113 }
114
115
116
117
118 private static final class TestTailerListener extends TailerListenerAdapter {
119
120
121 private final List<String> lines = Collections.synchronizedList(new ArrayList<>());
122
123 private final CountDownLatch latch;
124
125 volatile Exception exception;
126
127 volatile int notFound;
128
129 volatile int rotated;
130
131 volatile int initialized;
132
133 volatile int reachedEndOfFile;
134
135 public TestTailerListener() {
136 latch = new CountDownLatch(1);
137 }
138
139 public TestTailerListener(final int expectedLines) {
140 latch = new CountDownLatch(expectedLines);
141 }
142
143 public boolean awaitExpectedLines(final long timeout, final TimeUnit timeUnit) throws InterruptedException {
144 return latch.await(timeout, timeUnit);
145 }
146
147 public void clear() {
148 lines.clear();
149 }
150
151 @Override
152 public void endOfFileReached() {
153 reachedEndOfFile++;
154 }
155
156 @Override
157 public void fileNotFound() {
158 notFound++;
159 }
160
161 @Override
162 public void fileRotated() {
163 rotated++;
164 }
165
166 public List<String> getLines() {
167 return lines;
168 }
169
170 @Override
171 public void handle(final Exception e) {
172 exception = e;
173 }
174
175 @Override
176 public void handle(final String line) {
177 lines.add(line);
178 latch.countDown();
179 }
180
181 @Override
182 public void init(final Tailer tailer) {
183 initialized++;
184 }
185 }
186
187 private static final int TEST_BUFFER_SIZE = 1024;
188
189 private static final int TEST_DELAY_MILLIS = 1500;
190
191 @TempDir
192 public static File temporaryFolder;
193
194 protected void createFile(final File file, final long size) throws IOException {
195 assertTrue(file.getParentFile().exists(), () -> "Cannot create file " + file + " as the parent directory does not exist");
196 try (BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()))) {
197 TestUtils.generateTestData(output, size);
198 }
199
200
201
202 RandomAccessFile reader = null;
203 try {
204 while (reader == null) {
205 try {
206 reader = RandomAccessFileMode.READ_ONLY.create(file);
207 } catch (final FileNotFoundException ignore) {
208
209 }
210 TestUtils.sleepQuietly(200L);
211 }
212 } finally {
213 IOUtils.closeQuietly(reader);
214 }
215
216 assertTrue(file.exists());
217 assertEquals(size, file.length());
218 }
219
220 @Test
221 @SuppressWarnings("squid:S2699")
222 public void testBufferBreak() throws Exception {
223 final long delay = 50;
224
225 final File file = new File(temporaryFolder, "testBufferBreak.txt");
226 createFile(file, 0);
227 writeString(file, "SBTOURIST\n");
228
229 final TestTailerListener listener = new TestTailerListener();
230 try (Tailer tailer = new Tailer(file, listener, delay, false, 1)) {
231 final Thread thread = new Thread(tailer);
232 thread.start();
233
234 List<String> lines = listener.getLines();
235 while (lines.isEmpty() || !lines.get(lines.size() - 1).equals("SBTOURIST")) {
236 lines = listener.getLines();
237 }
238
239 listener.clear();
240 }
241 }
242
243 @Test
244 public void testBuilderWithNonStandardTailable() throws Exception {
245 final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen-and-buffersize-and-charset.txt");
246 createFile(file, 0);
247 final TestTailerListener listener = new TestTailerListener(1);
248 try (Tailer tailer = Tailer.builder()
249 .setExecutorService(Executors.newSingleThreadExecutor())
250 .setTailable(new NonStandardTailable(file))
251 .setTailerListener(listener)
252 .get()) {
253 assertTrue(tailer.getTailable() instanceof NonStandardTailable);
254 validateTailer(listener, file);
255 }
256 }
257
258 @Test
259 public void testCreate() throws Exception {
260 final File file = new File(temporaryFolder, "tailer-create.txt");
261 createFile(file, 0);
262 final TestTailerListener listener = new TestTailerListener(1);
263 try (Tailer tailer = Tailer.create(file, listener)) {
264 validateTailer(listener, file);
265 }
266 }
267
268 @Test
269 public void testCreateWithDelay() throws Exception {
270 final File file = new File(temporaryFolder, "tailer-create-with-delay.txt");
271 createFile(file, 0);
272 final TestTailerListener listener = new TestTailerListener(1);
273 try (Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS)) {
274 validateTailer(listener, file);
275 }
276 }
277
278 @Test
279 public void testCreateWithDelayAndFromStart() throws Exception {
280 final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start.txt");
281 createFile(file, 0);
282 final TestTailerListener listener = new TestTailerListener(1);
283 try (Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false)) {
284 validateTailer(listener, file);
285 }
286 }
287
288 @Test
289 public void testCreateWithDelayAndFromStartWithBufferSize() throws Exception {
290 final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-buffersize.txt");
291 createFile(file, 0);
292 final TestTailerListener listener = new TestTailerListener(1);
293 try (Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, TEST_BUFFER_SIZE)) {
294 validateTailer(listener, file);
295 }
296 }
297
298 @Test
299 public void testCreateWithDelayAndFromStartWithReopenAndBufferSize() throws Exception {
300 final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen-and-buffersize.txt");
301 createFile(file, 0);
302 final TestTailerListener listener = new TestTailerListener(1);
303 try (Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
304 validateTailer(listener, file);
305 }
306 }
307
308 @Test
309 public void testCreateWithDelayAndFromStartWithReopenAndBufferSizeAndCharset() throws Exception {
310 final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen-and-buffersize-and-charset.txt");
311 createFile(file, 0);
312 final TestTailerListener listener = new TestTailerListener(1);
313 try (Tailer tailer = Tailer.create(file, StandardCharsets.UTF_8, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
314 validateTailer(listener, file);
315 }
316 }
317
318 @Test
319 public void testCreatorWithDelayAndFromStartWithReopen() throws Exception {
320 final File file = new File(temporaryFolder, "tailer-create-with-delay-and-from-start-with-reopen.txt");
321 createFile(file, 0);
322 final TestTailerListener listener = new TestTailerListener(1);
323 try (Tailer tailer = Tailer.create(file, listener, TEST_DELAY_MILLIS, false, false)) {
324 validateTailer(listener, file);
325 }
326 }
327
328
329
330
331 @Test
332 public void testInterrupt() throws Exception {
333 final File file = new File(temporaryFolder, "nosuchfile");
334 assertFalse(file.exists(), "nosuchfile should not exist");
335 final TestTailerListener listener = new TestTailerListener();
336
337 final int delay = 1000;
338 final int idle = 50;
339 try (Tailer tailer = new Tailer(file, listener, delay, false, IOUtils.DEFAULT_BUFFER_SIZE)) {
340 final Thread thread = new Thread(tailer);
341 thread.setDaemon(true);
342 thread.start();
343 TestUtils.sleep(idle);
344 thread.interrupt();
345 TestUtils.sleep(delay + idle);
346 assertNotNull(listener.exception, "Missing InterruptedException");
347 assertTrue(listener.exception instanceof InterruptedException, "Unexpected Exception: " + listener.exception);
348 assertEquals(1, listener.initialized, "Expected init to be called");
349 assertTrue(listener.notFound > 0, "fileNotFound should be called");
350 assertEquals(0, listener.rotated, "fileRotated should be not be called");
351 assertEquals(0, listener.reachedEndOfFile, "end of file never reached");
352 }
353 }
354
355 @Test
356 public void testIO335() throws Exception {
357
358 final long delayMillis = 50;
359 final File file = new File(temporaryFolder, "tailer-testio334.txt");
360 createFile(file, 0);
361 final TestTailerListener listener = new TestTailerListener();
362 try (Tailer tailer = new Tailer(file, listener, delayMillis, false)) {
363 final Thread thread = new Thread(tailer);
364 thread.start();
365
366
367 writeString(file, "CRLF\r\n", "LF\n", "CR\r", "CRCR\r\r", "trail");
368 final long testDelayMillis = delayMillis * 10;
369 TestUtils.sleep(testDelayMillis);
370 final List<String> lines = listener.getLines();
371 assertEquals(4, lines.size(), "line count");
372 assertEquals("CRLF", lines.get(0), "line 1");
373 assertEquals("LF", lines.get(1), "line 2");
374 assertEquals("CR", lines.get(2), "line 3");
375 assertEquals("CRCR\r", lines.get(3), "line 4");
376 }
377 }
378
379 @Test
380 @SuppressWarnings("squid:S2699")
381 public void testLongFile() throws Exception {
382 final long delay = 50;
383
384 final File file = new File(temporaryFolder, "testLongFile.txt");
385 createFile(file, 0);
386 try (Writer writer = Files.newBufferedWriter(file.toPath(), StandardOpenOption.APPEND)) {
387 for (int i = 0; i < 100000; i++) {
388 writer.write("LineLineLineLineLineLineLineLineLineLine\n");
389 }
390 writer.write("SBTOURIST\n");
391 }
392
393 final TestTailerListener listener = new TestTailerListener();
394 try (Tailer tailer = new Tailer(file, listener, delay, false)) {
395
396
397
398 final Thread thread = new Thread(tailer);
399 thread.start();
400
401 List<String> lines = listener.getLines();
402 while (lines.isEmpty() || !lines.get(lines.size() - 1).equals("SBTOURIST")) {
403 lines = listener.getLines();
404 }
405
406
407 listener.clear();
408 }
409 }
410
411 @Test
412 public void testMultiByteBreak() throws Exception {
413
414 final long delay = 50;
415 final File origin = TestResources.getFile("test-file-utf8.bin");
416 final File file = new File(temporaryFolder, "testMultiByteBreak.txt");
417 createFile(file, 0);
418 final TestTailerListener listener = new TestTailerListener();
419 final String osname = System.getProperty("os.name");
420 final boolean isWindows = osname.startsWith("Windows");
421
422 final Charset charsetUTF8 = StandardCharsets.UTF_8;
423 try (Tailer tailer = new Tailer(file, charsetUTF8, listener, delay, false, isWindows, IOUtils.DEFAULT_BUFFER_SIZE)) {
424 final Thread thread = new Thread(tailer);
425 thread.start();
426
427 try (Writer out = new OutputStreamWriter(Files.newOutputStream(file.toPath()), charsetUTF8);
428 BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(origin.toPath()), charsetUTF8))) {
429 final List<String> lines = new ArrayList<>();
430 String line;
431 while ((line = reader.readLine()) != null) {
432 out.write(line);
433 out.write("\n");
434 lines.add(line);
435 }
436 out.close();
437
438 final long testDelayMillis = delay * 10;
439 TestUtils.sleep(testDelayMillis);
440 final List<String> tailerlines = listener.getLines();
441 assertEquals(lines.size(), tailerlines.size(), "line count");
442 for (int i = 0, len = lines.size(); i < len; i++) {
443 final String expected = lines.get(i);
444 final String actual = tailerlines.get(i);
445 if (!expected.equals(actual)) {
446 fail("Line: " + i + "\nExp: (" + expected.length() + ") " + expected + "\nAct: (" + actual.length() + ") " + actual);
447 }
448 }
449 }
450 }
451 }
452
453 @Test
454 public void testSimpleConstructor() throws Exception {
455 final File file = new File(temporaryFolder, "tailer-simple-constructor.txt");
456 createFile(file, 0);
457 final TestTailerListener listener = new TestTailerListener(1);
458 try (Tailer tailer = new Tailer(file, listener)) {
459 final Thread thread = new Thread(tailer);
460 thread.start();
461 validateTailer(listener, file);
462 }
463 }
464
465 @Test
466 public void testSimpleConstructorWithDelay() throws Exception {
467 final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay.txt");
468 createFile(file, 0);
469 final TestTailerListener listener = new TestTailerListener(1);
470 try (Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS)) {
471 final Thread thread = new Thread(tailer);
472 thread.start();
473 validateTailer(listener, file);
474 }
475 }
476
477 @Test
478 public void testSimpleConstructorWithDelayAndFromStart() throws Exception {
479 final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start.txt");
480 createFile(file, 0);
481 final TestTailerListener listener = new TestTailerListener(1);
482 try (Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false)) {
483 final Thread thread = new Thread(tailer);
484 thread.start();
485 validateTailer(listener, file);
486 }
487 }
488
489 @Test
490 public void testSimpleConstructorWithDelayAndFromStartWithBufferSize() throws Exception {
491 final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-buffersize.txt");
492 createFile(file, 0);
493 final TestTailerListener listener = new TestTailerListener(1);
494 try (Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, TEST_BUFFER_SIZE)) {
495 final Thread thread = new Thread(tailer);
496 thread.start();
497 validateTailer(listener, file);
498 }
499 }
500
501 @Test
502 public void testSimpleConstructorWithDelayAndFromStartWithReopen() throws Exception {
503 final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-reopen.txt");
504 createFile(file, 0);
505 final TestTailerListener listener = new TestTailerListener(1);
506 try (Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, false)) {
507 final Thread thread = new Thread(tailer);
508 thread.start();
509 validateTailer(listener, file);
510 }
511 }
512
513 @Test
514 public void testSimpleConstructorWithDelayAndFromStartWithReopenAndBufferSize() throws Exception {
515 final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-reopen-and-buffersize.txt");
516 createFile(file, 0);
517 final TestTailerListener listener = new TestTailerListener(1);
518 try (Tailer tailer = new Tailer(file, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
519 final Thread thread = new Thread(tailer);
520 thread.start();
521 validateTailer(listener, file);
522 }
523 }
524
525 @Test
526 public void testSimpleConstructorWithDelayAndFromStartWithReopenAndBufferSizeAndCharset() throws Exception {
527 final File file = new File(temporaryFolder, "tailer-simple-constructor-with-delay-and-from-start-with-reopen-and-buffersize-and-charset.txt");
528 createFile(file, 0);
529 final TestTailerListener listener = new TestTailerListener(1);
530 try (Tailer tailer = new Tailer(file, StandardCharsets.UTF_8, listener, TEST_DELAY_MILLIS, false, true, TEST_BUFFER_SIZE)) {
531 final Thread thread = new Thread(tailer);
532 thread.start();
533 validateTailer(listener, file);
534 }
535 }
536
537 @Test
538 public void testStopWithNoFile() throws Exception {
539 final File file = new File(temporaryFolder, "nosuchfile");
540 assertFalse(file.exists(), "nosuchfile should not exist");
541 final TestTailerListener listener = new TestTailerListener();
542 final int delay = 100;
543 final int idle = 50;
544 try (Tailer tailer = Tailer.create(file, listener, delay, false)) {
545 TestUtils.sleep(idle);
546 }
547 TestUtils.sleep(delay + idle);
548 if (listener.exception != null) {
549 listener.exception.printStackTrace();
550 }
551 assertNull(listener.exception, "Should not generate Exception");
552 assertEquals(1, listener.initialized, "Expected init to be called");
553 assertTrue(listener.notFound > 0, "fileNotFound should be called");
554 assertEquals(0, listener.rotated, "fileRotated should be not be called");
555 assertEquals(0, listener.reachedEndOfFile, "end of file never reached");
556 }
557
558 @Test
559 public void testStopWithNoFileUsingExecutor() throws Exception {
560 final File file = new File(temporaryFolder, "nosuchfile");
561 assertFalse(file.exists(), "nosuchfile should not exist");
562 final TestTailerListener listener = new TestTailerListener();
563 final int delay = 100;
564 final int idle = 50;
565 try (Tailer tailer = new Tailer(file, listener, delay, false)) {
566 final Executor exec = new ScheduledThreadPoolExecutor(1);
567 exec.execute(tailer);
568 TestUtils.sleep(idle);
569 }
570 TestUtils.sleep(delay + idle);
571 assertNull(listener.exception, "Should not generate Exception");
572 assertEquals(1, listener.initialized, "Expected init to be called");
573 assertTrue(listener.notFound > 0, "fileNotFound should be called");
574 assertEquals(0, listener.rotated, "fileRotated should be not be called");
575 assertEquals(0, listener.reachedEndOfFile, "end of file never reached");
576 }
577
578 @Test
579 public void testTailer() throws Exception {
580
581
582 final long delayMillis = 50;
583 final File file = new File(temporaryFolder, "tailer1-test.txt");
584 createFile(file, 0);
585 final TestTailerListener listener = new TestTailerListener();
586 final String osname = System.getProperty("os.name");
587 final boolean isWindows = osname.startsWith("Windows");
588 try (Tailer tailer = new Tailer(file, listener, delayMillis, false, isWindows)) {
589 final Thread thread = new Thread(tailer);
590 thread.start();
591
592
593 write(file, "Line one", "Line two");
594 final long testDelayMillis = delayMillis * 10;
595 TestUtils.sleep(testDelayMillis);
596 List<String> lines = listener.getLines();
597 assertEquals(2, lines.size(), "1 line count");
598 assertEquals("Line one", lines.get(0), "1 line 1");
599 assertEquals("Line two", lines.get(1), "1 line 2");
600 listener.clear();
601
602
603 write(file, "Line three");
604 TestUtils.sleep(testDelayMillis);
605 lines = listener.getLines();
606 assertEquals(1, lines.size(), "2 line count");
607 assertEquals("Line three", lines.get(0), "2 line 3");
608 listener.clear();
609
610
611 lines = FileUtils.readLines(file, StandardCharsets.UTF_8);
612 assertEquals(3, lines.size(), "3 line count");
613 assertEquals("Line one", lines.get(0), "3 line 1");
614 assertEquals("Line two", lines.get(1), "3 line 2");
615 assertEquals("Line three", lines.get(2), "3 line 3");
616
617
618 file.delete();
619 assertFalse(file.exists(), "File should not exist");
620 createFile(file, 0);
621 assertTrue(file.exists(), "File should now exist");
622 TestUtils.sleep(testDelayMillis);
623
624
625 write(file, "Line four");
626 TestUtils.sleep(testDelayMillis);
627 lines = listener.getLines();
628 assertEquals(1, lines.size(), "4 line count");
629 assertEquals("Line four", lines.get(0), "4 line 3");
630 listener.clear();
631
632
633 thread.interrupt();
634 TestUtils.sleep(testDelayMillis * 4);
635 write(file, "Line five");
636 assertEquals(0, listener.getLines().size(), "4 line count");
637 assertNotNull(listener.exception, "Missing InterruptedException");
638 assertTrue(listener.exception instanceof InterruptedException, "Unexpected Exception: " + listener.exception);
639 assertEquals(1, listener.initialized, "Expected init to be called");
640
641
642 assertEquals(1, listener.rotated, "fileRotated should be called");
643 }
644 }
645
646 @Test
647 public void testTailerEndOfFileReached() throws Exception {
648
649 final long delayMillis = 50;
650 final long testDelayMillis = delayMillis * 10;
651 final File file = new File(temporaryFolder, "tailer-eof-test.txt");
652 createFile(file, 0);
653 final TestTailerListener listener = new TestTailerListener();
654 final String osname = System.getProperty("os.name");
655 final boolean isWindows = osname.startsWith("Windows");
656 try (Tailer tailer = new Tailer(file, listener, delayMillis, false, isWindows)) {
657 final Thread thread = new Thread(tailer);
658 thread.start();
659
660
661 write(file, "line1", "line2", "line3");
662 TestUtils.sleep(testDelayMillis);
663
664
665 write(file, "line4", "line5", "line6");
666 TestUtils.sleep(testDelayMillis);
667
668
669 write(file, "line7", "line8", "line9");
670 TestUtils.sleep(testDelayMillis);
671
672
673 assertTrue(listener.reachedEndOfFile >= 3, "end of file reached at least 3 times");
674 }
675 }
676
677 @Test
678 public void testTailerEof() throws Exception {
679
680 final long delayMillis = 100;
681 final File file = new File(temporaryFolder, "tailer2-test.txt");
682 createFile(file, 0);
683 final TestTailerListener listener = new TestTailerListener();
684 try (Tailer tailer = new Tailer(file, listener, delayMillis, false)) {
685 final Thread thread = new Thread(tailer);
686 thread.start();
687
688
689 writeString(file, "Line");
690
691 TestUtils.sleep(delayMillis * 2);
692 List<String> lines = listener.getLines();
693 assertEquals(0, lines.size(), "1 line count");
694
695 writeString(file, " one\n");
696 TestUtils.sleep(delayMillis * 4);
697 lines = listener.getLines();
698
699 assertEquals(1, lines.size(), "1 line count");
700 assertEquals("Line one", lines.get(0), "1 line 1");
701
702 listener.clear();
703 }
704 }
705
706 private void validateTailer(final TestTailerListener listener, final File file) throws IOException, InterruptedException {
707 write(file, "foo");
708 final int timeout = 30;
709 final TimeUnit timeoutUnit = TimeUnit.SECONDS;
710 assertTrue(listener.awaitExpectedLines(timeout, timeoutUnit), () -> String.format("await timed out after %s %s", timeout, timeoutUnit));
711 assertEquals(listener.getLines(), Arrays.asList("foo"), "lines");
712 }
713
714
715 private void write(final File file, final String... lines) throws IOException {
716 try (Writer writer = Files.newBufferedWriter(file.toPath(), StandardOpenOption.APPEND)) {
717 for (final String line : lines) {
718 writer.write(line + "\n");
719 }
720 }
721 }
722
723
724 private void writeString(final File file, final String... strings) throws IOException {
725 try (Writer writer = Files.newBufferedWriter(file.toPath(), StandardOpenOption.APPEND)) {
726 for (final String string : strings) {
727 writer.write(string);
728 }
729 }
730 }
731 }