Skip to content

Commit 5c121c4

Browse files
zshuang0316claude
andcommitted
tests: add test for ignore_active_older_files re-pickup on mtime update
Add flb_test_in_tail_ignore_active_older_files_reread_on_update to verify that a file excluded by ignore_active_older_files is re-picked up once its mtime is refreshed by a new write, and that reading resumes from the stored offset (only new content is delivered, not a re-read from the beginning). Uses rotate_wait=1s and refresh_interval=1s to exercise the purge and scan callbacks within a reasonable test window. Sets read_newly_discovered_files_from_head=false so that ctx->read_from_head stays false for scan-discovered files. Waits for msg1 to be consumed before starting the aging clock to avoid a flaky saved-offset race on slow machines. Uses wait_expected_num_with_timeout instead of fixed sleeps for synchronisation points that have observable output signals. expected=2: 1 for the initial msg1 read, 1 for msg2 picked up after re-add at the stored offset. Signed-off-by: zshuang0316 <zshuang0316@163.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3b06524 commit 5c121c4

1 file changed

Lines changed: 101 additions & 0 deletions

File tree

tests/runtime/in_tail.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,6 +2038,106 @@ void flb_test_in_tail_ignore_active_older_files()
20382038
test_tail_ctx_destroy(ctx);
20392039
}
20402040

2041+
/*
2042+
* Verify that a file excluded by ignore_active_older_files is re-picked up
2043+
* once its mtime is refreshed by a new write.
2044+
*
2045+
* Sequence:
2046+
* 1. Write msg1 → engine reads it (count = 1)
2047+
* 2. Wait 4 s → purge fires (rotate_wait=1s), file is >2s old; inode
2048+
* registered as aged-out and file removed from monitoring
2049+
* 3. Write msg2 → mtime is now fresh
2050+
* 4. Wait 3 s → scan fires (refresh_interval=1s), sees fresh mtime;
2051+
* unregisters aged-out entry and re-adds file at the
2052+
* stored offset (file->offset saved at age-out time);
2053+
* engine reads only msg2 (count += 1)
2054+
* 5. Assert count == 2
2055+
*/
2056+
void flb_test_in_tail_ignore_active_older_files_reread_on_update()
2057+
{
2058+
struct flb_lib_out_cb cb_data;
2059+
struct test_tail_ctx *ctx;
2060+
char *file[] = {"source_file_reread.log"};
2061+
char *path = "source_file_reread.log";
2062+
char *msg = "TEST LINE";
2063+
const int expected = 2;
2064+
const int expected_before_rotate = 1;
2065+
int ret;
2066+
int num;
2067+
int unused;
2068+
2069+
clear_output_num();
2070+
2071+
cb_data.cb = cb_count_msgpack;
2072+
cb_data.data = &unused;
2073+
2074+
ctx = test_tail_ctx_create(&cb_data, &file[0], sizeof(file)/sizeof(char *), FLB_TRUE);
2075+
if (!TEST_CHECK(ctx != NULL)) {
2076+
TEST_MSG("test_ctx_create failed");
2077+
return;
2078+
}
2079+
2080+
ret = flb_input_set(ctx->flb, ctx->o_ffd,
2081+
"path", path,
2082+
"ignore_older", "2s",
2083+
"rotate_wait", "1s",
2084+
"refresh_interval", "1s",
2085+
"read_newly_discovered_files_from_head", "false",
2086+
"ignore_active_older_files", "on",
2087+
NULL);
2088+
TEST_CHECK(ret == 0);
2089+
2090+
ret = flb_start(ctx->flb);
2091+
if (!TEST_CHECK(ret == 0)) {
2092+
test_tail_ctx_destroy(ctx);
2093+
return;
2094+
}
2095+
2096+
/* Write first message and allow it to be flushed */
2097+
ret = write_msg(ctx, msg, strlen(msg));
2098+
if (!TEST_CHECK(ret > 0)) {
2099+
test_tail_ctx_destroy(ctx);
2100+
return;
2101+
}
2102+
2103+
/* Wait until msg1 is consumed before starting the aging clock. */
2104+
wait_expected_num_with_timeout(5000, expected_before_rotate, &num);
2105+
if (!TEST_CHECK(num == expected_before_rotate)) {
2106+
TEST_MSG("msg1 not consumed in time. got=%d", num);
2107+
test_tail_ctx_destroy(ctx);
2108+
return;
2109+
}
2110+
2111+
/*
2112+
* Wait long enough for the purge callback (rotate_wait=1s) to fire and
2113+
* detect that the file's mtime is older than ignore_older=2s, which
2114+
* removes the file from monitoring and registers its inode as aged-out.
2115+
*/
2116+
flb_time_msleep(4000);
2117+
2118+
/* Append new content: this updates mtime so the file is no longer old */
2119+
ret = write_msg(ctx, msg, strlen(msg));
2120+
if (!TEST_CHECK(ret > 0)) {
2121+
test_tail_ctx_destroy(ctx);
2122+
return;
2123+
}
2124+
2125+
/*
2126+
* Wait for the scan callback (refresh_interval=1s) to re-evaluate the
2127+
* aged-out entry, find the fresh mtime, unregister the entry, and
2128+
* re-add the file. The file is re-added at the stored offset (the read
2129+
* position saved when the file was aged out), so only msg2 — the content
2130+
* that refreshed the mtime — is flushed (count += 1).
2131+
*/
2132+
wait_expected_num_with_timeout(5000, expected, &num);
2133+
2134+
if (!TEST_CHECK(num == expected)) {
2135+
TEST_MSG("output num error. expect=%d got=%d", expected, num);
2136+
}
2137+
2138+
test_tail_ctx_destroy(ctx);
2139+
}
2140+
20412141
void flb_test_inotify_watcher_false()
20422142
{
20432143
struct flb_lib_out_cb cb_data;
@@ -2693,6 +2793,7 @@ TEST_LIST = {
26932793
{"skip_empty_lines_crlf", flb_test_skip_empty_lines_crlf},
26942794
{"ignore_older", flb_test_ignore_older},
26952795
{"ignore_active_older_files", flb_test_in_tail_ignore_active_older_files},
2796+
{"ignore_active_older_files_reread_on_update", flb_test_in_tail_ignore_active_older_files_reread_on_update},
26962797
#ifdef FLB_HAVE_INOTIFY
26972798
{"inotify_watcher_false", flb_test_inotify_watcher_false},
26982799
#endif /* FLB_HAVE_INOTIFY */

0 commit comments

Comments
 (0)