Fix flaky file discovery tests (#3438)

* flaky test caused by invalid fsnotify updates before the test files are written to disk causing the fd service to send empty `group[]` struct

* `close(filesReady)` needs to be before the file closing so that fsnotify triggers a new loop of the discovery service.

* nits

* use filepath.Join for the path url to be cross platform

* stupid mistake revert
This commit is contained in:
Krasi Georgiev 2017-11-11 16:20:39 +00:00 committed by Tobias Schmidt
parent 83bb1becab
commit c8a735ceb6

View file

@ -15,7 +15,6 @@ package file
import ( import (
"context" "context"
"fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
@ -27,11 +26,13 @@ import (
"github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/config"
) )
const testDir = "fixtures"
func TestFileSD(t *testing.T) { func TestFileSD(t *testing.T) {
defer os.Remove("fixtures/_test_valid.yml") defer os.Remove(filepath.Join(testDir, "_test_valid.yml"))
defer os.Remove("fixtures/_test_valid.json") defer os.Remove(filepath.Join(testDir, "_test_valid.json"))
defer os.Remove("fixtures/_test_invalid_nil.json") defer os.Remove(filepath.Join(testDir, "_test_invalid_nil.json"))
defer os.Remove("fixtures/_test_invalid_nil.yml") defer os.Remove(filepath.Join(testDir, "_test_invalid_nil.yml"))
testFileSD(t, "valid", ".yml", true) testFileSD(t, "valid", ".yml", true)
testFileSD(t, "valid", ".json", true) testFileSD(t, "valid", ".json", true)
testFileSD(t, "invalid_nil", ".json", false) testFileSD(t, "invalid_nil", ".json", false)
@ -42,7 +43,7 @@ func testFileSD(t *testing.T, prefix, ext string, expect bool) {
// As interval refreshing is more of a fallback, we only want to test // As interval refreshing is more of a fallback, we only want to test
// whether file watches work as expected. // whether file watches work as expected.
var conf config.FileSDConfig var conf config.FileSDConfig
conf.Files = []string{"fixtures/_*" + ext} conf.Files = []string{filepath.Join(testDir, "_*"+ext)}
conf.RefreshInterval = model.Duration(1 * time.Hour) conf.RefreshInterval = model.Duration(1 * time.Hour)
var ( var (
@ -59,22 +60,38 @@ func testFileSD(t *testing.T, prefix, ext string, expect bool) {
t.Fatalf("Unexpected target groups in file discovery: %s", tgs) t.Fatalf("Unexpected target groups in file discovery: %s", tgs)
} }
newf, err := os.Create("fixtures/_test_" + prefix + ext) // To avoid empty group struct sent from the discovery caused by invalid fsnotify updates,
// drain the channel until we are ready with the test files.
filesReady := make(chan struct{})
go func() {
for {
select {
case <-ch:
case <-filesReady:
return
}
}
}()
newf, err := os.Create(filepath.Join(testDir, "_test_"+prefix+ext))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer newf.Close() defer newf.Close()
f, err := os.Open("fixtures/" + prefix + ext) f, err := os.Open(filepath.Join(testDir, prefix+ext))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer f.Close() defer f.Close()
_, err = io.Copy(newf, f) _, err = io.Copy(newf, f)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
// File is written with the config so stop draining the discovery channel.
// It needs to be before the file closing so that fsnotify triggers a new loop of the discovery service.
close(filesReady)
newf.Close() newf.Close()
timeout := time.After(15 * time.Second) timeout := time.After(15 * time.Second)
@ -102,12 +119,12 @@ retry:
if _, ok := tg.Labels["foo"]; !ok { if _, ok := tg.Labels["foo"]; !ok {
t.Fatalf("Label not parsed") t.Fatalf("Label not parsed")
} }
if tg.String() != filepath.FromSlash(fmt.Sprintf("fixtures/_test_%s%s:0", prefix, ext)) { if tg.String() != filepath.Join(testDir, "_test_"+prefix+ext+":0") {
t.Fatalf("Unexpected target group %s", tg) t.Fatalf("Unexpected target group %s", tg)
} }
tg = tgs[1] tg = tgs[1]
if tg.String() != filepath.FromSlash(fmt.Sprintf("fixtures/_test_%s%s:1", prefix, ext)) { if tg.String() != filepath.Join(testDir, "_test_"+prefix+ext+":1") {
t.Fatalf("Unexpected target groups %s", tg) t.Fatalf("Unexpected target groups %s", tg)
} }
break retry break retry
@ -120,7 +137,6 @@ retry:
// not try to make sense of it all... // not try to make sense of it all...
drained := make(chan struct{}) drained := make(chan struct{})
go func() { go func() {
Loop:
for { for {
select { select {
case tgs := <-ch: case tgs := <-ch:
@ -130,13 +146,13 @@ retry:
t.Errorf("Unexpected empty target groups received: %s", tgs) t.Errorf("Unexpected empty target groups received: %s", tgs)
} }
case <-time.After(500 * time.Millisecond): case <-time.After(500 * time.Millisecond):
break Loop close(drained)
return
} }
} }
close(drained)
}() }()
newf, err = os.Create("fixtures/_test.new") newf, err = os.Create(filepath.Join(testDir, "_test.new"))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -147,7 +163,7 @@ retry:
} }
newf.Close() newf.Close()
os.Rename(newf.Name(), "fixtures/_test_"+prefix+ext) os.Rename(newf.Name(), filepath.Join(testDir, "_test_"+prefix+ext))
cancel() cancel()
<-drained <-drained