v2.31.1 f37fe67

traffic_test.go RawHistoryFolder

1package cli
2
3import (
4	"bytes"
5	"context"
6	"encoding/json"
7	"errors"
8	"net/http"
9	"net/http/httptest"
10	"testing"
11
12	"github.com/stretchr/testify/assert"
13	"github.com/stretchr/testify/require"
14
15	"github.com/bnema/gordon/internal/adapters/dto"
16	"github.com/bnema/gordon/internal/adapters/in/cli/remote"
17	"github.com/bnema/gordon/internal/domain"
18)
19
20func TestTrafficCommandExists(t *testing.T) {
21	cmd := NewRootCmd()
22	traffic, _, err := cmd.Find([]string{"traffic"})
23	require.NoError(t, err)
24	require.NotNil(t, traffic)
25	assert.Equal(t, "traffic", traffic.Name())
26
27	status, _, err := cmd.Find([]string{"traffic", "status"})
28	require.NoError(t, err)
29	require.NotNil(t, status)
30	assert.Equal(t, "status", status.Name())
31}
32
33func TestTrafficStatusRejectsArgs(t *testing.T) {
34	cmd := newTrafficStatusCmd()
35	require.Error(t, cmd.Args(cmd, []string{"extra"}))
36}
37
38func TestTrafficStatusHumanOutput(t *testing.T) {
39	status := &dto.TrafficStatusResponse{
40		LastReloadStatus: "ok",
41		EntryPoints: []dto.TrafficEntryPointStatus{{
42			Name: "postgres", Address: "127.0.0.1:5432", Protocol: domain.EntryPointProtocolTCP,
43			Active: true, ActiveTCPConnections: 1, TotalAccepted: 2, BytesIn: 10, BytesOut: 20,
44			SmartTCP: dto.SmartTCPCounters{HTTPAccepted: 1, PROXYRefused: 1},
45		}},
46		Routers: []dto.TrafficRouterStatus{{
47			Name: "pg-router", EntryPoint: "postgres", Protocol: domain.RouterProtocolTCP,
48			Service: "network_service:postgres:db", Active: true,
49		}},
50		Services: []dto.TrafficServiceStatus{{
51			Name: "network_service:postgres:db", Active: true,
52			Backends: []dto.TrafficBackendStatus{{Name: "postgres:db", Host: "127.0.0.1", Port: 5432, Protocol: domain.NetworkProtocolTCP, Active: true}},
53		}},
54		Counters: dto.TrafficCounters{ActiveTCPConnections: 1, TotalAccepted: 2, BytesIn: 10, BytesOut: 20, SmartTCP: dto.SmartTCPCounters{HTTPAccepted: 1, PROXYRefused: 1}},
55	}
56	var buf bytes.Buffer
57	require.NoError(t, renderTrafficStatus(&buf, status, false))
58	output := buf.String()
59	assert.Contains(t, output, "Traffic Status")
60	assert.Contains(t, output, "postgres")
61	assert.Contains(t, output, "127.0.0.1:5432")
62	assert.Contains(t, output, "pg-router")
63	assert.Contains(t, output, "network_service:postgres:db")
64	assert.Contains(t, output, "tcp://127.0.0.1:5432")
65	assert.Contains(t, output, "accepted=2")
66	assert.Contains(t, output, "smart_tcp")
67	assert.Contains(t, output, "http_accepted=1")
68	assert.Contains(t, output, "proxy_refused=1")
69}
70
71func TestTrafficStatusJSONOutput(t *testing.T) {
72	status := &dto.TrafficStatusResponse{LastReloadStatus: "ok", Counters: dto.TrafficCounters{ActiveUDPSessions: 3, SmartTCP: dto.SmartTCPCounters{SniffTimeout: 1}}}
73	var buf bytes.Buffer
74	require.NoError(t, renderTrafficStatus(&buf, status, true))
75	var got dto.TrafficStatusResponse
76	require.NoError(t, json.Unmarshal(buf.Bytes(), &got))
77	assert.Equal(t, "ok", got.LastReloadStatus)
78	assert.Equal(t, int64(3), got.Counters.ActiveUDPSessions)
79	assert.Equal(t, int64(1), got.Counters.SmartTCP.SniffTimeout)
80}
81
82func TestRunTrafficStatusUsesControlPlane(t *testing.T) {
83	status := &dto.TrafficStatusResponse{LastReloadStatus: "ok"}
84	cp := &trafficStatusPlane{status: status}
85
86	var buf bytes.Buffer
87	require.NoError(t, runTrafficStatus(context.Background(), cp, &buf, true))
88
89	assert.True(t, cp.called)
90	assert.Contains(t, buf.String(), `"last_reload_status": "ok"`)
91}
92
93func TestRemoteTrafficStatusControlPlaneStillRenders(t *testing.T) {
94	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
95		require.Equal(t, "/admin/traffic/status", r.URL.Path)
96		require.Equal(t, http.MethodGet, r.Method)
97		_, err := w.Write([]byte(`{"last_reload_status":"ok","counters":{"active_udp_sessions":3}}`))
98		require.NoError(t, err)
99	}))
100	defer srv.Close()
101
102	cp := NewRemoteControlPlane(remote.NewClient(srv.URL))
103	var buf bytes.Buffer
104	require.NoError(t, runTrafficStatus(context.Background(), cp, &buf, false))
105
106	output := buf.String()
107	assert.Contains(t, output, "Traffic Status")
108	assert.Contains(t, output, "Reload")
109	assert.Contains(t, output, "ok")
110	assert.Contains(t, output, "udp=3")
111}
112
113func TestLocalTrafficStatusReturnsActionableDaemonGuidance(t *testing.T) {
114	_, err := (&localControlPlane{}).GetTrafficStatus(context.Background())
115	require.Error(t, err)
116	assert.True(t, errors.Is(err, domain.ErrTrafficStatusUnavailable))
117	assert.Contains(t, err.Error(), "in-process CLI control plane")
118	assert.Contains(t, err.Error(), "running Gordon daemon")
119	assert.Contains(t, err.Error(), "--remote")
120	assert.Contains(t, err.Error(), "GORDON_REMOTE")
121}
122
123type trafficStatusPlane struct {
124	ControlPlane
125	status *dto.TrafficStatusResponse
126	called bool
127}
128
129func (p *trafficStatusPlane) GetTrafficStatus(context.Context) (*dto.TrafficStatusResponse, error) {
130	p.called = true
131	return p.status, nil
132}

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 8

Tags 106

↑↓ moveenter openesc close