mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-25 05:49:06 +01:00
177 lines
5.3 KiB
Go
177 lines
5.3 KiB
Go
package status
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
protobuf "google.golang.org/protobuf/proto"
|
|
|
|
"github.com/netbirdio/netbird/client/anonymize"
|
|
"github.com/netbirdio/netbird/client/proto"
|
|
)
|
|
|
|
func TestPeersTable(t *testing.T) {
|
|
overview := OutputOverview{Peers: PeersStateOutput{
|
|
Total: 2,
|
|
Connected: 1,
|
|
Details: []PeerStateDetailOutput{
|
|
{
|
|
FQDN: "web-01.netbird.cloud",
|
|
IP: "100.64.0.12",
|
|
PubKey: "k3Vx9pQ2abcdefghijklmnopqrstuvwxyz0123456789=",
|
|
Status: "Connected",
|
|
ConnType: "P2P",
|
|
Latency: 12 * time.Millisecond,
|
|
TransferReceived: 1024,
|
|
TransferSent: 2048,
|
|
},
|
|
{
|
|
FQDN: "old-nas.netbird.cloud",
|
|
IP: "100.64.0.77",
|
|
Status: "Idle",
|
|
},
|
|
},
|
|
}}
|
|
|
|
lines := strings.Split(strings.TrimRight(overview.PeersTable(), "\n"), "\n")
|
|
require.Len(t, lines, 4, "title, header and one line per peer")
|
|
|
|
assert.Equal(t, "Peers (1/2 connected):", lines[0])
|
|
assert.Equal(t,
|
|
[]string{"NAME", "IP", "STATUS", "CONN", "LATENCY", "RX", "/", "TX"},
|
|
strings.Fields(lines[1]))
|
|
|
|
connected := strings.Fields(lines[2])
|
|
assert.Equal(t, "web-01", connected[0], "domain suffix must be dropped")
|
|
assert.Equal(t, "Connected", connected[2])
|
|
assert.Equal(t, "P2P", connected[3])
|
|
assert.Equal(t, "12ms", connected[4])
|
|
assert.NotContains(t, lines[2], "k3Vx9pQ2", "public key must not be shown")
|
|
assert.Contains(t, lines[2], "1.0 KiB / 2.0 KiB")
|
|
|
|
idle := strings.Fields(lines[3])
|
|
assert.Equal(t, []string{"old-nas", "100.64.0.77", "Idle", "-", "-", "0", "B", "/", "0", "B"}, idle,
|
|
"missing values render as dashes")
|
|
}
|
|
|
|
func TestPeersTable_NoPeers(t *testing.T) {
|
|
out := (&OutputOverview{}).PeersTable()
|
|
assert.True(t, strings.HasPrefix(out, "Peers (0/0 connected):\n"))
|
|
assert.Contains(t, out, "NAME")
|
|
}
|
|
|
|
func tableRows(t *testing.T, opts ConvertOptions) []string {
|
|
t.Helper()
|
|
|
|
opts.DaemonVersion = resp.GetDaemonVersion()
|
|
opts.DaemonStatus = ParseDaemonStatus(resp.GetStatus())
|
|
// The anonymizer rewrites slices in place, so work on a copy to keep the
|
|
// shared fixture intact for the other tests.
|
|
fullStatus := protobuf.Clone(resp.GetFullStatus()).(*proto.FullStatus)
|
|
overview := ConvertToStatusOutputOverview(fullStatus, opts)
|
|
out := overview.PeersTable()
|
|
|
|
lines := strings.Split(strings.TrimRight(out, "\n"), "\n")
|
|
require.GreaterOrEqual(t, len(lines), 2, "title and header are always present")
|
|
return lines
|
|
}
|
|
|
|
// The fixture holds peer-1 (connected, P2P) and peer-2 (connected, relayed).
|
|
func TestPeersTable_Filters(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
opts ConvertOptions
|
|
wantTitle string
|
|
wantPeers []string
|
|
}{
|
|
{
|
|
name: "no filter lists every peer sorted by IP",
|
|
wantTitle: "Peers (2/2 connected):",
|
|
wantPeers: []string{"peer-1", "peer-2"},
|
|
},
|
|
{
|
|
name: "connection type P2P",
|
|
opts: ConvertOptions{ConnectionTypeFilter: "P2P"},
|
|
wantTitle: "Peers (1/1 connected):",
|
|
wantPeers: []string{"peer-1"},
|
|
},
|
|
{
|
|
name: "connection type Relayed",
|
|
opts: ConvertOptions{ConnectionTypeFilter: "relayed"},
|
|
wantTitle: "Peers (1/1 connected):",
|
|
wantPeers: []string{"peer-2"},
|
|
},
|
|
{
|
|
name: "status with no match",
|
|
opts: ConvertOptions{StatusFilter: "idle"},
|
|
wantTitle: "Peers (0/0 connected):",
|
|
},
|
|
{
|
|
name: "name prefix",
|
|
opts: ConvertOptions{
|
|
PrefixNamesFilter: []string{"peer-2"},
|
|
PrefixNamesFilterMap: map[string]struct{}{"peer-2": {}},
|
|
},
|
|
wantTitle: "Peers (1/1 connected):",
|
|
wantPeers: []string{"peer-2"},
|
|
},
|
|
{
|
|
name: "IPv4",
|
|
opts: ConvertOptions{IPsFilter: map[string]struct{}{"192.168.178.101": {}}},
|
|
wantTitle: "Peers (1/1 connected):",
|
|
wantPeers: []string{"peer-1"},
|
|
},
|
|
{
|
|
name: "IPv6",
|
|
opts: ConvertOptions{IPsFilter: map[string]struct{}{"fd00::1": {}}},
|
|
wantTitle: "Peers (1/1 connected):",
|
|
wantPeers: []string{"peer-1"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
lines := tableRows(t, tt.opts)
|
|
|
|
assert.Equal(t, tt.wantTitle, lines[0])
|
|
rows := lines[2:]
|
|
require.Len(t, rows, len(tt.wantPeers), "one row per matching peer")
|
|
for i, name := range tt.wantPeers {
|
|
assert.True(t, strings.HasPrefix(rows[i], name+" "), "row %d should be %s, got %q", i, name, rows[i])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// The table shows whatever the anonymizer left in the overview, so it must
|
|
// carry the redacted names rather than the originals.
|
|
func TestPeersTable_Anonymized(t *testing.T) {
|
|
lines := tableRows(t, ConvertOptions{Anonymize: true, AnonymizeLevel: anonymize.LevelStrict})
|
|
|
|
for _, row := range lines[2:] {
|
|
assert.NotContains(t, row, "awesome-domain.com", "FQDN must be anonymized")
|
|
assert.NotContains(t, row, "peer-", "peer name must be anonymized")
|
|
}
|
|
}
|
|
|
|
func TestShortName(t *testing.T) {
|
|
assert.Equal(t, "web-01", shortName("web-01.netbird.cloud"))
|
|
assert.Equal(t, "web-01", shortName("web-01"))
|
|
assert.Equal(t, "-", shortName(""))
|
|
}
|
|
|
|
func TestTableLatency(t *testing.T) {
|
|
tests := map[time.Duration]string{
|
|
0: "-",
|
|
145939625 * time.Nanosecond: "146ms",
|
|
12 * time.Millisecond: "12ms",
|
|
420*time.Microsecond + 700: "421µs",
|
|
}
|
|
for in, want := range tests {
|
|
assert.Equal(t, want, tableLatency(PeerStateDetailOutput{Latency: in}), "latency %s", in)
|
|
}
|
|
}
|