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
14package notify
15
16import (
17	"bytes"
18	"fmt"
19	"io"
20	"io/ioutil"
21	"net/http"
22	"testing"
23
24	"github.com/stretchr/testify/require"
25)
26
27func TestTruncate(t *testing.T) {
28	testCases := []struct {
29		in string
30		n  int
31
32		out   string
33		trunc bool
34	}{
35		{
36			in:    "",
37			n:     5,
38			out:   "",
39			trunc: false,
40		},
41		{
42			in:    "abcde",
43			n:     2,
44			out:   "ab",
45			trunc: true,
46		},
47		{
48			in:    "abcde",
49			n:     4,
50			out:   "a...",
51			trunc: true,
52		},
53		{
54			in:    "abcde",
55			n:     5,
56			out:   "abcde",
57			trunc: false,
58		},
59		{
60			in:    "abcdefgh",
61			n:     5,
62			out:   "ab...",
63			trunc: true,
64		},
65		{
66			in:    "a⌘cde",
67			n:     5,
68			out:   "a⌘cde",
69			trunc: false,
70		},
71		{
72			in:    "a⌘cdef",
73			n:     5,
74			out:   "a⌘...",
75			trunc: true,
76		},
77	}
78
79	for _, tc := range testCases {
80		t.Run(fmt.Sprintf("truncate(%s,%d)", tc.in, tc.n), func(t *testing.T) {
81			s, trunc := Truncate(tc.in, tc.n)
82			require.Equal(t, tc.trunc, trunc)
83			require.Equal(t, tc.out, s)
84		})
85	}
86}
87
88type brokenReader struct{}
89
90func (b brokenReader) Read([]byte) (int, error) {
91	return 0, fmt.Errorf("some error")
92}
93
94func TestRetrierCheck(t *testing.T) {
95	for _, tc := range []struct {
96		retrier Retrier
97		status  int
98		body    io.Reader
99
100		retry       bool
101		expectedErr string
102	}{
103		{
104			retrier: Retrier{},
105			status:  http.StatusOK,
106			body:    bytes.NewBuffer([]byte("ok")),
107
108			retry: false,
109		},
110		{
111			retrier: Retrier{},
112			status:  http.StatusNoContent,
113
114			retry: false,
115		},
116		{
117			retrier: Retrier{},
118			status:  http.StatusBadRequest,
119
120			retry:       false,
121			expectedErr: "unexpected status code 400",
122		},
123		{
124			retrier: Retrier{RetryCodes: []int{http.StatusTooManyRequests}},
125			status:  http.StatusBadRequest,
126			body:    bytes.NewBuffer([]byte("invalid request")),
127
128			retry:       false,
129			expectedErr: "unexpected status code 400: invalid request",
130		},
131		{
132			retrier: Retrier{RetryCodes: []int{http.StatusTooManyRequests}},
133			status:  http.StatusTooManyRequests,
134
135			retry:       true,
136			expectedErr: "unexpected status code 429",
137		},
138		{
139			retrier: Retrier{},
140			status:  http.StatusServiceUnavailable,
141			body:    bytes.NewBuffer([]byte("retry later")),
142
143			retry:       true,
144			expectedErr: "unexpected status code 503: retry later",
145		},
146		{
147			retrier: Retrier{},
148			status:  http.StatusBadGateway,
149			body:    &brokenReader{},
150
151			retry:       true,
152			expectedErr: "unexpected status code 502",
153		},
154		{
155			retrier: Retrier{CustomDetailsFunc: func(status int, b io.Reader) string {
156				if status != http.StatusServiceUnavailable {
157					return "invalid"
158				}
159				bs, _ := ioutil.ReadAll(b)
160				return fmt.Sprintf("server response is %q", string(bs))
161			}},
162			status: http.StatusServiceUnavailable,
163			body:   bytes.NewBuffer([]byte("retry later")),
164
165			retry:       true,
166			expectedErr: "unexpected status code 503: server response is \"retry later\"",
167		},
168	} {
169		t.Run("", func(t *testing.T) {
170			retry, err := tc.retrier.Check(tc.status, tc.body)
171			require.Equal(t, tc.retry, retry)
172			if tc.expectedErr == "" {
173				require.NoError(t, err)
174				return
175			}
176			require.EqualError(t, err, tc.expectedErr)
177		})
178	}
179}
180