@@ -95,26 +95,30 @@ func TestAll(t *testing.T) {
9595// * directories with the xattr com.apple.FinderInfo (like everything in /tmp) are hidden
9696// In order to test this, we must create a log file somewhere outside of /tmp, so we use $HOME.
9797func TestVisibleInOSXFinder (t * testing.T ) {
98+ ctx := setUp (t , "visible in macOS finder" , closeFileAfterEachLine , fseventTailer , _nocreate , mv )
99+
100+ // replace ctx.basedir with a directory in $HOME
98101 currentUser , err := user .Current ()
99102 if err != nil {
100- t . Fatalf ( "failed to get current user: %v" , err )
103+ fatalf ( t , ctx , "failed to get current user: %v" , err )
101104 }
102105 testDir , err := ioutil .TempDir (currentUser .HomeDir , "grok_exporter_test_dir_" )
103106 if err != nil {
104- t . Fatalf ( "failed to create test directory: %v" , err .Error ())
107+ fatalf ( t , ctx , "failed to create test directory: %v" , err .Error ())
105108 }
106109 defer func () {
107110 err := os .RemoveAll (testDir )
108111 if err != nil {
109- t . Fatalf ( "%v: Failed to remove test directory after running the tests: %v" , testDir , err .Error ())
112+ fatalf ( t , ctx , "%v: Failed to remove test directory after running the tests: %v" , testDir , err .Error ())
110113 }
111114 }()
112- ctx := setUp (t , "visible in macOS finder" , closeFileAfterEachLine , fseventTailer , _nocreate , mv )
113115 err = os .RemoveAll (ctx .basedir )
114116 if err != nil {
115- t . Fatalf ( "%v: failed to remove temp dir: %v" , ctx .basedir , err )
117+ fatalf ( t , ctx , "%v: failed to remove temp dir: %v" , ctx .basedir , err )
116118 }
117119 ctx .basedir = testDir
120+
121+ // run simple test in the new directory
118122 test := [][]string {
119123 {"log" , "line 1" , "test.log" },
120124 {"start file tailer" , "test.log" },
@@ -156,21 +160,24 @@ func runTest(t *testing.T, ctx *context, cmds [][]string) {
156160}
157161
158162func closeTailer (t * testing.T , ctx * context ) {
163+ // Note: This function checks if the Lines() channel gets closed.
164+ // While it's good to check this, it doesn't guarantee that the tailer is
165+ // fully shut down. There might be an fseventProducerLoop running in the
166+ // background, or a hanging system call keeping the log directory open.
167+ // There are tests for that like counting the number of goroutines
168+ // in assertGoroutinesTerminated() or making sure the log directory
169+ // can be removed in tearDown().
159170 timeout := 5 * time .Second
160171 if ctx .tailer != nil {
161172 ctx .tailer .Close ()
162- // wait until closed
173+ // check if the lines channel gets closed
163174 select {
164175 case line , open := <- ctx .tailer .Lines ():
165176 if open {
166- msg := fmt .Sprintf ("read unexpected line line from file %q: %q" , line .File , line .Line )
167- ctx .log .Error (msg )
168- t .Fatal (msg )
177+ fatalf (t , ctx , "read unexpected line line from file %q: %q" , line .File , line .Line )
169178 }
170179 case <- time .After (timeout ):
171- msg := fmt .Sprintf ("failed to shut down the tailer. timeout after %v seconds" , timeout )
172- ctx .log .Error (msg )
173- fatalf (t , ctx , msg )
180+ fatalf (t , ctx , "failed to shut down the tailer. timeout after %v seconds" , timeout )
174181 }
175182 }
176183}
@@ -468,7 +475,7 @@ func startFileTailer(t *testing.T, ctx *context, params []string) {
468475 for _ , g := range globs {
469476 parsedGlob , err := glob .Parse (filepath .Join (ctx .basedir , g ))
470477 if err != nil {
471- t . Fatal ( err )
478+ fatalf ( t , ctx , "%v" , err )
472479 }
473480 parsedGlobs = append (parsedGlobs , parsedGlob )
474481 }
@@ -723,9 +730,64 @@ func (l *keepOpenLogFileWriter) close(t *testing.T, ctx *context) {
723730}
724731
725732func tearDown (t * testing.T , ctx * context ) {
726- err := os .RemoveAll (ctx .basedir )
733+ deleteRecursively (t , ctx , ctx .basedir )
734+ }
735+
736+ func deleteRecursively (t * testing.T , ctx * context , file string ) {
737+ // os.RemoveAll() fails on Windows with "Access is denied".
738+ // Remove each file individually to learn which file cannot be removed.
739+ fileInfo , err := os .Stat (file )
740+ if err != nil {
741+ fatalf (t , ctx , "tearDown: stat(%q) failed: %v" , file , err )
742+ }
743+ if fileInfo .IsDir () {
744+ for _ , childInfo := range ls (t , ctx , file ) {
745+ deleteRecursively (t , ctx , path .Join (file , childInfo .Name ()))
746+ }
747+ }
748+ ctx .log .Debugf ("tearDown: removing %q" , file )
749+ delete (t , ctx , file )
750+ //if err != nil {
751+ // // We get "The directory is not empty" here on Windows.
752+ // // Let's print what files are in here.
753+ // var filesInDir []string
754+ // for _, fileInDir := range ls(t, ctx, file) {
755+ // filesInDir = append(filesInDir, fileInDir.Name())
756+ // }
757+ // fatalf(t, ctx, "tearDown: %q: remove failed: %v. number of files in dir: %v, list of file in dir: %#v", file, err, len(filesInDir), filesInDir)
758+ //}
759+ }
760+
761+ func delete (t * testing.T , ctx * context , file string ) {
762+ // repeat a few times in case the file or directory is still used by the file system watcher.
763+ var (
764+ err error
765+ timeout = 5 * time .Second
766+ timePassed = 0 * time .Second
767+ )
768+ for timePassed < timeout {
769+ err = os .Remove (file )
770+ if err == nil {
771+ // Check if the file or directory is really removed. On Windows, os.Remove() sometimes
772+ // returns no error when removing the log directory, but the directory is still there.
773+ _ , err = os .Stat (file )
774+ if err != nil {
775+ if os .IsNotExist (err ) {
776+ // os.Remove(file) was successful, the file or directory is gone.
777+ return
778+ } else {
779+ fatalf (t , ctx , "tearDown: %q: stat failed: %v" , file , err )
780+ }
781+ }
782+ }
783+ // os.Stat() successful. The file or directory is still there. Try again.
784+ time .Sleep (200 * time .Millisecond )
785+ timePassed += 200 * time .Millisecond
786+ }
727787 if err != nil {
728- fatalf (t , ctx , "%v: failed to remove the test directory after running the tests: %v" , ctx .basedir , err )
788+ fatalf (t , ctx , "tearDown: %q: failed to remove file or directory: %v" , file , err )
789+ } else {
790+ fatalf (t , ctx , "tearDown: %q: failed to remove file or directory" , file )
729791 }
730792}
731793
@@ -803,18 +865,18 @@ func runTestShutdown(t *testing.T, mode string) {
803865 select {
804866 case _ , open := <- tailer .Errors ():
805867 if open {
806- t . Fatalf ( "error channel not closed" )
868+ fatalf ( t , ctx , "error channel not closed" )
807869 }
808870 case <- time .After (5 * time .Second ):
809- t . Fatalf ( "timeout while waiting for errors channel to be closed." )
871+ fatalf ( t , ctx , "timeout while waiting for errors channel to be closed." )
810872 }
811873 select {
812874 case _ , open := <- tailer .Lines ():
813875 if open {
814- t . Fatalf ( "lines channel not closed" )
876+ fatalf ( t , ctx , "lines channel not closed" )
815877 }
816878 case <- time .After (5 * time .Second ):
817- t . Fatalf ( "timeout while waiting for errors channel to be closed." )
879+ fatalf ( t , ctx , "timeout while waiting for errors channel to be closed." )
818880 }
819881 assertGoroutinesTerminated (t , ctx , nGoroutinesBefore )
820882}
0 commit comments