如何测试在goroutine中监视文件的函数

huangapple go评论70阅读模式
英文:

How to test a function that watches a file in a goroutine

问题

我有一个函数,通过fsnotify监视特定的文件,并在文件更改时调用回调函数。如果回调函数返回false,则停止监视:

import (
	"github.com/golang/glog"
	"github.com/fsnotify/fsnotify"
)

type WatcherFunc func(err error) bool

func WatchFileChanges(filename string, watcherFunc WatcherFunc) {
	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		glog.Errorf("Got error creating watcher %s", err)
	}

	defer watcher.Close()

	done := make(chan bool)

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				glog.Infof("inotify event %s", event)

				if event.Op&fsnotify.Write == fsnotify.Write {
					glog.Infof("modified file %s, calling watcher func", event.Name)

					if !watcherFunc(nil) {
						close(done)
					}
				}

			case err := <-watcher.Errors:
				glog.Errorf("Got error watching %s, calling watcher func", err)

				if !watcherFunc(err) {
					close(done)
				}
			}
		}
	}()

	glog.Infof("Start watching file %s", filename)

	err = watcher.Add(filename)

	if err != nil {
		glog.Errorf("Got error adding watcher %s", err)
	}
	<-done
}

然后我想为它编写一个测试,所以我从一个简单的测试用例开始:

import (
	"io/ioutil"
	"os"
	"testing"
)

func TestStuff(t *testing.T) {
	tmpfile, err := ioutil.TempFile("", "test")

	if err != nil {
		t.Fatal("Failed to create tmp file")
	}

	defer os.Remove(tmpfile.Name())

	watcherFunc := func(err error) bool {
		return false
	}

	WatchFileChanges(tmpfile.Name(), watcherFunc)
}

我想在这里对文件进行一些修改,将事件收集到一个数组中,然后从watcherFunc返回false,最后对数组进行断言。问题是,当启动了goroutine时,测试会一直挂起等待事件。

有没有办法测试这样的函数,比如...启动一个不同的线程(?)来更新/修改文件?

英文:

I have a function that watches certian file via fsnotify and calls a callback when the file changes. If the callback returns false, the watching is ended:

import (
	&quot;github.com/golang/glog&quot;
	&quot;github.com/fsnotify/fsnotify&quot;
)

type WatcherFunc func(err error) bool

func WatchFileChanges(filename string, watcherFunc WatcherFunc) {
	watcher, err := fsnotify.NewWatcher()

	if err != nil {
		glog.Errorf(&quot;Got error creating watcher %s&quot;, err)
	}

	defer watcher.Close()

	done := make(chan bool)

	go func() {
		for {
			select {
			case event := &lt;-watcher.Events:
				glog.Infof(&quot;inotify event %s&quot;, event)

				if event.Op&amp;fsnotify.Write == fsnotify.Write {
					glog.Infof(&quot;modified file %s, calling watcher func&quot;, event.Name)

					if !watcherFunc(nil) {
						close(done)
					}
				}

			case err := &lt;-watcher.Errors:
				glog.Errorf(&quot;Got error watching %s, calling watcher func&quot;, err)

				if !watcherFunc(err) {
					close(done)
				}
			}
		}
	}()

	glog.Infof(&quot;Start watching file %s&quot;, filename)

	err = watcher.Add(filename)

	if err != nil {
		glog.Errorf(&quot;Got error adding watcher %s&quot;, err)
	}
	&lt;-done
}

Then I thought it would be nice to have a test for that, so I started out with a simple test case:

import (
	&quot;io/ioutil&quot;
	&quot;os&quot;
	&quot;testing&quot;
)

func TestStuff(t *testing.T) {
	tmpfile, err := ioutil.TempFile(&quot;&quot;, &quot;test&quot;)

	if err != nil {
		t.Fatal(&quot;Failed to create tmp file&quot;)
	}

	defer os.Remove(tmpfile.Name())

	watcherFunc := func (err error) bool {
		return false
	}

	WatchFileChanges(tmpfile.Name(), watcherFunc)
}

What I wanted do to here is to do a few modifications to the file, collect the events in an array, return then false from the watcherFunc and then assert on the array. The thing is, of course the test just hangs and waits for events, as the goroutine was started.

Is there any way how I can test a function like this, like … starting a different thread (?) that updates/modifies the file?

答案1

得分: 0

当然可以。你可以启动一个 goroutine 来执行你想要的更新操作。

func TestStuff(t *testing.T) {
    tmpfile, err := ioutil.TempFile("", "test")

    if err != nil {
        t.Fatal("Failed to create tmp file")
    }

    defer os.Remove(tmpfile.Name())

    watcherFunc := func (err error) bool {
        return false
    }
    go func() {
        // 在这里进行更新操作
    }()

    WatchFileChanges(tmpfile.Name(), watcherFunc)
}

在这个示例中,你可以在 go func() 中执行你想要的更新操作。

英文:

> Is there any way how I can test a function like this, like … starting a different thread (?) that updates/modifies the file?

Of course... start a goroutine that does the updates you want.

func TestStuff(t *testing.T) {
    tmpfile, err := ioutil.TempFile(&quot;&quot;, &quot;test&quot;)

    if err != nil {
        t.Fatal(&quot;Failed to create tmp file&quot;)
    }

    defer os.Remove(tmpfile.Name())

    watcherFunc := func (err error) bool {
        return false
    }
    go func() {
        // Do updates here
    }()

    WatchFileChanges(tmpfile.Name(), watcherFunc)
}

huangapple
  • 本文由 发表于 2017年4月18日 17:31:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/43468476.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定