//go:build windows package wineventlogacquisition import ( "runtime" "testing" "time" "github.com/crowdsecurity/crowdsec/pkg/exprhelpers" "github.com/crowdsecurity/crowdsec/pkg/types" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/sys/windows/svc/eventlog" "gopkg.in/tomb.v2" ) func TestBadConfiguration(t *testing.T) { if runtime.GOOS != "windows" { t.Skip("Skipping test on non-windows OS") } tests := []struct { config string expectedErr string }{ { config: `source: wineventlog foobar: 42`, expectedErr: "field foobar not found in type wineventlogacquisition.WinEventLogConfiguration", }, { config: `source: wineventlog`, expectedErr: "event_channel or xpath_query must be set", }, { config: `source: wineventlog event_channel: Security event_level: blabla`, expectedErr: "buildXpathQuery failed: invalid log level", }, { config: `source: wineventlog event_channel: Security event_level: blabla`, expectedErr: "buildXpathQuery failed: invalid log level", }, { config: `source: wineventlog event_channel: foo xpath_query: test`, expectedErr: "event_channel and xpath_query are mutually exclusive", }, } subLogger := log.WithFields(log.Fields{ "type": "windowseventlog", }) for _, test := range tests { f := WinEventLogSource{} err := f.Configure([]byte(test.config), subLogger) assert.Contains(t, err.Error(), test.expectedErr) } } func TestQueryBuilder(t *testing.T) { if runtime.GOOS != "windows" { t.Skip("Skipping test on non-windows OS") } tests := []struct { config string expectedQuery string expectedErr string }{ { config: `source: wineventlog event_channel: Security event_level: Information`, expectedQuery: "", expectedErr: "", }, { config: `source: wineventlog event_channel: Security event_level: Error event_ids: - 42`, expectedQuery: "", expectedErr: "", }, { config: `source: wineventlog event_channel: Security event_level: Error event_ids: - 42 - 43`, expectedQuery: "", expectedErr: "", }, { config: `source: wineventlog event_channel: Security`, expectedQuery: "", expectedErr: "", }, { config: `source: wineventlog event_channel: Security event_level: bla`, expectedQuery: "", expectedErr: "invalid log level", }, } subLogger := log.WithFields(log.Fields{ "type": "windowseventlog", }) for _, test := range tests { f := WinEventLogSource{} f.Configure([]byte(test.config), subLogger) q, err := f.buildXpathQuery() if test.expectedErr != "" { if err == nil { t.Fatalf("expected error '%s' but got none", test.expectedErr) } assert.Contains(t, err.Error(), test.expectedErr) } else { require.NoError(t, err) assert.Equal(t, test.expectedQuery, q) } } } func TestLiveAcquisition(t *testing.T) { if runtime.GOOS != "windows" { t.Skip("Skipping test on non-windows OS") } tests := []struct { config string expectedLines []string }{ { config: `source: wineventlog xpath_query: | `, expectedLines: []string{ "blabla", "test", "aaaa", "bbbbb", }, }, { config: `source: wineventlog xpath_query: | asdfsdf`, expectedLines: nil, }, { config: `source: wineventlog event_channel: Application event_level: Information event_ids: - 42`, expectedLines: []string{ "testmessage", }, }, { config: `source: wineventlog event_channel: Application event_level: Information event_ids: - 43`, expectedLines: nil, }, } subLogger := log.WithFields(log.Fields{ "type": "windowseventlog", }) evthandler, err := eventlog.Open("Application") if err != nil { t.Fatalf("failed to open event log: %s", err) } for _, test := range tests { to := &tomb.Tomb{} c := make(chan types.Event) f := WinEventLogSource{} f.Configure([]byte(test.config), subLogger) f.StreamingAcquisition(c, to) time.Sleep(time.Second) lines := test.expectedLines go func() { for _, line := range lines { evthandler.Info(42, line) } }() ticker := time.NewTicker(time.Second * 5) linesRead := make([]string, 0) READLOOP: for { select { case <-ticker.C: if test.expectedLines == nil { break READLOOP } t.Fatalf("timeout") case e := <-c: line, _ := exprhelpers.XMLGetNodeValue(e.Line.Raw, "/Event/EventData[1]/Data") linesRead = append(linesRead, line.(string)) if len(linesRead) == len(lines) { break READLOOP } } } if test.expectedLines == nil { assert.Empty(t, linesRead) } else { assert.Equal(t, test.expectedLines, linesRead) } to.Kill(nil) to.Wait() } }