@@ -12,6 +12,11 @@ import (
1212 "golang.org/x/sys/unix"
1313)
1414
15+ //
16+ // TestWithCapSysAdm* tests require CAP_SYS_ADM privilege.
17+ // Run tests with sudo or as root -
18+ // sudo go test -v
19+
1520func TestNewListenerInvalidFlagClassContent (t * testing.T ) {
1621 var invalidFlag uint
1722 var eventFlags uint
@@ -42,33 +47,25 @@ func TestNewListenerValidFlags(t *testing.T) {
4247 assert .NotNil (t , l )
4348}
4449
45- // func testKernelVersion(t *testing.T) {
46- // maj, min, patch, err := kernelVersion()
47- // assert.Equal(t, maj, 5)
48- // assert.Equal(t, min, 15)
49- // assert.Equal(t, patch, 0)
50- // assert.Nil(t, err)
51- // }
52-
53- func catFile (filename string ) (int , error ) {
54- cmd := exec .Command ("cat" , filename )
55- err := cmd .Run ()
56- if err != nil {
57- return 0 , err
50+ func runAsCmd (args ... string ) (int , error ) {
51+ var cmd * exec.Cmd
52+ if len (args ) == 0 {
53+ return 0 , errors .New ("missing command name" )
54+ }
55+ cmdName := args [0 ]
56+ cmdArgs := args [1 :]
57+ if len (args ) == 1 {
58+ cmd = exec .Command (cmdName )
59+ } else {
60+ cmd = exec .Command (cmdName , cmdArgs ... )
5861 }
59- return cmd .Process .Pid , nil
60- }
61-
62- func modifyFile (filename string ) (int , error ) {
63- cmd := exec .Command ("touch" , "-m" , filename )
6462 err := cmd .Run ()
6563 if err != nil {
6664 return 0 , err
6765 }
6866 return cmd .Process .Pid , nil
6967}
7068
71- // TestWithCapSysAdmFanotifyFileAccessed requires CAP_SYS_ADM privilege.
7269func TestWithCapSysAdmFanotifyFileAccessed (t * testing.T ) {
7370 l , err := NewListener ("/" , 4096 , true )
7471 assert .Nil (t , err )
@@ -85,7 +82,7 @@ func TestWithCapSysAdmFanotifyFileAccessed(t *testing.T) {
8582 err = os .WriteFile (testFile , data , 0666 )
8683 assert .Nil (t , err )
8784 t .Logf ("Test file created %s" , testFile )
88- pid , err := catFile ( testFile )
85+ pid , err := runAsCmd ( "cat" , testFile )
8986 assert .Nil (t , err )
9087 select {
9188 case <- time .After (100 * time .Millisecond ):
@@ -98,7 +95,6 @@ func TestWithCapSysAdmFanotifyFileAccessed(t *testing.T) {
9895 }
9996}
10097
101- // TestWithCapSysAdmFanotifyFileModified requires CAP_SYS_ADM privilege.
10298func TestWithCapSysAdmFanotifyFileModified (t * testing.T ) {
10399 l , err := NewListener ("/" , 4096 , true )
104100 assert .Nil (t , err )
@@ -115,7 +111,7 @@ func TestWithCapSysAdmFanotifyFileModified(t *testing.T) {
115111 l .AddWatch (watchDir , action )
116112 go l .Start ()
117113 defer l .Stop ()
118- pid , err := modifyFile ( testFile )
114+ pid , err := runAsCmd ( "touch" , "-m" , testFile )
119115 assert .Nil (t , err )
120116 select {
121117 case <- time .After (100 * time .Millisecond ):
@@ -127,3 +123,264 @@ func TestWithCapSysAdmFanotifyFileModified(t *testing.T) {
127123 assert .True (t , isModifed )
128124 }
129125}
126+
127+ func TestWithCapSysAdmFanotifyFileClosed (t * testing.T ) {
128+ l , err := NewListener ("/" , 4096 , true )
129+ assert .Nil (t , err )
130+ assert .NotNil (t , l )
131+ watchDir := t .TempDir ()
132+
133+ t .Logf ("Watch Directory: %s" , watchDir )
134+ data := []byte ("test data..." )
135+ testFile := fmt .Sprintf ("%s/test.dat" , watchDir )
136+ err = os .WriteFile (testFile , data , 0666 )
137+ assert .Nil (t , err )
138+ t .Logf ("Test file created %s" , testFile )
139+ action := FileClosed
140+ l .AddWatch (watchDir , action )
141+ go l .Start ()
142+ defer l .Stop ()
143+ pid , err := runAsCmd ("cat" , testFile )
144+ assert .Nil (t , err )
145+ select {
146+ case <- time .After (100 * time .Millisecond ):
147+ t .Error ("Timeout Error: FileClosed event not received" )
148+ case event := <- l .Events :
149+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testFile )
150+ assert .Equal (t , event .Pid , pid )
151+ closeNoWrite := (event .Mask & FileClosedWithNoWrite ) == FileClosedWithNoWrite
152+ assert .True (t , closeNoWrite )
153+ }
154+ }
155+
156+ func TestWithCapSysAdmFanotifyFileOpen (t * testing.T ) {
157+ l , err := NewListener ("/" , 4096 , true )
158+ assert .Nil (t , err )
159+ assert .NotNil (t , l )
160+ watchDir := t .TempDir ()
161+
162+ t .Logf ("Watch Directory: %s" , watchDir )
163+ data := []byte ("test data..." )
164+ testFile := fmt .Sprintf ("%s/test.dat" , watchDir )
165+ err = os .WriteFile (testFile , data , 0666 )
166+ assert .Nil (t , err )
167+ t .Logf ("Test file created %s" , testFile )
168+ action := FileOpened
169+ l .AddWatch (watchDir , action )
170+ go l .Start ()
171+ defer l .Stop ()
172+ pid , err := runAsCmd ("cat" , testFile )
173+ assert .Nil (t , err )
174+ select {
175+ case <- time .After (100 * time .Millisecond ):
176+ t .Error ("Timeout Error: FileOpened event not received" )
177+ case event := <- l .Events :
178+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testFile )
179+ assert .Equal (t , event .Pid , pid )
180+ opened := (event .Mask & FileOpened ) == FileOpened
181+ assert .True (t , opened )
182+ }
183+ }
184+
185+ func TestWithCapSysAdmFanotifyFileOrDirectoryOpen (t * testing.T ) {
186+ l , err := NewListener ("/" , 4096 , true )
187+ assert .Nil (t , err )
188+ assert .NotNil (t , l )
189+ watchDir := t .TempDir ()
190+
191+ t .Logf ("Watch Directory: %s" , watchDir )
192+ action := FileOrDirectoryOpened
193+ l .AddWatch (watchDir , action )
194+ go l .Start ()
195+ defer l .Stop ()
196+ pid , err := runAsCmd ("ls" , watchDir )
197+ assert .Nil (t , err )
198+ assert .NotEqual (t , pid , 0 )
199+ select {
200+ case <- time .After (100 * time .Millisecond ):
201+ t .Error ("Timeout Error: FileOrDirectoryOpened event not received" )
202+ case event := <- l .Events :
203+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), fmt .Sprintf ("%s/%s" , watchDir , "." ))
204+ assert .Equal (t , event .Pid , pid )
205+ opened := (event .Mask & FileOpened ) == FileOpened
206+ assert .True (t , opened )
207+ }
208+ }
209+
210+ func TestWithCapSysAdmFanotifyFileOpenForExec (t * testing.T ) {
211+ l , err := NewListener ("/" , 4096 , true )
212+ assert .Nil (t , err )
213+ assert .NotNil (t , l )
214+ watchDir := t .TempDir ()
215+
216+ t .Logf ("Watch Directory: %s" , watchDir )
217+ data := []byte (`
218+ #!/bin/bash
219+
220+ echo "test shell script"
221+ exit 0
222+ ` )
223+ testFile := fmt .Sprintf ("%s/test.sh" , watchDir )
224+ err = os .WriteFile (testFile , data , 0755 )
225+ assert .Nil (t , err )
226+ t .Logf ("Test shell script created %s" , testFile )
227+ action := FileOpenedForExec
228+ l .AddWatch (watchDir , action )
229+ go l .Start ()
230+ defer l .Stop ()
231+ pid , err := runAsCmd ("bash" , "-c" , testFile )
232+ assert .Nil (t , err )
233+ select {
234+ case <- time .After (100 * time .Millisecond ):
235+ t .Error ("Timeout Error: FileOpenedForExec event not received" )
236+ case event := <- l .Events :
237+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testFile )
238+ assert .Equal (t , event .Pid , pid )
239+ openedForExec := (event .Mask & FileOpenedForExec ) == FileOpenedForExec
240+ assert .True (t , openedForExec )
241+ }
242+ }
243+
244+ func TestWithCapSysAdmFanotifyFileAttribChanged (t * testing.T ) {
245+ l , err := NewListener ("/" , 4096 , true )
246+ assert .Nil (t , err )
247+ assert .NotNil (t , l )
248+ watchDir := t .TempDir ()
249+
250+ t .Logf ("Watch Directory: %s" , watchDir )
251+ data := []byte (`
252+ #!/bin/bash
253+
254+ echo "test shell script"
255+ exit 0
256+ ` )
257+ testFile := fmt .Sprintf ("%s/test.sh" , watchDir )
258+ err = os .WriteFile (testFile , data , 0666 )
259+ assert .Nil (t , err )
260+ t .Logf ("Test shell script created %s" , testFile )
261+ action := FileAttribChanged
262+ l .AddWatch (watchDir , action )
263+ go l .Start ()
264+ defer l .Stop ()
265+ pid , err := runAsCmd ("chmod" , "+x" , testFile )
266+ assert .Nil (t , err )
267+ select {
268+ case <- time .After (100 * time .Millisecond ):
269+ t .Error ("Timeout Error: FileOpenedForExec event not received" )
270+ case event := <- l .Events :
271+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testFile )
272+ assert .Equal (t , event .Pid , pid )
273+ openedForExec := (event .Mask & FileAttribChanged ) == FileAttribChanged
274+ assert .True (t , openedForExec )
275+ }
276+ }
277+
278+ func TestWithCapSysAdmFanotifyFileCreated (t * testing.T ) {
279+ l , err := NewListener ("/" , 4096 , true )
280+ assert .Nil (t , err )
281+ assert .NotNil (t , l )
282+ watchDir := t .TempDir ()
283+
284+ t .Logf ("Watch Directory: %s" , watchDir )
285+ action := FileCreated
286+ l .AddWatch (watchDir , action )
287+ go l .Start ()
288+ defer l .Stop ()
289+ testFile := fmt .Sprintf ("%s/test.txt" , watchDir )
290+ pid , err := runAsCmd ("touch" , testFile )
291+ assert .Nil (t , err )
292+ select {
293+ case <- time .After (100 * time .Millisecond ):
294+ t .Error ("Timeout Error: FileOpenedForExec event not received" )
295+ case event := <- l .Events :
296+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testFile )
297+ assert .Equal (t , event .Pid , pid )
298+ created := (event .Mask & FileCreated ) == FileCreated
299+ assert .True (t , created )
300+ }
301+ }
302+
303+ func TestWithCapSysAdmFanotifyFileOrDirectoryCreated (t * testing.T ) {
304+ l , err := NewListener ("/" , 4096 , true )
305+ assert .Nil (t , err )
306+ assert .NotNil (t , l )
307+ watchDir := t .TempDir ()
308+
309+ t .Logf ("Watch Directory: %s" , watchDir )
310+ action := FileOrDirCreated
311+ l .AddWatch (watchDir , action )
312+ go l .Start ()
313+ defer l .Stop ()
314+ testDir := fmt .Sprintf ("%s/testdir" , watchDir )
315+ pid , err := runAsCmd ("mkdir" , testDir )
316+ assert .Nil (t , err )
317+ select {
318+ case <- time .After (100 * time .Millisecond ):
319+ t .Error ("Timeout Error: FileOpenedForExec event not received" )
320+ case event := <- l .Events :
321+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testDir )
322+ assert .Equal (t , event .Pid , pid )
323+ created := (event .Mask & FileCreated ) == FileCreated
324+ assert .True (t , created )
325+ }
326+ }
327+
328+ func TestWithCapSysAdmFanotifyFileDeleted (t * testing.T ) {
329+
330+ l , err := NewListener ("/" , 4096 , true )
331+ assert .Nil (t , err )
332+ assert .NotNil (t , l )
333+
334+ watchDir := t .TempDir ()
335+ testFile := fmt .Sprintf ("%s/test.txt" , watchDir )
336+ pid , err := runAsCmd ("touch" , testFile )
337+ assert .Nil (t , err )
338+
339+ t .Logf ("Watch Directory: %s" , watchDir )
340+ action := FileDeleted
341+ l .AddWatch (watchDir , action )
342+ go l .Start ()
343+ defer l .Stop ()
344+
345+ pid , err = runAsCmd ("rm" , "-f" , testFile )
346+ assert .Nil (t , err )
347+ select {
348+ case <- time .After (100 * time .Millisecond ):
349+ t .Error ("Timeout Error: FileOpenedForExec event not received" )
350+ case event := <- l .Events :
351+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testFile )
352+ assert .Equal (t , event .Pid , pid )
353+ deleted := (event .Mask & FileDeleted ) == FileDeleted
354+ assert .True (t , deleted )
355+ }
356+ }
357+
358+ func TestWithCapSysAdmFanotifyFileOrDirDeleted (t * testing.T ) {
359+
360+ l , err := NewListener ("/" , 4096 , true )
361+ assert .Nil (t , err )
362+ assert .NotNil (t , l )
363+
364+ watchDir := t .TempDir ()
365+ testDir := fmt .Sprintf ("%s/testdir" , watchDir )
366+ pid , err := runAsCmd ("mkdir" , testDir )
367+ assert .Nil (t , err )
368+
369+ t .Logf ("Watch Directory: %s" , watchDir )
370+ action := FileOrDirDeleted
371+ l .AddWatch (watchDir , action )
372+ go l .Start ()
373+ defer l .Stop ()
374+
375+ pid , err = runAsCmd ("rm" , "-rf" , testDir )
376+ assert .Nil (t , err )
377+ select {
378+ case <- time .After (100 * time .Millisecond ):
379+ t .Error ("Timeout Error: FileOpenedForExec event not received" )
380+ case event := <- l .Events :
381+ assert .Equal (t , fmt .Sprintf ("%s/%s" , event .Path , event .FileName ), testDir )
382+ assert .Equal (t , event .Pid , pid )
383+ deleted := (event .Mask & FileDeleted ) == FileDeleted
384+ assert .True (t , deleted )
385+ }
386+ }
0 commit comments