|
0 |
package cloudwatch
|
|
1 |
|
|
2 |
import (
|
|
3 |
"errors"
|
|
4 |
"testing"
|
|
5 |
|
|
6 |
"sync"
|
|
7 |
|
|
8 |
"fmt"
|
|
9 |
|
|
10 |
"github.com/aws/aws-sdk-go/service/cloudwatch"
|
|
11 |
"github.com/aws/aws-sdk-go/service/cloudwatch/cloudwatchiface"
|
|
12 |
"github.com/go-kit/kit/log"
|
|
13 |
"github.com/go-kit/kit/metrics/teststat"
|
|
14 |
)
|
|
15 |
|
|
16 |
type mockCloudWatch struct {
|
|
17 |
cloudwatchiface.CloudWatchAPI
|
|
18 |
mtx sync.RWMutex
|
|
19 |
valuesReceived map[string]float64
|
|
20 |
dimensionsReceived map[string][]*cloudwatch.Dimension
|
|
21 |
}
|
|
22 |
|
|
23 |
func newMockCloudWatch() *mockCloudWatch {
|
|
24 |
return &mockCloudWatch{
|
|
25 |
valuesReceived: map[string]float64{},
|
|
26 |
dimensionsReceived: map[string][]*cloudwatch.Dimension{},
|
|
27 |
}
|
|
28 |
}
|
|
29 |
|
|
30 |
func (mcw *mockCloudWatch) PutMetricData(input *cloudwatch.PutMetricDataInput) (*cloudwatch.PutMetricDataOutput, error) {
|
|
31 |
mcw.mtx.Lock()
|
|
32 |
defer mcw.mtx.Unlock()
|
|
33 |
for _, datum := range input.MetricData {
|
|
34 |
mcw.valuesReceived[*datum.MetricName] = *datum.Value
|
|
35 |
mcw.dimensionsReceived[*datum.MetricName] = datum.Dimensions
|
|
36 |
}
|
|
37 |
return nil, nil
|
|
38 |
}
|
|
39 |
|
|
40 |
func testDimensions(svc *mockCloudWatch, name string, labelValues ...string) error {
|
|
41 |
dimensions, ok := svc.dimensionsReceived[name]
|
|
42 |
if !ok {
|
|
43 |
if len(labelValues) > 0 {
|
|
44 |
return errors.New("Expected dimensions to be available, but none were")
|
|
45 |
}
|
|
46 |
}
|
|
47 |
LabelValues:
|
|
48 |
for i, j := 0, 0; i < len(labelValues); i, j = i+2, j+1 {
|
|
49 |
name, value := labelValues[i], labelValues[i+1]
|
|
50 |
for _, dimension := range dimensions {
|
|
51 |
if *dimension.Name == name {
|
|
52 |
if *dimension.Value == value {
|
|
53 |
break LabelValues
|
|
54 |
}
|
|
55 |
}
|
|
56 |
}
|
|
57 |
return fmt.Errorf("Could not find dimension with name %s and value %s", name, value)
|
|
58 |
}
|
|
59 |
|
|
60 |
return nil
|
|
61 |
}
|
|
62 |
|
|
63 |
func TestCounter(t *testing.T) {
|
|
64 |
namespace, name := "abc", "def"
|
|
65 |
label, value := "label", "value"
|
|
66 |
svc := newMockCloudWatch()
|
|
67 |
cw := New(namespace, log.NewNopLogger(), svc)
|
|
68 |
counter := cw.NewCounter(name).With(label, value)
|
|
69 |
valuef := func() float64 {
|
|
70 |
err := cw.Send()
|
|
71 |
if err != nil {
|
|
72 |
t.Fatal(err)
|
|
73 |
}
|
|
74 |
svc.mtx.RLock()
|
|
75 |
defer svc.mtx.RUnlock()
|
|
76 |
return svc.valuesReceived[name]
|
|
77 |
}
|
|
78 |
if err := teststat.TestCounter(counter, valuef); err != nil {
|
|
79 |
t.Fatal(err)
|
|
80 |
}
|
|
81 |
if err := testDimensions(svc, name, label, value); err != nil {
|
|
82 |
t.Fatal(err)
|
|
83 |
}
|
|
84 |
}
|
|
85 |
|
|
86 |
func TestGauge(t *testing.T) {
|
|
87 |
namespace, name := "abc", "def"
|
|
88 |
label, value := "label", "value"
|
|
89 |
svc := newMockCloudWatch()
|
|
90 |
cw := New(namespace, log.NewNopLogger(), svc)
|
|
91 |
gauge := cw.NewGauge(name).With(label, value)
|
|
92 |
valuef := func() float64 {
|
|
93 |
err := cw.Send()
|
|
94 |
if err != nil {
|
|
95 |
t.Fatal(err)
|
|
96 |
}
|
|
97 |
svc.mtx.RLock()
|
|
98 |
defer svc.mtx.RUnlock()
|
|
99 |
return svc.valuesReceived[name]
|
|
100 |
}
|
|
101 |
if err := teststat.TestGauge(gauge, valuef); err != nil {
|
|
102 |
t.Fatal(err)
|
|
103 |
}
|
|
104 |
if err := testDimensions(svc, name, label, value); err != nil {
|
|
105 |
t.Fatal(err)
|
|
106 |
}
|
|
107 |
}
|
|
108 |
|
|
109 |
func TestHistogram(t *testing.T) {
|
|
110 |
namespace, name := "abc", "def"
|
|
111 |
label, value := "label", "value"
|
|
112 |
svc := newMockCloudWatch()
|
|
113 |
cw := New(namespace, log.NewNopLogger(), svc)
|
|
114 |
histogram := cw.NewHistogram(name, 50).With(label, value)
|
|
115 |
n50 := fmt.Sprintf("%s_50", name)
|
|
116 |
n90 := fmt.Sprintf("%s_90", name)
|
|
117 |
n95 := fmt.Sprintf("%s_95", name)
|
|
118 |
n99 := fmt.Sprintf("%s_99", name)
|
|
119 |
quantiles := func() (p50, p90, p95, p99 float64) {
|
|
120 |
err := cw.Send()
|
|
121 |
if err != nil {
|
|
122 |
t.Fatal(err)
|
|
123 |
}
|
|
124 |
svc.mtx.RLock()
|
|
125 |
defer svc.mtx.RUnlock()
|
|
126 |
p50 = svc.valuesReceived[n50]
|
|
127 |
p90 = svc.valuesReceived[n90]
|
|
128 |
p95 = svc.valuesReceived[n95]
|
|
129 |
p99 = svc.valuesReceived[n99]
|
|
130 |
return
|
|
131 |
}
|
|
132 |
if err := teststat.TestHistogram(histogram, quantiles, 0.01); err != nil {
|
|
133 |
t.Fatal(err)
|
|
134 |
}
|
|
135 |
if err := testDimensions(svc, n50, label, value); err != nil {
|
|
136 |
t.Fatal(err)
|
|
137 |
}
|
|
138 |
if err := testDimensions(svc, n90, label, value); err != nil {
|
|
139 |
t.Fatal(err)
|
|
140 |
}
|
|
141 |
if err := testDimensions(svc, n95, label, value); err != nil {
|
|
142 |
t.Fatal(err)
|
|
143 |
}
|
|
144 |
if err := testDimensions(svc, n99, label, value); err != nil {
|
|
145 |
t.Fatal(err)
|
|
146 |
}
|
|
147 |
}
|