aboutsummaryrefslogtreecommitdiff
path: root/node_exporter_test.go
diff options
context:
space:
mode:
authorTobias Schmidt <tobidt@gmail.com>2017-03-13 23:55:19 -0300
committerTobias Schmidt <tobidt@gmail.com>2017-03-14 00:38:02 -0300
commitdace41e3d4c3dfc3a52fa73fcba322082dcce22a (patch)
tree8ed0e1883e34a17f72df94e2e8cd05581cf009aa /node_exporter_test.go
parenta0a0dbaad0a53ce6d98eeb34cc8519299aba5155 (diff)
downloadprometheus_node_collector-dace41e3d4c3dfc3a52fa73fcba322082dcce22a.tar.bz2
prometheus_node_collector-dace41e3d4c3dfc3a52fa73fcba322082dcce22a.tar.xz
prometheus_node_collector-dace41e3d4c3dfc3a52fa73fcba322082dcce22a.zip
Continue scrape with duplicated metrics
Problems of a single collector, like duplicated metrics read via the textfile collector, should not fail the collection and export of other metrics.
Diffstat (limited to 'node_exporter_test.go')
-rw-r--r--node_exporter_test.go132
1 files changed, 85 insertions, 47 deletions
diff --git a/node_exporter_test.go b/node_exporter_test.go
index 4ff0caa..d1830ec 100644
--- a/node_exporter_test.go
+++ b/node_exporter_test.go
@@ -2,21 +2,23 @@ package main
2 2
3import ( 3import (
4 "fmt" 4 "fmt"
5 "io/ioutil"
5 "net/http" 6 "net/http"
6 "os" 7 "os"
7 "os/exec" 8 "os/exec"
9 "path/filepath"
8 "testing" 10 "testing"
9 "time" 11 "time"
10 12
11 "github.com/prometheus/procfs" 13 "github.com/prometheus/procfs"
12) 14)
13 15
14func TestFileDescriptorLeak(t *testing.T) { 16const (
15 const ( 17 binary = "./node_exporter"
16 binary = "./node_exporter" 18 address = "localhost:19100"
17 address = "localhost:9100" 19)
18 )
19 20
21func TestFileDescriptorLeak(t *testing.T) {
20 if _, err := os.Stat(binary); err != nil { 22 if _, err := os.Stat(binary); err != nil {
21 t.Skipf("node_exporter binary not available, try to run `make build` first: %s", err) 23 t.Skipf("node_exporter binary not available, try to run `make build` first: %s", err)
22 } 24 }
@@ -24,75 +26,111 @@ func TestFileDescriptorLeak(t *testing.T) {
24 t.Skipf("proc filesystem is not available, but currently required to read number of open file descriptors: %s", err) 26 t.Skipf("proc filesystem is not available, but currently required to read number of open file descriptors: %s", err)
25 } 27 }
26 28
27 errc := make(chan error)
28 exporter := exec.Command(binary, "-web.listen-address", address) 29 exporter := exec.Command(binary, "-web.listen-address", address)
29 go func() { 30 test := func(pid int) error {
30 if err := exporter.Run(); err != nil { 31 if err := queryExporter(address); err != nil {
31 errc <- fmt.Errorf("execution of node_exporter failed: %s", err) 32 return err
32 } else {
33 errc <- nil
34 }
35 }()
36
37 select {
38 case err := <-errc:
39 t.Fatal(err)
40 case <-time.After(100 * time.Millisecond):
41 }
42
43 go func(pid int, url string) {
44 if err := queryExporter(url); err != nil {
45 errc <- err
46 return
47 } 33 }
48 proc, err := procfs.NewProc(pid) 34 proc, err := procfs.NewProc(pid)
49 if err != nil { 35 if err != nil {
50 errc <- err 36 return err
51 return
52 } 37 }
53 fdsBefore, err := proc.FileDescriptors() 38 fdsBefore, err := proc.FileDescriptors()
54 if err != nil { 39 if err != nil {
55 errc <- err 40 return err
56 return
57 } 41 }
58 for i := 0; i < 5; i++ { 42 for i := 0; i < 5; i++ {
59 if err := queryExporter(url); err != nil { 43 if err := queryExporter(address); err != nil {
60 errc <- err 44 return err
61 return
62 } 45 }
63 } 46 }
64 fdsAfter, err := proc.FileDescriptors() 47 fdsAfter, err := proc.FileDescriptors()
65 if err != nil { 48 if err != nil {
66 errc <- err 49 return err
67 return
68 } 50 }
69 if want, have := len(fdsBefore), len(fdsAfter); want != have { 51 if want, have := len(fdsBefore), len(fdsAfter); want != have {
70 errc <- fmt.Errorf("want %d open file descriptors after metrics scrape, have %d", want, have) 52 return fmt.Errorf("want %d open file descriptors after metrics scrape, have %d", want, have)
71 } 53 }
72 errc <- nil 54 return nil
73 }(exporter.Process.Pid, fmt.Sprintf("http://%s/metrics", address)) 55 }
74 56
75 select { 57 if err := runCommandAndTests(exporter, test); err != nil {
76 case err := <-errc: 58 t.Error(err)
77 if exporter.Process != nil {
78 exporter.Process.Kill()
79 }
80 if err != nil {
81 t.Fatal(err)
82 }
83 } 59 }
84} 60}
85 61
86func queryExporter(url string) error { 62func TestHandlingOfDuplicatedMetrics(t *testing.T) {
87 resp, err := http.Get(url) 63 if _, err := os.Stat(binary); err != nil {
64 t.Skipf("node_exporter binary not available, try to run `make build` first: %s", err)
65 }
66
67 dir, err := ioutil.TempDir("", "node-exporter")
68 if err != nil {
69 t.Fatal(err)
70 }
71 defer os.RemoveAll(dir)
72
73 content := []byte("dummy_metric 1\n")
74 if err := ioutil.WriteFile(filepath.Join(dir, "a.prom"), content, 0600); err != nil {
75 t.Fatal(err)
76 }
77 if err := ioutil.WriteFile(filepath.Join(dir, "b.prom"), content, 0600); err != nil {
78 t.Fatal(err)
79 }
80
81 exporter := exec.Command(binary, "-web.listen-address", address, "-collector.textfile.directory", dir)
82 test := func(_ int) error {
83 return queryExporter(address)
84 }
85
86 if err := runCommandAndTests(exporter, test); err != nil {
87 t.Error(err)
88 }
89}
90
91func queryExporter(address string) error {
92 resp, err := http.Get(fmt.Sprintf("http://%s/metrics", address))
88 if err != nil { 93 if err != nil {
89 return err 94 return err
90 } 95 }
91 if err := resp.Body.Close(); err != nil { 96 if err := resp.Body.Close(); err != nil {
92 return err 97 return err
93 } 98 }
94 if want, have := resp.StatusCode, http.StatusOK; want != have { 99 if want, have := http.StatusOK, resp.StatusCode; want != have {
95 return fmt.Errorf("want /metrics status code %d, have %d", want, have) 100 return fmt.Errorf("want /metrics status code %d, have %d", want, have)
96 } 101 }
97 return nil 102 return nil
98} 103}
104
105func runCommandAndTests(cmd *exec.Cmd, fn func(pid int) error) error {
106 errc := make(chan error)
107 go func() {
108 if err := cmd.Run(); err != nil {
109 errc <- fmt.Errorf("execution of command failed: %s", err)
110 } else {
111 errc <- nil
112 }
113 }()
114
115 // Allow the process to start before running any tests.
116 select {
117 case err := <-errc:
118 return err
119 case <-time.After(100 * time.Millisecond):
120 }
121
122 go func(pid int) {
123 errc <- fn(pid)
124 }(cmd.Process.Pid)
125
126 select {
127 case err := <-errc:
128 if cmd.Process != nil {
129 cmd.Process.Kill()
130 }
131 if err != nil {
132 return err
133 }
134 }
135 return nil
136}