bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/acquisition/file_reader_test.go (about) 1 package acquisition 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 "testing" 8 "time" 9 10 "bitbucket.org/Aishee/synsec/pkg/types" 11 log "github.com/sirupsen/logrus" 12 "github.com/stretchr/testify/assert" 13 tomb "gopkg.in/tomb.v2" 14 ) 15 16 func TestAcquisCat(t *testing.T) { 17 18 tests := []struct { 19 cfg DataSourceCfg 20 //tombState 21 config_error string 22 read_error string 23 tomb_error string 24 lines int 25 }{ 26 { //missing filename(s) 27 cfg: DataSourceCfg{ 28 Mode: CAT_MODE, 29 }, 30 config_error: "no filename or filenames", 31 }, 32 { //forbiden file 33 cfg: DataSourceCfg{ 34 Mode: CAT_MODE, 35 Filename: "/etc/shadow", 36 }, 37 config_error: "unable to open /etc/shadow : permission denied", 38 }, 39 { //bad regexp 40 cfg: DataSourceCfg{ 41 Filename: "[a-", 42 Mode: CAT_MODE, 43 }, 44 config_error: "while globbing [a-: syntax error in pattern", 45 }, 46 { //inexisting file 47 cfg: DataSourceCfg{ 48 Filename: "/does/not/exists", 49 Mode: CAT_MODE, 50 }, 51 config_error: "no files to read for [/does/not/exists]", 52 }, 53 { //ok file 54 cfg: DataSourceCfg{ 55 Filename: "./tests/test.log", 56 Mode: CAT_MODE, 57 }, 58 lines: 1, 59 }, 60 { //invalid gz 61 cfg: DataSourceCfg{ 62 Filename: "./tests/badlog.gz", 63 Mode: CAT_MODE, 64 }, 65 lines: 0, 66 tomb_error: "failed to read gz ./tests/badlog.gz: EOF", 67 }, 68 { //good gz 69 cfg: DataSourceCfg{ 70 Filename: "./tests/test.log.gz", 71 Mode: CAT_MODE, 72 }, 73 lines: 1, 74 }, 75 } 76 77 for tidx, test := range tests { 78 fileSrc := new(FileSource) 79 err := fileSrc.Configure(test.cfg) 80 if test.config_error != "" { 81 assert.Contains(t, fmt.Sprintf("%s", err), test.config_error) 82 log.Infof("expected config error ok : %s", test.config_error) 83 continue 84 } else { 85 if err != nil { 86 t.Fatalf("%d/%d unexpected config error %s", tidx, len(tests), err) 87 } 88 } 89 90 out := make(chan types.Event) 91 tomb := tomb.Tomb{} 92 count := 0 93 94 err = fileSrc.StartReading(out, &tomb) 95 if test.read_error != "" { 96 assert.Contains(t, fmt.Sprintf("%s", err), test.read_error) 97 log.Infof("expected read error ok : %s", test.read_error) 98 continue 99 } else { 100 if err != nil { 101 t.Fatalf("%d/%d unexpected read error %s", tidx, len(tests), err) 102 } 103 } 104 105 READLOOP: 106 for { 107 select { 108 case <-out: 109 count++ 110 case <-time.After(1 * time.Second): 111 break READLOOP 112 } 113 } 114 115 if count != test.lines { 116 t.Fatalf("%d/%d expected %d line read, got %d", tidx, len(tests), test.lines, count) 117 } 118 119 if test.tomb_error != "" { 120 assert.Contains(t, fmt.Sprintf("%s", tomb.Err()), test.tomb_error) 121 log.Infof("expected tomb error ok : %s", test.read_error) 122 continue 123 } else { 124 if tomb.Err() != nil { 125 t.Fatalf("%d/%d unexpected tomb error %s", tidx, len(tests), tomb.Err()) 126 } 127 } 128 129 } 130 131 } 132 133 func TestTailKill(t *testing.T) { 134 cfg := DataSourceCfg{ 135 Filename: "./tests/test.log", 136 Mode: TAIL_MODE, 137 } 138 139 fileSrc := new(FileSource) 140 err := fileSrc.Configure(cfg) 141 if err != nil { 142 t.Fatalf("unexpected config error %s", err) 143 } 144 145 out := make(chan types.Event) 146 tb := tomb.Tomb{} 147 148 err = fileSrc.StartReading(out, &tb) 149 if err != nil { 150 t.Fatalf("unexpected read error %s", err) 151 } 152 time.Sleep(1 * time.Second) 153 if tb.Err() != tomb.ErrStillAlive { 154 t.Fatalf("unexpected tomb error %s (should be alive)", tb.Err()) 155 } 156 //kill it :> 157 tb.Kill(nil) 158 time.Sleep(1 * time.Second) 159 if tb.Err() != nil { 160 t.Fatalf("unexpected tomb error %s (should be dead)", tb.Err()) 161 } 162 163 } 164 165 func TestTailKillBis(t *testing.T) { 166 cfg := DataSourceCfg{ 167 Filename: "./tests/test.log", 168 Mode: TAIL_MODE, 169 } 170 171 fileSrc := new(FileSource) 172 err := fileSrc.Configure(cfg) 173 if err != nil { 174 t.Fatalf("unexpected config error %s", err) 175 } 176 177 out := make(chan types.Event) 178 tb := tomb.Tomb{} 179 180 err = fileSrc.StartReading(out, &tb) 181 if err != nil { 182 t.Fatalf("unexpected read error %s", err) 183 } 184 time.Sleep(1 * time.Second) 185 if tb.Err() != tomb.ErrStillAlive { 186 t.Fatalf("unexpected tomb error %s (should be alive)", tb.Err()) 187 } 188 //kill the underlying tomb of tailer 189 fileSrc.tails[0].Kill(fmt.Errorf("ratata")) 190 time.Sleep(1 * time.Second) 191 //it can be two errors : 192 if !strings.Contains(fmt.Sprintf("%s", tb.Err()), "dead reader for ./tests/test.log") && 193 !strings.Contains(fmt.Sprintf("%s", tb.Err()), "tail for ./tests/test.log is empty") { 194 t.Fatalf("unexpected error : %s", tb.Err()) 195 } 196 197 } 198 199 func TestTailRuntime(t *testing.T) { 200 //log.SetLevel(log.TraceLevel) 201 202 cfg := DataSourceCfg{ 203 Filename: "./tests/test.log", 204 Mode: TAIL_MODE, 205 } 206 207 fileSrc := new(FileSource) 208 err := fileSrc.Configure(cfg) 209 if err != nil { 210 t.Fatalf("unexpected config error %s", err) 211 } 212 213 out := make(chan types.Event) 214 tb := tomb.Tomb{} 215 count := 0 216 217 err = fileSrc.StartReading(out, &tb) 218 if err != nil { 219 t.Fatalf("unexpected read error %s", err) 220 } 221 222 time.Sleep(1 * time.Second) 223 //write data 224 f, err := os.OpenFile(cfg.Filename, os.O_APPEND|os.O_WRONLY, 0644) 225 if err != nil { 226 t.Fatal(err) 227 } 228 for i := 0; i < 5; i++ { 229 _, err := f.WriteString(fmt.Sprintf("ratata%d\n", i)) 230 if err != nil { 231 t.Fatal(err) 232 } 233 } 234 f.Close() 235 236 READLOOP: 237 for { 238 select { 239 case <-out: 240 count++ 241 case <-time.After(1 * time.Second): 242 break READLOOP 243 } 244 } 245 246 if count != 5 { 247 t.Fatalf("expected %d line read, got %d", 5, count) 248 } 249 250 if tb.Err() != tomb.ErrStillAlive { 251 t.Fatalf("unexpected tomb error %s", tb.Err()) 252 } 253 254 /*reset the file*/ 255 f, err = os.OpenFile(cfg.Filename, os.O_CREATE|os.O_WRONLY, 0644) 256 if err != nil { 257 t.Fatal(err) 258 } 259 _, err = f.WriteString("one log line\n") 260 if err != nil { 261 t.Fatal(err) 262 } 263 f.Close() 264 } 265 266 func TestAcquisTail(t *testing.T) { 267 268 tests := []struct { 269 cfg DataSourceCfg 270 //tombState 271 config_error string 272 read_error string 273 tomb_error string 274 lines int 275 }{ 276 { //missing filename(s) 277 cfg: DataSourceCfg{ 278 Mode: TAIL_MODE, 279 }, 280 config_error: "no filename or filenames", 281 }, 282 { //forbiden file 283 cfg: DataSourceCfg{ 284 Mode: TAIL_MODE, 285 Filename: "/etc/shadow", 286 }, 287 config_error: "unable to open /etc/shadow : permission denied", 288 }, 289 { //bad regexp 290 cfg: DataSourceCfg{ 291 Filename: "[a-", 292 Mode: TAIL_MODE, 293 }, 294 config_error: "while globbing [a-: syntax error in pattern", 295 }, 296 { //inexisting file 297 cfg: DataSourceCfg{ 298 Filename: "/does/not/exists", 299 Mode: TAIL_MODE, 300 }, 301 config_error: "no files to read for [/does/not/exists]", 302 }, 303 { //ok file 304 cfg: DataSourceCfg{ 305 Filename: "./tests/test.log", 306 Mode: TAIL_MODE, 307 }, 308 lines: 0, 309 tomb_error: "still alive", 310 }, 311 { //invalid gz 312 cfg: DataSourceCfg{ 313 Filename: "./tests/badlog.gz", 314 Mode: TAIL_MODE, 315 }, 316 lines: 0, 317 tomb_error: "still alive", 318 }, 319 { //good gz 320 cfg: DataSourceCfg{ 321 Filename: "./tests/test.log.gz", 322 Mode: TAIL_MODE, 323 }, 324 lines: 0, 325 tomb_error: "still alive", 326 }, 327 } 328 329 for tidx, test := range tests { 330 fileSrc := new(FileSource) 331 err := fileSrc.Configure(test.cfg) 332 if test.config_error != "" { 333 assert.Contains(t, fmt.Sprintf("%s", err), test.config_error) 334 log.Infof("expected config error ok : %s", test.config_error) 335 continue 336 } else { 337 if err != nil { 338 t.Fatalf("%d/%d unexpected config error %s", tidx, len(tests), err) 339 } 340 } 341 342 out := make(chan types.Event) 343 tomb := tomb.Tomb{} 344 count := 0 345 346 err = fileSrc.StartReading(out, &tomb) 347 if test.read_error != "" { 348 assert.Contains(t, fmt.Sprintf("%s", err), test.read_error) 349 log.Infof("expected read error ok : %s", test.read_error) 350 continue 351 } else { 352 if err != nil { 353 t.Fatalf("%d/%d unexpected read error %s", tidx, len(tests), err) 354 } 355 } 356 357 READLOOP: 358 for { 359 select { 360 case <-out: 361 count++ 362 case <-time.After(1 * time.Second): 363 break READLOOP 364 } 365 } 366 367 if count != test.lines { 368 t.Fatalf("%d/%d expected %d line read, got %d", tidx, len(tests), test.lines, count) 369 } 370 371 if test.tomb_error != "" { 372 assert.Contains(t, fmt.Sprintf("%s", tomb.Err()), test.tomb_error) 373 log.Infof("expected tomb error ok : %s", test.read_error) 374 continue 375 } else { 376 if tomb.Err() != nil { 377 t.Fatalf("%d/%d unexpected tomb error %s", tidx, len(tests), tomb.Err()) 378 } 379 } 380 381 } 382 383 }