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  }