github.com/thanos-io/thanos@v0.32.5/pkg/alert/alert_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package alert 5 6 import ( 7 "context" 8 "net/http" 9 "net/http/httptest" 10 "net/url" 11 "sync" 12 "testing" 13 "time" 14 15 "github.com/pkg/errors" 16 promtestutil "github.com/prometheus/client_golang/prometheus/testutil" 17 "github.com/prometheus/common/model" 18 "github.com/prometheus/prometheus/model/labels" 19 "github.com/prometheus/prometheus/model/relabel" 20 "github.com/prometheus/prometheus/notifier" 21 22 "github.com/efficientgo/core/testutil" 23 ) 24 25 func TestQueue_Pop_all_Pushed(t *testing.T) { 26 qcapacity := 10 27 batchsize := 1 28 pushes := 3 29 30 q := NewQueue(nil, nil, qcapacity, batchsize, nil, nil, nil) 31 for i := 0; i < pushes; i++ { 32 q.Push([]*notifier.Alert{ 33 {}, 34 {}, 35 }) 36 } 37 38 timeoutc := make(chan struct{}, 1) 39 time.AfterFunc(time.Second, func() { timeoutc <- struct{}{} }) 40 popped := 0 41 for p := q.Pop(timeoutc); p != nil; p = q.Pop(timeoutc) { 42 popped += len(p) 43 } 44 45 testutil.Equals(t, pushes*2, popped) 46 } 47 48 func TestQueue_Push_Relabelled(t *testing.T) { 49 q := NewQueue(nil, nil, 10, 10, labels.FromStrings("a", "1", "replica", "A"), []string{"b", "replica"}, nil) 50 51 q.Push([]*notifier.Alert{ 52 {Labels: labels.FromStrings("b", "2", "c", "3")}, 53 {Labels: labels.FromStrings("c", "3")}, 54 {Labels: labels.FromStrings("a", "2")}, 55 }) 56 57 testutil.Equals(t, 3, len(q.queue)) 58 testutil.Equals(t, labels.FromStrings("a", "1", "c", "3"), q.queue[0].Labels) 59 testutil.Equals(t, labels.FromStrings("a", "1", "c", "3"), q.queue[1].Labels) 60 testutil.Equals(t, labels.FromStrings("a", "1"), q.queue[2].Labels) 61 } 62 63 func TestQueue_Push_Relabelled_Alerts(t *testing.T) { 64 q := NewQueue( 65 nil, nil, 10, 10, labels.New(), []string{}, 66 []*relabel.Config{ 67 { 68 SourceLabels: model.LabelNames{"a"}, 69 Separator: ";", 70 Regex: relabel.MustNewRegexp(".*(b).*"), 71 TargetLabel: "d", 72 Action: relabel.Replace, 73 Replacement: "$1", 74 }, 75 }, 76 ) 77 78 q.Push([]*notifier.Alert{ 79 {Labels: labels.FromMap(map[string]string{ 80 "a": "abc", 81 })}, 82 }) 83 84 testutil.Equals(t, 1, len(q.queue)) 85 testutil.Equals( 86 t, labels.FromMap(map[string]string{ 87 "a": "abc", 88 "d": "b", 89 }), 90 q.queue[0].Labels, 91 ) 92 } 93 94 func TestQueue_Push_RelabelDropAlerts(t *testing.T) { 95 q := NewQueue(nil, nil, 10, 10, nil, nil, 96 []*relabel.Config{ 97 { 98 SourceLabels: model.LabelNames{"a"}, 99 Regex: relabel.MustNewRegexp("1"), 100 Action: relabel.Drop, 101 }, 102 }) 103 104 q.Push([]*notifier.Alert{ 105 {Labels: labels.FromStrings("a", "1")}, 106 {Labels: labels.FromStrings("a", "2")}, 107 {Labels: labels.FromStrings("b", "3")}, 108 }) 109 110 testutil.Equals(t, 2, len(q.queue)) 111 testutil.Equals(t, labels.FromStrings("a", "2"), q.queue[0].Labels) 112 testutil.Equals(t, labels.FromStrings("b", "3"), q.queue[1].Labels) 113 } 114 115 func assertSameHosts(t *testing.T, expected, found []*url.URL) { 116 testutil.Equals(t, len(expected), len(found)) 117 118 host := map[string]struct{}{} 119 for _, u := range expected { 120 host[u.Host] = struct{}{} 121 } 122 123 for _, u := range found { 124 _, ok := host[u.Host] 125 testutil.Assert(t, ok, "host %s not found in expected URL list %v", u.Host, expected) 126 } 127 } 128 129 type fakeClient struct { 130 urls []*url.URL 131 dof func(u *url.URL) (*http.Response, error) 132 mtx sync.Mutex 133 seen []*url.URL 134 } 135 136 func (f *fakeClient) Endpoints() []*url.URL { 137 return f.urls 138 } 139 140 func (f *fakeClient) Do(req *http.Request) (*http.Response, error) { 141 f.mtx.Lock() 142 defer f.mtx.Unlock() 143 u := req.URL 144 f.seen = append(f.seen, u) 145 if f.dof == nil { 146 rec := httptest.NewRecorder() 147 rec.WriteHeader(http.StatusOK) 148 return rec.Result(), nil 149 } 150 return f.dof(u) 151 } 152 153 func TestSenderSendsOk(t *testing.T) { 154 poster := &fakeClient{ 155 urls: []*url.URL{{Host: "am1:9090"}, {Host: "am2:9090"}}, 156 } 157 s := NewSender(nil, nil, []*Alertmanager{NewAlertmanager(nil, poster, time.Minute, APIv1)}) 158 159 s.Send(context.Background(), []*notifier.Alert{{}, {}}) 160 161 assertSameHosts(t, poster.urls, poster.seen) 162 163 testutil.Equals(t, 2, int(promtestutil.ToFloat64(s.sent.WithLabelValues(poster.urls[0].Host)))) 164 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.errs.WithLabelValues(poster.urls[0].Host)))) 165 166 testutil.Equals(t, 2, int(promtestutil.ToFloat64(s.sent.WithLabelValues(poster.urls[1].Host)))) 167 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.errs.WithLabelValues(poster.urls[1].Host)))) 168 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.dropped))) 169 } 170 171 func TestSenderSendsOneFails(t *testing.T) { 172 poster := &fakeClient{ 173 urls: []*url.URL{{Host: "am1:9090"}, {Host: "am2:9090"}}, 174 dof: func(u *url.URL) (*http.Response, error) { 175 rec := httptest.NewRecorder() 176 if u.Host == "am1:9090" { 177 rec.WriteHeader(http.StatusBadRequest) 178 } else { 179 rec.WriteHeader(http.StatusOK) 180 } 181 return rec.Result(), nil 182 }, 183 } 184 s := NewSender(nil, nil, []*Alertmanager{NewAlertmanager(nil, poster, time.Minute, APIv1)}) 185 186 s.Send(context.Background(), []*notifier.Alert{{}, {}}) 187 188 assertSameHosts(t, poster.urls, poster.seen) 189 190 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.sent.WithLabelValues(poster.urls[0].Host)))) 191 testutil.Equals(t, 1, int(promtestutil.ToFloat64(s.errs.WithLabelValues(poster.urls[0].Host)))) 192 193 testutil.Equals(t, 2, int(promtestutil.ToFloat64(s.sent.WithLabelValues(poster.urls[1].Host)))) 194 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.errs.WithLabelValues(poster.urls[1].Host)))) 195 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.dropped))) 196 } 197 198 func TestSenderSendsAllFail(t *testing.T) { 199 poster := &fakeClient{ 200 urls: []*url.URL{{Host: "am1:9090"}, {Host: "am2:9090"}}, 201 dof: func(u *url.URL) (*http.Response, error) { 202 return nil, errors.New("no such host") 203 }, 204 } 205 s := NewSender(nil, nil, []*Alertmanager{NewAlertmanager(nil, poster, time.Minute, APIv1)}) 206 207 s.Send(context.Background(), []*notifier.Alert{{}, {}}) 208 209 assertSameHosts(t, poster.urls, poster.seen) 210 211 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.sent.WithLabelValues(poster.urls[0].Host)))) 212 testutil.Equals(t, 1, int(promtestutil.ToFloat64(s.errs.WithLabelValues(poster.urls[0].Host)))) 213 214 testutil.Equals(t, 0, int(promtestutil.ToFloat64(s.sent.WithLabelValues(poster.urls[1].Host)))) 215 testutil.Equals(t, 1, int(promtestutil.ToFloat64(s.errs.WithLabelValues(poster.urls[1].Host)))) 216 testutil.Equals(t, 2, int(promtestutil.ToFloat64(s.dropped))) 217 }