...

Source file src/github.com/prometheus/alertmanager/notify/test/test.go

Documentation: github.com/prometheus/alertmanager/notify/test

     1  // Copyright 2019 Prometheus Team
     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  
    14  package test
    15  
    16  import (
    17  	"context"
    18  	"net/http"
    19  	"net/http/httptest"
    20  	"net/url"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/prometheus/common/model"
    25  	"github.com/stretchr/testify/require"
    26  
    27  	"github.com/prometheus/alertmanager/notify"
    28  	"github.com/prometheus/alertmanager/template"
    29  	"github.com/prometheus/alertmanager/types"
    30  )
    31  
    32  // RetryTests returns a map of HTTP status codes to bool indicating whether the notifier should retry or not.
    33  func RetryTests(retryCodes []int) map[int]bool {
    34  	tests := map[int]bool{
    35  		// 1xx
    36  		http.StatusContinue:           false,
    37  		http.StatusSwitchingProtocols: false,
    38  		http.StatusProcessing:         false,
    39  
    40  		// 2xx
    41  		http.StatusOK:                   false,
    42  		http.StatusCreated:              false,
    43  		http.StatusAccepted:             false,
    44  		http.StatusNonAuthoritativeInfo: false,
    45  		http.StatusNoContent:            false,
    46  		http.StatusResetContent:         false,
    47  		http.StatusPartialContent:       false,
    48  		http.StatusMultiStatus:          false,
    49  		http.StatusAlreadyReported:      false,
    50  		http.StatusIMUsed:               false,
    51  
    52  		// 3xx
    53  		http.StatusMultipleChoices:   false,
    54  		http.StatusMovedPermanently:  false,
    55  		http.StatusFound:             false,
    56  		http.StatusSeeOther:          false,
    57  		http.StatusNotModified:       false,
    58  		http.StatusUseProxy:          false,
    59  		http.StatusTemporaryRedirect: false,
    60  		http.StatusPermanentRedirect: false,
    61  
    62  		// 4xx
    63  		http.StatusBadRequest:                   false,
    64  		http.StatusUnauthorized:                 false,
    65  		http.StatusPaymentRequired:              false,
    66  		http.StatusForbidden:                    false,
    67  		http.StatusNotFound:                     false,
    68  		http.StatusMethodNotAllowed:             false,
    69  		http.StatusNotAcceptable:                false,
    70  		http.StatusProxyAuthRequired:            false,
    71  		http.StatusRequestTimeout:               false,
    72  		http.StatusConflict:                     false,
    73  		http.StatusGone:                         false,
    74  		http.StatusLengthRequired:               false,
    75  		http.StatusPreconditionFailed:           false,
    76  		http.StatusRequestEntityTooLarge:        false,
    77  		http.StatusRequestURITooLong:            false,
    78  		http.StatusUnsupportedMediaType:         false,
    79  		http.StatusRequestedRangeNotSatisfiable: false,
    80  		http.StatusExpectationFailed:            false,
    81  		http.StatusTeapot:                       false,
    82  		http.StatusUnprocessableEntity:          false,
    83  		http.StatusLocked:                       false,
    84  		http.StatusFailedDependency:             false,
    85  		http.StatusUpgradeRequired:              false,
    86  		http.StatusPreconditionRequired:         false,
    87  		http.StatusTooManyRequests:              false,
    88  		http.StatusRequestHeaderFieldsTooLarge:  false,
    89  		http.StatusUnavailableForLegalReasons:   false,
    90  
    91  		// 5xx
    92  		http.StatusInternalServerError:           false,
    93  		http.StatusNotImplemented:                false,
    94  		http.StatusBadGateway:                    false,
    95  		http.StatusServiceUnavailable:            false,
    96  		http.StatusGatewayTimeout:                false,
    97  		http.StatusHTTPVersionNotSupported:       false,
    98  		http.StatusVariantAlsoNegotiates:         false,
    99  		http.StatusInsufficientStorage:           false,
   100  		http.StatusLoopDetected:                  false,
   101  		http.StatusNotExtended:                   false,
   102  		http.StatusNetworkAuthenticationRequired: false,
   103  	}
   104  
   105  	for _, statusCode := range retryCodes {
   106  		tests[statusCode] = true
   107  	}
   108  
   109  	return tests
   110  }
   111  
   112  // DefaultRetryCodes returns the list of HTTP status codes that need to be retried.
   113  func DefaultRetryCodes() []int {
   114  	return []int{
   115  		http.StatusInternalServerError,
   116  		http.StatusNotImplemented,
   117  		http.StatusBadGateway,
   118  		http.StatusServiceUnavailable,
   119  		http.StatusGatewayTimeout,
   120  		http.StatusHTTPVersionNotSupported,
   121  		http.StatusVariantAlsoNegotiates,
   122  		http.StatusInsufficientStorage,
   123  		http.StatusLoopDetected,
   124  		http.StatusNotExtended,
   125  		http.StatusNetworkAuthenticationRequired,
   126  	}
   127  }
   128  
   129  // CreateTmpl returns a ready-to-use template.
   130  func CreateTmpl(t *testing.T) *template.Template {
   131  	tmpl, err := template.FromGlobs()
   132  	require.NoError(t, err)
   133  	tmpl.ExternalURL, _ = url.Parse("http://am")
   134  	return tmpl
   135  }
   136  
   137  // AssertNotifyLeaksNoSecret calls the Notify() method of the notifier, expects
   138  // it to fail because the context is canceled by the server and checks that no
   139  // secret data is leaked in the error message returned by Notify().
   140  func AssertNotifyLeaksNoSecret(ctx context.Context, t *testing.T, n notify.Notifier, secret ...string) {
   141  	t.Helper()
   142  	require.NotEmpty(t, secret)
   143  
   144  	ctx = notify.WithGroupKey(ctx, "1")
   145  	ok, err := n.Notify(ctx, []*types.Alert{
   146  		{
   147  			Alert: model.Alert{
   148  				Labels: model.LabelSet{
   149  					"lbl1": "val1",
   150  				},
   151  				StartsAt: time.Now(),
   152  				EndsAt:   time.Now().Add(time.Hour),
   153  			},
   154  		},
   155  	}...)
   156  
   157  	require.Error(t, err)
   158  	require.Contains(t, err.Error(), context.Canceled.Error())
   159  	for _, s := range secret {
   160  		require.NotContains(t, err.Error(), s)
   161  	}
   162  	require.True(t, ok)
   163  }
   164  
   165  // GetContextWithCancelingURL returns a context that gets canceled when a
   166  // client does a GET request to the returned URL.
   167  // Handlers passed to the function will be invoked in order before the context gets canceled.
   168  // The last argument is a function that needs to be called before the caller returns.
   169  func GetContextWithCancelingURL(h ...func(w http.ResponseWriter, r *http.Request)) (context.Context, *url.URL, func()) {
   170  	done := make(chan struct{})
   171  	ctx, cancel := context.WithCancel(context.Background())
   172  	i := 0
   173  
   174  	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   175  		if i < len(h) {
   176  			h[i](w, r)
   177  		} else {
   178  			cancel()
   179  			<-done
   180  		}
   181  		i++
   182  	}))
   183  
   184  	// No need to check the error since httptest.NewServer always return a valid URL.
   185  	u, _ := url.Parse(srv.URL)
   186  
   187  	return ctx, u, func() {
   188  		close(done)
   189  		srv.Close()
   190  	}
   191  }
   192  

View as plain text