渠道竞争条件

时间:2018-04-06 20:01:47

标签: unit-testing go channel

我试图为一个简单的程序编写测试,该程序从inotify总线读取事件,过滤它们,然后将它们放在一个通道上。我在实际运行代码时没有看到任何问题,但是在下面的测试的最后一行中,从该通道读取时偶尔会死锁(大约30%的时间),尽管我可以说,事件是始终被放置在频道上。

这是功能:

func eventFilter(watcher *rfsnotify.RWatcher, excludes []string, out chan<- fsnotify.Event) {
    for {
        select {
        case event := <-watcher.Events:
            log.Debug(fmt.Sprintf("Got event %v", event))
            if isExcluded(event.Name, excludes) {
                log.Info("Ignoring excluded file: %v", event)
            } else if isRelevantOp(event) {
                log.Info(fmt.Sprintf("Handling event %v", event))
                out <- event
            } else {
                log.Info(fmt.Sprintf("Ignoring event %v", event))
            }
        case err := <-watcher.Errors:
            log.Error(fmt.Sprintf("Error: %v", err))
        }
    }
}

以下是测试代码:

var hook *logrusTest.Hook
var testDir string
var rWatcher *rfsnotify.RWatcher


func TestMain(m *testing.M) {
    // initialize bad globals, amongst other things
    log.SetLevel(log.DebugLevel)
    hook = logrusTest.NewGlobal()

    // Create directory to watch
    testDir = tempMkdir()
    defer os.RemoveAll(testDir)

    rWatcher, _ = rfsnotify.NewWatcher()
    defer rWatcher.Close()

    err := rWatcher.AddRecursive(testDir)
    if err != nil {
        log.Fatal("Failed to add watcher: ", err)
    }

    os.Exit(m.Run())
}

func TestEventFilterMove(t *testing.T) {

    ch := make(chan fsnotify.Event, 10)
    go eventFilter(rWatcher, []string{"test"}, ch)
    testFileSrc := filepath.Join(testDir, "TestFsnotifyEvents.testfileSrc")
    testFileDest := filepath.Join(testDir, "TestFsnotifyEvents.testfileDest")

    f, err := os.OpenFile(testFileSrc, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        t.Fatalf("creating test file failed: %s", err)
    }

    f.WriteString("data")
    f.Sync()
    hook.Reset()

    err = os.Rename(testFileSrc, testFileDest)
    if err != nil {
        t.Fatalf("renaming test file failed: %s", err)
    }

    time.Sleep(100 * time.Millisecond)

    expectedLogs := []string{
        fmt.Sprintf("Got event \"%v\": CREATE|UPDATE", testFileDest),
        fmt.Sprintf("Handling event \"%v\": CREATE|UPDATE", testFileDest),
        fmt.Sprintf("Got event \"%v\": RENAME", testFileSrc),
        fmt.Sprintf("Ignoring event \"%v\": RENAME", testFileSrc),
    }
    var actualLogs []string
    for _, logEntry := range hook.AllEntries() {
        actualLogs = append(actualLogs, logEntry.Message)
    }
    assert.ElementsMatch(t, actualLogs, expectedLogs)
    hook.Reset()
    _ = <-ch
    assert.Equal(t, 0, len(ch))

}

0 个答案:

没有答案