Repository: favonia/cloudflare-ddns
Pull request #314 (2022-11-29 21:29:29)

refactor(monitor): use retryablehttp
Closes #239.


Patch:
diff --git a/internal/monitor/healthchecks.go b/internal/monitor/healthchecks.go
index 638a096..acbf364 100644
--- a/internal/monitor/healthchecks.go
+++ b/internal/monitor/healthchecks.go
@@ -10,6 +10,8 @@ import (
 	"strings"
 	"time"
 
+	"github.com/hashicorp/go-retryablehttp"
+
 	"github.com/favonia/cloudflare-ddns/internal/pp"
 )
 
@@ -21,35 +23,16 @@ type Healthchecks struct {
 
 	// Timeout for each ping.
 	Timeout time.Duration
-
-	// MaxRetries before giving up a ping.
-	MaxRetries int
 }
 
 const (
 	// HealthchecksDefaultTimeout is the default timeout for a Healthchecks ping.
 	HealthchecksDefaultTimeout = 10 * time.Second
-
-	// HealthchecksDefaultMaxRetries is the maximum number of retries to ping Healthchecks.
-	HealthchecksDefaultMaxRetries int = 5
 )
 
-// HealthchecksOption is an option for [NewHealthchecks].
-type HealthchecksOption func(*Healthchecks)
-
-// SetHealthchecksMaxRetries sets the MaxRetries of a Healthchecks.
-func SetHealthchecksMaxRetries(maxRetries int) HealthchecksOption {
-	if maxRetries <= 0 {
-		panic("maxRetries <= 0")
-	}
-	return func(h *Healthchecks) {
-		h.MaxRetries = maxRetries
-	}
-}
-
 // NewHealthchecks creates a new Healthchecks monitor.
 // See https://healthchecks.io/docs/http_api/ for more information.
-func NewHealthchecks(ppfmt pp.PP, rawURL string, os ...HealthchecksOption) (Monitor, bool) {
+func NewHealthchecks(ppfmt pp.PP, rawURL string) (Monitor, bool) {
 	url, err := url.Parse(rawURL)
 	if err != nil {
 		ppfmt.Errorf(pp.EmojiUserError, "Failed to parse the Healthchecks URL (redacted)")
@@ -57,8 +40,8 @@ func NewHealthchecks(ppfmt pp.PP, rawURL string, os ...HealthchecksOption) (Moni
 	}
 
 	if !(url.IsAbs() && url.Opaque == "" && url.Host != "") {
-		ppfmt.Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL.`)
-		ppfmt.Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc".`)
+		ppfmt.Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL`)
+		ppfmt.Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc"`)
 		return nil, false
 	}
 
@@ -70,19 +53,14 @@ func NewHealthchecks(ppfmt pp.PP, rawURL string, os ...HealthchecksOption) (Moni
 		// HTTPS is good!
 
 	default:
-		ppfmt.Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL.`)
-		ppfmt.Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc".`)
+		ppfmt.Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL`)
+		ppfmt.Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc"`)
 		return nil, false
 	}
 
 	h := &Healthchecks{
-		BaseURL:    url,
-		Timeout:    HealthchecksDefaultTimeout,
-		MaxRetries: HealthchecksDefaultMaxRetries,
-	}
-
-	for _, o := range os {
-		o(h)
+		BaseURL: url,
+		Timeout: HealthchecksDefaultTimeout,
 	}
 
 	return h, true
@@ -93,7 +71,35 @@ func (h *Healthchecks) Describe(callback func(service, params string)) {
 	callback("Healthchecks", "(URL redacted)")
 }
 
-//nolint:funlen
+/*
+ping sends a POST request to a Healthchecks server.
+
+Code and body for UUID API:
+
+  - 200
+    OK
+  - 200
+    OK (not found)
+  - 200
+    OK (rate limited)
+  - 400
+    invalid url format
+
+Code and body for the slug API:
+
+  - 200
+    OK
+  - 400
+    invalid url format
+  - 404
+    not found
+  - 409
+    ambiguous slug
+  - 429
+    rate limit exceeded
+
+To support both APIs, we check both (1) whether the status code is 200 and (2) whether the body is "OK".
+*/
 func (h *Healthchecks) ping(ctx context.Context, ppfmt pp.PP, endpoint string, message string) bool {
 	url := h.BaseURL.JoinPath(endpoint)
 
@@ -102,75 +108,47 @@ func (h *Healthchecks) ping(ctx context.Context, ppfmt pp.PP, endpoint string, m
 		endpointDescription = strconv.Quote(endpoint)
 	}
 
-	for retries := 0; retries < h.MaxRetries; retries++ {
-		if retries > 0 {
-			time.Sleep(time.Second << (retries - 1))
-		}
-
-		ctx, cancel := context.WithTimeout(ctx, h.Timeout)
-		defer cancel()
-
-		req, err := http.NewRequestWithContext(ctx, http.MethodPost, url.String(), strings.NewReader(message))
-		if err != nil {
-			ppfmt.Warningf(pp.EmojiImpossible,
-				"Failed to prepare HTTP(S) request to the %s endpoint of Healthchecks: %v",
-				endpointDescription, err)
-			return false
-		}
-
-		resp, err := http.DefaultClient.Do(req)
-		if err != nil {
-			ppfmt.Warningf(pp.EmojiError,
-				"Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v",
-				endpointDescription, err)
-			ppfmt.Infof(pp.EmojiRepeatOnce, "Trying again . . .")
-			continue
-		}
-		defer resp.Body.Close()
-		body, err := io.ReadAll(resp.Body)
-		if err != nil {
-			ppfmt.Warningf(pp.EmojiError,
-				"Failed to read HTTP(S) response from the %s endpoint of Healthchecks: %v",
-				endpointDescription, err)
-			ppfmt.Infof(pp.EmojiRepeatOnce, "Trying again . . .")
-			continue
-		}
-
-		/*
-			Code and body for uuid API:
-
-			200 OK
-			200 OK (not found)
-			200 OK (rate limited)
-			400 invalid url format
-
-			Code and body for the slug API:
-
-			200 OK
-			400 invalid url format
-			404 not found
-			409 ambiguous slug
-			429 rate limit exceeded
-		*/
-
-		bodyAsString := strings.TrimSpace(string(body))
-		if bodyAsString != "OK" {
-			ppfmt.Warningf(pp.EmojiError,
-				"Failed to ping the %s endpoint of Healthchecks; got response code: %d %s",
-				endpointDescription, resp.StatusCode, bodyAsString,
-			)
-			return false
-		}
-
-		ppfmt.Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", endpointDescription)
-		return true
+	ctx, cancel := context.WithTimeout(ctx, h.Timeout)
+	defer cancel()
+
+	req, err := retryablehttp.NewRequestWithContext(ctx, http.MethodPost, url.String(), strings.NewReader(message))
+	if err != nil {
+		ppfmt.Warningf(pp.EmojiImpossible,
+			"Failed to prepare HTTP(S) request to the %s endpoint of Healthchecks: %v",
+			endpointDescription, err)
+		return false
+	}
+
+	c := retryablehttp.NewClient()
+	c.Logger = nil
+
+	resp, err := c.Do(req)
+	if err != nil {
+		ppfmt.Warningf(pp.EmojiError,
+			"Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v",
+			endpointDescription, err)
+		return false
+	}
+	defer resp.Body.Close()
+	body, err := io.ReadAll(resp.Body)
+	if err != nil {
+		ppfmt.Warningf(pp.EmojiError,
+			"Failed to read HTTP(S) response from the %s endpoint of Healthchecks: %v",
+			endpointDescription, err)
+		return false
+	}
+
+	bodyAsString := strings.TrimSpace(string(body))
+	if resp.StatusCode != http.StatusOK || bodyAsString != "OK" {
+		ppfmt.Warningf(pp.EmojiError,
+			"Failed to ping the %s endpoint of Healthchecks; got response code: %d %s",
+			endpointDescription, resp.StatusCode, bodyAsString,
+		)
+		return false
 	}
 
-	ppfmt.Warningf(
-		pp.EmojiError,
-		"Failed to send HTTP(S) request to the %s endpoint of Healthchecks in %d time(s)",
-		endpointDescription, h.MaxRetries)
-	return false
+	ppfmt.Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", endpointDescription)
+	return true
 }
 
 // Success pings the root endpoint.


Test patch:
diff --git a/internal/config/env_test.go b/internal/config/env_test.go
index 2af1cc0..cad4acb 100644
--- a/internal/config/env_test.go
+++ b/internal/config/env_test.go
@@ -790,9 +790,8 @@ func TestReadHealthchecksURL(t *testing.T) {
 			true, "https://hi.org/1234",
 			nil,
 			&monitor.Healthchecks{
-				BaseURL:    urlMustParse(t, "https://hi.org/1234"),
-				Timeout:    monitor.HealthchecksDefaultTimeout,
-				MaxRetries: monitor.HealthchecksDefaultMaxRetries,
+				BaseURL: urlMustParse(t, "https://hi.org/1234"),
+				Timeout: monitor.HealthchecksDefaultTimeout,
 			},
 			true,
 			nil,
@@ -801,9 +800,8 @@ func TestReadHealthchecksURL(t *testing.T) {
 			true, "https://me:pass@hi.org/1234",
 			nil,
 			&monitor.Healthchecks{
-				BaseURL:    urlMustParse(t, "https://me:pass@hi.org/1234"),
-				Timeout:    monitor.HealthchecksDefaultTimeout,
-				MaxRetries: monitor.HealthchecksDefaultMaxRetries,
+				BaseURL: urlMustParse(t, "https://me:pass@hi.org/1234"),
+				Timeout: monitor.HealthchecksDefaultTimeout,
 			},
 			true,
 			nil,
@@ -812,9 +810,8 @@ func TestReadHealthchecksURL(t *testing.T) {
 			true, "https://hi.org/1234#fragment",
 			nil,
 			&monitor.Healthchecks{
-				BaseURL:    urlMustParse(t, "https://hi.org/1234#fragment"),
-				Timeout:    monitor.HealthchecksDefaultTimeout,
-				MaxRetries: monitor.HealthchecksDefaultMaxRetries,
+				BaseURL: urlMustParse(t, "https://hi.org/1234#fragment"),
+				Timeout: monitor.HealthchecksDefaultTimeout,
 			},
 			true,
 			nil,
@@ -823,9 +820,8 @@ func TestReadHealthchecksURL(t *testing.T) {
 			true, "https://hi.org/1234?hello=123",
 			nil,
 			&monitor.Healthchecks{
-				BaseURL:    urlMustParse(t, "https://hi.org/1234?hello=123"),
-				Timeout:    monitor.HealthchecksDefaultTimeout,
-				MaxRetries: monitor.HealthchecksDefaultMaxRetries,
+				BaseURL: urlMustParse(t, "https://hi.org/1234?hello=123"),
+				Timeout: monitor.HealthchecksDefaultTimeout,
 			},
 			true,
 			nil,
diff --git a/internal/monitor/healthchecks_test.go b/internal/monitor/healthchecks_test.go
index 54ac803..4f8657f 100644
--- a/internal/monitor/healthchecks_test.go
+++ b/internal/monitor/healthchecks_test.go
@@ -16,31 +16,6 @@ import (
 	"github.com/favonia/cloudflare-ddns/internal/pp"
 )
 
-func TestSetHealthchecksMaxRetries(t *testing.T) {
-	t.Parallel()
-
-	m := &monitor.Healthchecks{} //nolint:exhaustruct
-
-	monitor.SetHealthchecksMaxRetries(42)(m)
-
-	require.Equal(t, &monitor.Healthchecks{MaxRetries: 42}, m) //nolint:exhaustruct
-}
-
-func TestSetHealthchecksMaxRetriesPanic(t *testing.T) {
-	t.Parallel()
-
-	require.Panics(t,
-		func() {
-			monitor.SetHealthchecksMaxRetries(0)
-		},
-	)
-	require.Panics(t,
-		func() {
-			monitor.SetHealthchecksMaxRetries(-1)
-		},
-	)
-}
-
 func TestNewHealthchecks(t *testing.T) {
 	t.Parallel()
 
@@ -50,11 +25,10 @@ func TestNewHealthchecks(t *testing.T) {
 
 	mockCtrl := gomock.NewController(t)
 	mockPP := mocks.NewMockPP(mockCtrl)
-	m, ok := monitor.NewHealthchecks(mockPP, rawURL, monitor.SetHealthchecksMaxRetries(100))
+	m, ok := monitor.NewHealthchecks(mockPP, rawURL)
 	require.Equal(t, &monitor.Healthchecks{
-		BaseURL:    parsedURL,
-		Timeout:    monitor.HealthchecksDefaultTimeout,
-		MaxRetries: 100,
+		BaseURL: parsedURL,
+		Timeout: monitor.HealthchecksDefaultTimeout,
 	}, m)
 	require.True(t, ok)
 }
@@ -65,8 +39,8 @@ func TestNewHealthchecksFail1(t *testing.T) {
 	mockCtrl := gomock.NewController(t)
 	mockPP := mocks.NewMockPP(mockCtrl)
 	gomock.InOrder(
-		mockPP.EXPECT().Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL.`),
-		mockPP.EXPECT().Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc".`), //nolint:lll
+		mockPP.EXPECT().Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL`),
+		mockPP.EXPECT().Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc"`), //nolint:lll
 	)
 	_, ok := monitor.NewHealthchecks(mockPP, "this is not a valid URL")
 	require.False(t, ok)
@@ -78,8 +52,8 @@ func TestNewHealthchecksFail2(t *testing.T) {
 	mockCtrl := gomock.NewController(t)
 	mockPP := mocks.NewMockPP(mockCtrl)
 	gomock.InOrder(
-		mockPP.EXPECT().Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL.`),
-		mockPP.EXPECT().Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc".`), //nolint:lll
+		mockPP.EXPECT().Errorf(pp.EmojiUserError, `The Healthchecks URL (redacted) does not look like a valid URL`),
+		mockPP.EXPECT().Errorf(pp.EmojiUserError, `A valid example is "https://hc-ping.com/01234567-0123-0123-0123-0123456789abc"`), //nolint:lll
 	)
 	_, ok := monitor.NewHealthchecks(mockPP, "ftp://example.org")
 	require.False(t, ok)
@@ -124,6 +98,7 @@ func TestEndPoints(t *testing.T) {
 		url           string
 		message       string
 		actions       []action
+		defaultAction action
 		pinged        bool
 		ok            bool
 		prepareMockPP func(*mocks.MockPP)
@@ -134,14 +109,11 @@ func TestEndPoints(t *testing.T) {
 			},
 			"/", "hello",
 			[]action{ActionAbort, ActionAbort, ActionOk},
+			ActionAbort,
 			true, true,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `default (root)`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `default (root)`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
 					m.EXPECT().Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", `default (root)`), //nolint:lll
 				)
 			},
@@ -152,14 +124,11 @@ func TestEndPoints(t *testing.T) {
 			},
 			"/", "aloha",
 			[]action{ActionAbort, ActionAbort, ActionNotOk},
+			ActionAbort,
 			false, false,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `default (root)`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `default (root)`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
 					m.EXPECT().Warningf(pp.EmojiError, "Failed to ping the %s endpoint of Healthchecks; got response code: %d %s", `default (root)`, 400, "invalid url format"), //nolint:lll
 				)
 			},
@@ -169,18 +138,13 @@ func TestEndPoints(t *testing.T) {
 				return m.Success(context.Background(), ppfmt, "stop now")
 			},
 			"/", "stop now",
-			[]action{ActionAbort, ActionAbort, ActionAbort},
+			nil,
+			ActionAbort,
 			false, false,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
 					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `default (root)`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `default (root)`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `default (root)`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks in %d time(s)", `default (root)`, 3), //nolint:lll
 				)
 			},
 		},
@@ -190,14 +154,11 @@ func TestEndPoints(t *testing.T) {
 			},
 			"/start", "starting now!",
 			[]action{ActionAbort, ActionAbort, ActionOk},
+			ActionAbort,
 			true, true,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/start"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/start"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
 					m.EXPECT().Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", `"/start"`), //nolint:lll
 				)
 			},
@@ -208,14 +169,11 @@ func TestEndPoints(t *testing.T) {
 			},
 			"/fail", "something's wrong",
 			[]action{ActionAbort, ActionAbort, ActionOk},
+			ActionAbort,
 			true, true,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/fail"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/fail"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
 					m.EXPECT().Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", `"/fail"`), //nolint:lll
 				)
 			},
@@ -226,14 +184,11 @@ func TestEndPoints(t *testing.T) {
 			},
 			"/log", "message",
 			[]action{ActionAbort, ActionAbort, ActionOk},
+			ActionAbort,
 			true, true,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/log"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/log"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
 					m.EXPECT().Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", `"/log"`), //nolint:lll
 				)
 			},
@@ -244,14 +199,11 @@ func TestEndPoints(t *testing.T) {
 			},
 			"/0", "bye!",
 			[]action{ActionAbort, ActionAbort, ActionOk},
+			ActionAbort,
 			true, true,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/0"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/0"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
 					m.EXPECT().Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", `"/0"`),
 				)
 			},
@@ -262,14 +214,11 @@ func TestEndPoints(t *testing.T) {
 			},
 			"/1", "did exit(1)",
 			[]action{ActionAbort, ActionAbort, ActionOk},
+			ActionAbort,
 			true, true,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
 					m.EXPECT().Warningf(pp.EmojiUserWarning, "The Healthchecks URL (redacted) uses HTTP; please consider using HTTPS"),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/1"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
-					m.EXPECT().Warningf(pp.EmojiError, "Failed to send HTTP(S) request to the %s endpoint of Healthchecks: %v", `"/1"`, gomock.Any()), //nolint:lll
-					m.EXPECT().Infof(pp.EmojiRepeatOnce, "Trying again . . ."),
 					m.EXPECT().Infof(pp.EmojiNotification, "Successfully pinged the %s endpoint of Healthchecks", `"/1"`),
 				)
 			},
@@ -279,7 +228,7 @@ func TestEndPoints(t *testing.T) {
 				return m.ExitStatus(context.Background(), ppfmt, -1, "feeling negative")
 			},
 			"", "feeling negative",
-			nil,
+			nil, ActionAbort,
 			false, false,
 			func(m *mocks.MockPP) {
 				gomock.InOrder(
@@ -309,8 +258,11 @@ func TestEndPoints(t *testing.T) {
 				require.Equal(t, tc.message, string(reqBody))
 
 				visited++
-				require.LessOrEqual(t, visited, len(tc.actions))
-				switch tc.actions[visited-1] {
+				action := tc.defaultAction
+				if visited <= len(tc.actions) {
+					action = tc.actions[visited-1]
+				}
+				switch action {
 				case ActionOk:
 					pinged = true
 					_, err := io.WriteString(w, "OK")
@@ -328,7 +280,7 @@ func TestEndPoints(t *testing.T) {
 				}
 			}))
 
-			m, ok := monitor.NewHealthchecks(mockPP, server.URL, monitor.SetHealthchecksMaxRetries(3))
+			m, ok := monitor.NewHealthchecks(mockPP, server.URL)
 			require.True(t, ok)
 			ok = tc.endpoint(mockPP, m)
 			require.Equal(t, tc.ok, ok)