1package prometheus
2
3import (
4	"runtime"
5	"testing"
6	"time"
7
8	dto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/prometheus/client_model/go"
9)
10
11func TestGoCollector(t *testing.T) {
12	var (
13		c      = NewGoCollector()
14		ch     = make(chan Metric)
15		waitc  = make(chan struct{})
16		closec = make(chan struct{})
17		old    = -1
18	)
19	defer close(closec)
20
21	go func() {
22		c.Collect(ch)
23		go func(c <-chan struct{}) {
24			<-c
25		}(closec)
26		<-waitc
27		c.Collect(ch)
28	}()
29
30	for {
31		select {
32		case metric := <-ch:
33			switch m := metric.(type) {
34			// Attention, this also catches Counter...
35			case Gauge:
36				pb := &dto.Metric{}
37				m.Write(pb)
38				if pb.GetGauge() == nil {
39					continue
40				}
41
42				if old == -1 {
43					old = int(pb.GetGauge().GetValue())
44					close(waitc)
45					continue
46				}
47
48				if diff := int(pb.GetGauge().GetValue()) - old; diff != 1 {
49					// TODO: This is flaky in highly concurrent situations.
50					t.Errorf("want 1 new goroutine, got %d", diff)
51				}
52
53				// GoCollector performs two sends per call.
54				// On line 27 we need to receive the second send
55				// to shut down cleanly.
56				<-ch
57				return
58			}
59		case <-time.After(1 * time.Second):
60			t.Fatalf("expected collect timed out")
61		}
62	}
63}
64
65func TestGCCollector(t *testing.T) {
66	var (
67		c        = NewGoCollector()
68		ch       = make(chan Metric)
69		waitc    = make(chan struct{})
70		closec   = make(chan struct{})
71		oldGC    uint64
72		oldPause float64
73	)
74	defer close(closec)
75
76	go func() {
77		c.Collect(ch)
78		// force GC
79		runtime.GC()
80		<-waitc
81		c.Collect(ch)
82	}()
83
84	first := true
85	for {
86		select {
87		case metric := <-ch:
88			switch m := metric.(type) {
89			case *constSummary, *value:
90				pb := &dto.Metric{}
91				m.Write(pb)
92				if pb.GetSummary() == nil {
93					continue
94				}
95
96				if len(pb.GetSummary().Quantile) != 5 {
97					t.Errorf("expected 4 buckets, got %d", len(pb.GetSummary().Quantile))
98				}
99				for idx, want := range []float64{0.0, 0.25, 0.5, 0.75, 1.0} {
100					if *pb.GetSummary().Quantile[idx].Quantile != want {
101						t.Errorf("bucket #%d is off, got %f, want %f", idx, *pb.GetSummary().Quantile[idx].Quantile, want)
102					}
103				}
104				if first {
105					first = false
106					oldGC = *pb.GetSummary().SampleCount
107					oldPause = *pb.GetSummary().SampleSum
108					close(waitc)
109					continue
110				}
111				if diff := *pb.GetSummary().SampleCount - oldGC; diff != 1 {
112					t.Errorf("want 1 new garbage collection run, got %d", diff)
113				}
114				if diff := *pb.GetSummary().SampleSum - oldPause; diff <= 0 {
115					t.Errorf("want moar pause, got %f", diff)
116				}
117				return
118			}
119		case <-time.After(1 * time.Second):
120			t.Fatalf("expected collect timed out")
121		}
122	}
123}
124