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  }