Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaime Martinez <jmartinez@gitlab.com>2020-07-15 10:06:12 +0300
committerJaime Martinez <jmartinez@gitlab.com>2020-07-24 07:49:29 +0300
commit11eaa4f759a746ee621f85362bae0512cb96497a (patch)
treef29a317a1d395faaef86762f7df2f7962bbac22d
parent1544f88bec36413b0775391a90e31ee8427a98ac (diff)
Add simple polling to the GitLab client
-rw-r--r--internal/source/gitlab/client/client_poll.go34
-rw-r--r--internal/source/gitlab/client/client_poll_test.go94
2 files changed, 128 insertions, 0 deletions
diff --git a/internal/source/gitlab/client/client_poll.go b/internal/source/gitlab/client/client_poll.go
new file mode 100644
index 00000000..bdbfb345
--- /dev/null
+++ b/internal/source/gitlab/client/client_poll.go
@@ -0,0 +1,34 @@
+package client
+
+import (
+ "fmt"
+ "time"
+)
+
+const (
+ // DefaultPollingMaxRetries to be used by Poll
+ DefaultPollingMaxRetries = 30
+ // DefaultPollingInterval to be used by Poll
+ DefaultPollingInterval = 10 * time.Second
+)
+
+// Poll tries to call the /internal/pages/status API endpoint for
+// `retries` every `interval`.
+// TODO: should we consider using an exponential back-off approach?
+// https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples
+func (gc *Client) Poll(retries int, interval time.Duration, errCh chan error) {
+ defer close(errCh)
+
+ var err error
+ for i := 0; i <= retries; i++ {
+ err = gc.Status()
+ if err == nil {
+ // return as soon as we connect to the API
+ errCh <- nil
+ }
+
+ time.Sleep(interval)
+ }
+
+ errCh <- fmt.Errorf("polling failed after %d tries every %fs: %w", retries, interval.Seconds(), err)
+}
diff --git a/internal/source/gitlab/client/client_poll_test.go b/internal/source/gitlab/client/client_poll_test.go
new file mode 100644
index 00000000..59da32c5
--- /dev/null
+++ b/internal/source/gitlab/client/client_poll_test.go
@@ -0,0 +1,94 @@
+package client
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestClient_Poll(t *testing.T) {
+ tests := []struct {
+ name string
+ retries int
+ interval time.Duration
+ timeout time.Duration
+ status int
+ wantErr bool
+ }{
+ {
+ name: "success_with_no_retry",
+ retries: 0,
+ interval: 5 * time.Millisecond,
+ timeout: 5 * time.Millisecond,
+ status: http.StatusOK,
+ wantErr: false,
+ },
+ {
+ name: "success_after_N_retries",
+ retries: 3,
+ interval: 5 * time.Millisecond,
+ timeout: 20 * time.Millisecond,
+ status: http.StatusOK,
+ wantErr: false,
+ },
+ {
+ name: "fail_with_no_retries",
+ retries: 0,
+ interval: 5 * time.Millisecond,
+ timeout: 100 * time.Millisecond,
+ status: http.StatusUnauthorized,
+ wantErr: true,
+ },
+ {
+ name: "fail_after_N_retries",
+ retries: 3,
+ interval: 5 * time.Millisecond,
+ timeout: 100 * time.Millisecond,
+ status: http.StatusUnauthorized,
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ var counter int
+ mux := http.NewServeMux()
+ mux.HandleFunc("/api/v4/internal/pages/status", func(w http.ResponseWriter, r *http.Request) {
+ if counter < tt.retries {
+ counter++
+ // fail on purpose until we reach the max retry
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ w.WriteHeader(tt.status)
+ })
+
+ server := httptest.NewServer(mux)
+ defer server.Close()
+
+ client := defaultClient(t, server.URL)
+ errCh := make(chan error)
+
+ go client.Poll(tt.retries, tt.interval, errCh)
+
+ // go func() {
+ select {
+ case err := <-errCh:
+ if tt.wantErr {
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "polling failed after")
+ require.Contains(t, err.Error(), ConnectionErrorMsg)
+ return
+ }
+ require.NoError(t, err)
+ case <-time.After(tt.timeout):
+ t.Logf("%s timed out", tt.name)
+ t.FailNow()
+ }
+ // }()
+ })
+ }
+}