master
go 245 lines 5.08 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package logs
4
5 import (
6 "bufio"
7 "fmt"
8 "io"
9 "os"
10 "path/filepath"
11 "testing"
12 "time"
13
14 "github.com/stretchr/testify/assert"
15 "github.com/stretchr/testify/require"
16 )
17
18 func TestReader_Read(t *testing.T) {
19 reader, teardown := prepareTestReader(t)
20 defer teardown()
21
22 r := testReader{bufio.NewReader(reader)}
23 filename := reader.CurrentFilename()
24 numLogs := 5
25 var sum int
26
27 for i := range 10 {
28 appendLogs(t, filename, time.Millisecond*10, numLogs)
29 n, err := r.readUntilEOF()
30 sum += n
31
32 assert.Equal(t, io.EOF, err)
33 assert.Equal(t, numLogs*(i+1), sum)
34 }
35 }
36
37 func TestReader_Read_HandleFileRotation(t *testing.T) {
38 reader, teardown := prepareTestReader(t)
39 defer teardown()
40
41 r := testReader{bufio.NewReader(reader)}
42 filename := reader.CurrentFilename()
43 numLogs := 5
44 rotateFile(t, filename)
45 appendLogs(t, filename, time.Millisecond*10, numLogs)
46
47 n, err := r.readUntilEOFTimes(maxEOF)
48 assert.Equal(t, io.EOF, err)
49 assert.Equal(t, 0, n)
50
51 appendLogs(t, filename, time.Millisecond*10, numLogs)
52 n, err = r.readUntilEOF()
53 assert.Equal(t, io.EOF, err)
54 assert.Equal(t, numLogs, n)
55 }
56
57 func TestReader_Read_HandleFileRotationWithDelay(t *testing.T) {
58 reader, teardown := prepareTestReader(t)
59 defer teardown()
60
61 r := testReader{bufio.NewReader(reader)}
62 filename := reader.CurrentFilename()
63 _ = os.Remove(filename)
64
65 // trigger reopen first time
66 n, err := r.readUntilEOFTimes(maxEOF)
67 assert.Equal(t, ErrNoMatchedFile, err)
68 assert.Equal(t, 0, n)
69
70 f, err := os.Create(filename)
71 require.NoError(t, err)
72 _ = f.Close()
73
74 // trigger reopen 2nd time
75 n, err = r.readUntilEOF()
76 assert.Equal(t, io.EOF, err)
77 assert.Equal(t, 0, n)
78
79 numLogs := 5
80 appendLogs(t, filename, time.Millisecond*10, numLogs)
81 n, err = r.readUntilEOF()
82 assert.Equal(t, io.EOF, err)
83 assert.Equal(t, numLogs, n)
84 }
85
86 func TestReader_Close(t *testing.T) {
87 reader, teardown := prepareTestReader(t)
88 defer teardown()
89
90 assert.NoError(t, reader.Close())
91 assert.Nil(t, reader.file)
92 }
93
94 func TestReader_Close_NilFile(t *testing.T) {
95 var r Reader
96 assert.NoError(t, r.Close())
97 }
98
99 func TestOpen(t *testing.T) {
100 tempFileName1 := prepareTempFile(t, "*-web_log-open-test-1.log")
101 tempFileName2 := prepareTempFile(t, "*-web_log-open-test-2.log")
102 tempFileName3 := prepareTempFile(t, "*-web_log-open-test-3.log")
103 defer func() {
104 _ = os.Remove(tempFileName1)
105 _ = os.Remove(tempFileName2)
106 _ = os.Remove(tempFileName3)
107 }()
108
109 makePath := func(s string) string {
110 return filepath.Join(os.TempDir(), s)
111 }
112
113 tests := []struct {
114 name string
115 path string
116 exclude string
117 err bool
118 }{
119 {
120 name: "match without exclude",
121 path: makePath("*-web_log-open-test-[1-3].log"),
122 },
123 {
124 name: "match with exclude",
125 path: makePath("*-web_log-open-test-[1-3].log"),
126 exclude: makePath("*-web_log-open-test-[2-3].log"),
127 },
128 {
129 name: "exclude everything",
130 path: makePath("*-web_log-open-test-[1-3].log"),
131 exclude: makePath("*"),
132 err: true,
133 },
134 {
135 name: "no match",
136 path: makePath("*-web_log-no-match-test-[1-3].log"),
137 err: true,
138 },
139 {
140 name: "bad path pattern",
141 path: "[qw",
142 err: true,
143 },
144 {
145 name: "bad exclude path pattern",
146 path: "[qw",
147 err: true,
148 },
149 }
150
151 for _, tt := range tests {
152 t.Run(tt.name, func(t *testing.T) {
153 r, err := Open(tt.path, tt.exclude, nil)
154
155 if tt.err {
156 assert.Error(t, err)
157 } else {
158 assert.NoError(t, err)
159 assert.NotNil(t, r.file)
160 _ = r.Close()
161 }
162 })
163 }
164 }
165
166 func TestReader_CurrentFilename(t *testing.T) {
167 reader, teardown := prepareTestReader(t)
168 defer teardown()
169
170 assert.Equal(t, reader.file.Name(), reader.CurrentFilename())
171 }
172
173 type testReader struct {
174 *bufio.Reader
175 }
176
177 func (r *testReader) readUntilEOF() (n int, err error) {
178 for {
179 _, err = r.ReadBytes('\n')
180 if err != nil {
181 break
182 }
183 n++
184 }
185 return n, err
186 }
187
188 func (r *testReader) readUntilEOFTimes(times int) (sum int, err error) {
189 var n int
190 for range times {
191 n, err = r.readUntilEOF()
192 if err != io.EOF {
193 break
194 }
195 sum += n
196 }
197 return sum, err
198 }
199
200 func prepareTempFile(t *testing.T, pattern string) string {
201 t.Helper()
202 f, err := os.CreateTemp("", pattern)
203 require.NoError(t, err)
204 return f.Name()
205 }
206
207 func prepareTestReader(t *testing.T) (reader *Reader, teardown func()) {
208 t.Helper()
209 filename := prepareTempFile(t, "*-web_log-test.log")
210 f, err := os.Open(filename)
211 require.NoError(t, err)
212
213 teardown = func() {
214 _ = os.Remove(filename)
215 _ = reader.file.Close()
216 }
217 reader = &Reader{
218 file: f,
219 path: filename,
220 }
221 return reader, teardown
222 }
223
224 func rotateFile(t *testing.T, filename string) {
225 t.Helper()
226 require.NoError(t, os.Remove(filename))
227 f, err := os.Create(filename)
228 require.NoError(t, err)
229 _ = f.Close()
230 }
231
232 func appendLogs(t *testing.T, filename string, interval time.Duration, numOfLogs int) {
233 t.Helper()
234 base := filepath.Base(filename)
235 file, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND, os.ModeAppend)
236 require.NoError(t, err)
237 require.NotNil(t, file)
238 defer func() { _ = file.Close() }()
239
240 for i := range numOfLogs {
241 _, err = fmt.Fprintln(file, "line", i, "filename", base)
242 require.NoError(t, err)
243 time.Sleep(interval)
244 }
245 }