github.com/crowdsecurity/crowdsec@v1.6.1/pkg/acquisition/modules/wineventlog/wineventlog_test.go (about) 1 //go:build windows 2 3 package wineventlogacquisition 4 5 import ( 6 "runtime" 7 "testing" 8 "time" 9 10 "github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration" 11 "github.com/crowdsecurity/crowdsec/pkg/exprhelpers" 12 "github.com/crowdsecurity/crowdsec/pkg/types" 13 log "github.com/sirupsen/logrus" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 "golang.org/x/sys/windows/svc/eventlog" 17 "gopkg.in/tomb.v2" 18 ) 19 20 func TestBadConfiguration(t *testing.T) { 21 if runtime.GOOS != "windows" { 22 t.Skip("Skipping test on non-windows OS") 23 } 24 tests := []struct { 25 config string 26 expectedErr string 27 }{ 28 { 29 config: `source: wineventlog 30 foobar: 42`, 31 expectedErr: "field foobar not found in type wineventlogacquisition.WinEventLogConfiguration", 32 }, 33 { 34 config: `source: wineventlog`, 35 expectedErr: "event_channel or xpath_query must be set", 36 }, 37 { 38 config: `source: wineventlog 39 event_channel: Security 40 event_level: blabla`, 41 expectedErr: "buildXpathQuery failed: invalid log level", 42 }, 43 { 44 config: `source: wineventlog 45 event_channel: Security 46 event_level: blabla`, 47 expectedErr: "buildXpathQuery failed: invalid log level", 48 }, 49 { 50 config: `source: wineventlog 51 event_channel: foo 52 xpath_query: test`, 53 expectedErr: "event_channel and xpath_query are mutually exclusive", 54 }, 55 } 56 57 subLogger := log.WithFields(log.Fields{ 58 "type": "windowseventlog", 59 }) 60 for _, test := range tests { 61 f := WinEventLogSource{} 62 err := f.Configure([]byte(test.config), subLogger, configuration.METRICS_NONE) 63 assert.Contains(t, err.Error(), test.expectedErr) 64 } 65 } 66 67 func TestQueryBuilder(t *testing.T) { 68 if runtime.GOOS != "windows" { 69 t.Skip("Skipping test on non-windows OS") 70 } 71 tests := []struct { 72 config string 73 expectedQuery string 74 expectedErr string 75 }{ 76 { 77 config: `source: wineventlog 78 event_channel: Security 79 event_level: Information`, 80 expectedQuery: "<QueryList><Query><Select Path=\"Security\">*[System[(Level=0 or Level=4)]]</Select></Query></QueryList>", 81 expectedErr: "", 82 }, 83 { 84 config: `source: wineventlog 85 event_channel: Security 86 event_level: Error 87 event_ids: 88 - 42`, 89 expectedQuery: "<QueryList><Query><Select Path=\"Security\">*[System[(EventID=42) and (Level=2)]]</Select></Query></QueryList>", 90 expectedErr: "", 91 }, 92 { 93 config: `source: wineventlog 94 event_channel: Security 95 event_level: Error 96 event_ids: 97 - 42 98 - 43`, 99 expectedQuery: "<QueryList><Query><Select Path=\"Security\">*[System[(EventID=42 or EventID=43) and (Level=2)]]</Select></Query></QueryList>", 100 expectedErr: "", 101 }, 102 { 103 config: `source: wineventlog 104 event_channel: Security`, 105 expectedQuery: "<QueryList><Query><Select Path=\"Security\">*</Select></Query></QueryList>", 106 expectedErr: "", 107 }, 108 { 109 config: `source: wineventlog 110 event_channel: Security 111 event_level: bla`, 112 expectedQuery: "", 113 expectedErr: "invalid log level", 114 }, 115 } 116 subLogger := log.WithFields(log.Fields{ 117 "type": "windowseventlog", 118 }) 119 for _, test := range tests { 120 f := WinEventLogSource{} 121 f.Configure([]byte(test.config), subLogger, configuration.METRICS_NONE) 122 q, err := f.buildXpathQuery() 123 if test.expectedErr != "" { 124 if err == nil { 125 t.Fatalf("expected error '%s' but got none", test.expectedErr) 126 } 127 assert.Contains(t, err.Error(), test.expectedErr) 128 } else { 129 require.NoError(t, err) 130 assert.Equal(t, test.expectedQuery, q) 131 } 132 } 133 } 134 135 func TestLiveAcquisition(t *testing.T) { 136 if runtime.GOOS != "windows" { 137 t.Skip("Skipping test on non-windows OS") 138 } 139 140 tests := []struct { 141 config string 142 expectedLines []string 143 }{ 144 { 145 config: `source: wineventlog 146 xpath_query: | 147 <QueryList> 148 <Query Id="0" Path="Application"> 149 <Select Path="Application">*[System[(Level=4 or Level=0) and (EventID=42)]]</Select> 150 </Query> 151 </QueryList>`, 152 expectedLines: []string{ 153 "blabla", 154 "test", 155 "aaaa", 156 "bbbbb", 157 }, 158 }, 159 { 160 config: `source: wineventlog 161 xpath_query: | 162 <sdf>asdfsdf`, 163 expectedLines: nil, 164 }, 165 { 166 config: `source: wineventlog 167 event_channel: Application 168 event_level: Information 169 event_ids: 170 - 42`, 171 expectedLines: []string{ 172 "testmessage", 173 }, 174 }, 175 { 176 config: `source: wineventlog 177 event_channel: Application 178 event_level: Information 179 event_ids: 180 - 43`, 181 expectedLines: nil, 182 }, 183 } 184 subLogger := log.WithFields(log.Fields{ 185 "type": "windowseventlog", 186 }) 187 188 evthandler, err := eventlog.Open("Application") 189 190 if err != nil { 191 t.Fatalf("failed to open event log: %s", err) 192 } 193 194 for _, test := range tests { 195 to := &tomb.Tomb{} 196 c := make(chan types.Event) 197 f := WinEventLogSource{} 198 f.Configure([]byte(test.config), subLogger, configuration.METRICS_NONE) 199 f.StreamingAcquisition(c, to) 200 time.Sleep(time.Second) 201 lines := test.expectedLines 202 go func() { 203 for _, line := range lines { 204 evthandler.Info(42, line) 205 } 206 }() 207 ticker := time.NewTicker(time.Second * 5) 208 linesRead := make([]string, 0) 209 READLOOP: 210 for { 211 select { 212 case <-ticker.C: 213 if test.expectedLines == nil { 214 break READLOOP 215 } 216 t.Fatalf("timeout") 217 case e := <-c: 218 line, _ := exprhelpers.XMLGetNodeValue(e.Line.Raw, "/Event/EventData[1]/Data") 219 linesRead = append(linesRead, line.(string)) 220 if len(linesRead) == len(lines) { 221 break READLOOP 222 } 223 } 224 } 225 if test.expectedLines == nil { 226 assert.Empty(t, linesRead) 227 } else { 228 assert.Equal(t, test.expectedLines, linesRead) 229 } 230 to.Kill(nil) 231 to.Wait() 232 } 233 }