v2.13.0 7748089

client_test.go RawHistoryFolder

1package remote
2
3import (
4	"context"
5	"net/http"
6	"net/http/httptest"
7	"sync/atomic"
8	"testing"
9	"time"
10
11	"github.com/stretchr/testify/assert"
12	"github.com/stretchr/testify/require"
13)
14
15func withFastRetry(t *testing.T) {
16	t.Helper()
17	prevAttempts := retryMaxAttempts
18	prevDelay := retryBaseDelay
19	retryMaxAttempts = 3
20	retryBaseDelay = 10 * time.Millisecond
21	t.Cleanup(func() {
22		retryMaxAttempts = prevAttempts
23		retryBaseDelay = prevDelay
24	})
25}
26
27func TestClientRestartRetriesOn5xx(t *testing.T) {
28	withFastRetry(t)
29
30	var attempts int32
31	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
32		require.Equal(t, "/admin/restart/test.example.com", r.URL.Path)
33		require.Equal(t, http.MethodPost, r.Method)
34		current := atomic.AddInt32(&attempts, 1)
35		if current < 3 {
36			w.WriteHeader(http.StatusServiceUnavailable)
37			_, _ = w.Write([]byte(`{"error":"temporary outage"}`))
38			return
39		}
40		w.Header().Set("Content-Type", "application/json")
41		_, _ = w.Write([]byte(`{"status":"restarted","domain":"test.example.com"}`))
42	}))
43	defer srv.Close()
44
45	client := NewClient(srv.URL)
46	result, err := client.Restart(context.Background(), "test.example.com", false)
47	require.NoError(t, err)
48	require.NotNil(t, result)
49	assert.Equal(t, "test.example.com", result.Domain)
50	assert.EqualValues(t, 3, atomic.LoadInt32(&attempts))
51}
52
53func TestClientReloadRetriesOn5xx(t *testing.T) {
54	withFastRetry(t)
55
56	var attempts int32
57	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
58		require.Equal(t, "/admin/reload", r.URL.Path)
59		require.Equal(t, http.MethodPost, r.Method)
60		current := atomic.AddInt32(&attempts, 1)
61		if current < 2 {
62			w.WriteHeader(http.StatusBadGateway)
63			_, _ = w.Write([]byte(`upstream down`))
64			return
65		}
66		w.Header().Set("Content-Type", "application/json")
67		_, _ = w.Write([]byte(`{"status":"reloaded"}`))
68	}))
69	defer srv.Close()
70
71	client := NewClient(srv.URL)
72	err := client.Reload(context.Background())
73	require.NoError(t, err)
74	assert.EqualValues(t, 2, atomic.LoadInt32(&attempts))
75}
76
77func TestClientDeployReturnsErrorAfterRetryExhaustion(t *testing.T) {
78	withFastRetry(t)
79
80	var attempts int32
81	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
82		require.Equal(t, "/admin/deploy/test.example.com", r.URL.Path)
83		require.Equal(t, http.MethodPost, r.Method)
84		atomic.AddInt32(&attempts, 1)
85		w.WriteHeader(http.StatusBadGateway)
86		_, _ = w.Write([]byte(`{"error":"upstream unavailable"}`))
87	}))
88	defer srv.Close()
89
90	client := NewClient(srv.URL)
91	_, err := client.Deploy(context.Background(), "test.example.com")
92	require.Error(t, err)
93	assert.Contains(t, err.Error(), "502 Bad Gateway: upstream unavailable")
94	assert.EqualValues(t, retryMaxAttempts, atomic.LoadInt32(&attempts))
95}
96
97func TestClientWithInsecureTLS_AllowsSelfSignedCertificate(t *testing.T) {
98	srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
99		require.Equal(t, "/admin/status", r.URL.Path)
100		w.Header().Set("Content-Type", "application/json")
101		_, _ = w.Write([]byte(`{"routes":0,"registry_domain":"","registry_port":0,"server_port":0,"auto_route":false,"network_isolation":false,"container_status":{}}`))
102	}))
103	defer srv.Close()
104
105	_, err := NewClient(srv.URL).GetStatus(context.Background())
106	require.Error(t, err)
107
108	_, err = NewClient(srv.URL, WithInsecureTLS(true)).GetStatus(context.Background())
109	require.NoError(t, err)
110}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close