1// Copyright 2014 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package prometheus 15 16import ( 17 "math" 18 "math/rand" 19 "sync" 20 "testing" 21 "testing/quick" 22 23 dto "github.com/coreos/etcd/Godeps/_workspace/src/github.com/prometheus/client_model/go" 24) 25 26func listenGaugeStream(vals, result chan float64, done chan struct{}) { 27 var sum float64 28outer: 29 for { 30 select { 31 case <-done: 32 close(vals) 33 for v := range vals { 34 sum += v 35 } 36 break outer 37 case v := <-vals: 38 sum += v 39 } 40 } 41 result <- sum 42 close(result) 43} 44 45func TestGaugeConcurrency(t *testing.T) { 46 it := func(n uint32) bool { 47 mutations := int(n % 10000) 48 concLevel := int(n%15 + 1) 49 50 var start, end sync.WaitGroup 51 start.Add(1) 52 end.Add(concLevel) 53 54 sStream := make(chan float64, mutations*concLevel) 55 result := make(chan float64) 56 done := make(chan struct{}) 57 58 go listenGaugeStream(sStream, result, done) 59 go func() { 60 end.Wait() 61 close(done) 62 }() 63 64 gge := NewGauge(GaugeOpts{ 65 Name: "test_gauge", 66 Help: "no help can be found here", 67 }) 68 for i := 0; i < concLevel; i++ { 69 vals := make([]float64, mutations) 70 for j := 0; j < mutations; j++ { 71 vals[j] = rand.Float64() - 0.5 72 } 73 74 go func(vals []float64) { 75 start.Wait() 76 for _, v := range vals { 77 sStream <- v 78 gge.Add(v) 79 } 80 end.Done() 81 }(vals) 82 } 83 start.Done() 84 85 if expected, got := <-result, math.Float64frombits(gge.(*value).valBits); math.Abs(expected-got) > 0.000001 { 86 t.Fatalf("expected approx. %f, got %f", expected, got) 87 return false 88 } 89 return true 90 } 91 92 if err := quick.Check(it, nil); err != nil { 93 t.Fatal(err) 94 } 95} 96 97func TestGaugeVecConcurrency(t *testing.T) { 98 it := func(n uint32) bool { 99 mutations := int(n % 10000) 100 concLevel := int(n%15 + 1) 101 vecLength := int(n%5 + 1) 102 103 var start, end sync.WaitGroup 104 start.Add(1) 105 end.Add(concLevel) 106 107 sStreams := make([]chan float64, vecLength) 108 results := make([]chan float64, vecLength) 109 done := make(chan struct{}) 110 111 for i := 0; i < vecLength; i++ { 112 sStreams[i] = make(chan float64, mutations*concLevel) 113 results[i] = make(chan float64) 114 go listenGaugeStream(sStreams[i], results[i], done) 115 } 116 117 go func() { 118 end.Wait() 119 close(done) 120 }() 121 122 gge := NewGaugeVec( 123 GaugeOpts{ 124 Name: "test_gauge", 125 Help: "no help can be found here", 126 }, 127 []string{"label"}, 128 ) 129 for i := 0; i < concLevel; i++ { 130 vals := make([]float64, mutations) 131 pick := make([]int, mutations) 132 for j := 0; j < mutations; j++ { 133 vals[j] = rand.Float64() - 0.5 134 pick[j] = rand.Intn(vecLength) 135 } 136 137 go func(vals []float64) { 138 start.Wait() 139 for i, v := range vals { 140 sStreams[pick[i]] <- v 141 gge.WithLabelValues(string('A' + pick[i])).Add(v) 142 } 143 end.Done() 144 }(vals) 145 } 146 start.Done() 147 148 for i := range sStreams { 149 if expected, got := <-results[i], math.Float64frombits(gge.WithLabelValues(string('A'+i)).(*value).valBits); math.Abs(expected-got) > 0.000001 { 150 t.Fatalf("expected approx. %f, got %f", expected, got) 151 return false 152 } 153 } 154 return true 155 } 156 157 if err := quick.Check(it, nil); err != nil { 158 t.Fatal(err) 159 } 160} 161 162func TestGaugeFunc(t *testing.T) { 163 gf := NewGaugeFunc( 164 GaugeOpts{ 165 Name: "test_name", 166 Help: "test help", 167 ConstLabels: Labels{"a": "1", "b": "2"}, 168 }, 169 func() float64 { return 3.1415 }, 170 ) 171 172 if expected, got := `Desc{fqName: "test_name", help: "test help", constLabels: {a="1",b="2"}, variableLabels: []}`, gf.Desc().String(); expected != got { 173 t.Errorf("expected %q, got %q", expected, got) 174 } 175 176 m := &dto.Metric{} 177 gf.Write(m) 178 179 if expected, got := `label:<name:"a" value:"1" > label:<name:"b" value:"2" > gauge:<value:3.1415 > `, m.String(); expected != got { 180 t.Errorf("expected %q, got %q", expected, got) 181 } 182} 183