467 lines
11 KiB
Go
467 lines
11 KiB
Go
|
package diagnostic_test
|
||
|
|
||
|
import (
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/cloudflare/cloudflared/diagnostic"
|
||
|
)
|
||
|
|
||
|
func TestParseMemoryInformationFromKV(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
mapper := func(field string) (uint64, error) {
|
||
|
value, err := strconv.ParseUint(field, 10, 64)
|
||
|
return value, err
|
||
|
}
|
||
|
|
||
|
linuxMapper := func(field string) (uint64, error) {
|
||
|
field = strings.TrimRight(field, " kB")
|
||
|
return strconv.ParseUint(field, 10, 64)
|
||
|
}
|
||
|
|
||
|
windowsMemoryOutput := `
|
||
|
|
||
|
FreeVirtualMemory : 5350472
|
||
|
TotalVirtualMemorySize : 8903424
|
||
|
|
||
|
|
||
|
`
|
||
|
macosMemoryOutput := `hw.memsize: 38654705664
|
||
|
hw.memsize_usable: 38009012224`
|
||
|
memoryOutputWithMissingKey := `hw.memsize: 38654705664`
|
||
|
|
||
|
linuxMemoryOutput := `MemTotal: 8028860 kB
|
||
|
MemFree: 731396 kB
|
||
|
MemAvailable: 4678844 kB
|
||
|
Buffers: 472632 kB
|
||
|
Cached: 3186492 kB
|
||
|
SwapCached: 4196 kB
|
||
|
Active: 3088988 kB
|
||
|
Inactive: 3468560 kB`
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
output string
|
||
|
memoryMaximumKey string
|
||
|
memoryAvailableKey string
|
||
|
expected *diagnostic.MemoryInformation
|
||
|
expectedErr bool
|
||
|
mapper func(string) (uint64, error)
|
||
|
}{
|
||
|
{
|
||
|
name: "parse linux memory values",
|
||
|
output: linuxMemoryOutput,
|
||
|
memoryMaximumKey: "MemTotal",
|
||
|
memoryAvailableKey: "MemAvailable",
|
||
|
expected: &diagnostic.MemoryInformation{
|
||
|
8028860,
|
||
|
8028860 - 4678844,
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
mapper: linuxMapper,
|
||
|
},
|
||
|
{
|
||
|
name: "parse memory values with missing key",
|
||
|
output: memoryOutputWithMissingKey,
|
||
|
memoryMaximumKey: "hw.memsize",
|
||
|
memoryAvailableKey: "hw.memsize_usable",
|
||
|
expected: nil,
|
||
|
expectedErr: true,
|
||
|
mapper: mapper,
|
||
|
},
|
||
|
{
|
||
|
name: "parse macos memory values",
|
||
|
output: macosMemoryOutput,
|
||
|
memoryMaximumKey: "hw.memsize",
|
||
|
memoryAvailableKey: "hw.memsize_usable",
|
||
|
expected: &diagnostic.MemoryInformation{
|
||
|
38654705664,
|
||
|
38654705664 - 38009012224,
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
mapper: mapper,
|
||
|
},
|
||
|
{
|
||
|
name: "parse windows memory values",
|
||
|
output: windowsMemoryOutput,
|
||
|
memoryMaximumKey: "TotalVirtualMemorySize",
|
||
|
memoryAvailableKey: "FreeVirtualMemory",
|
||
|
expected: &diagnostic.MemoryInformation{
|
||
|
8903424,
|
||
|
8903424 - 5350472,
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
mapper: mapper,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tCase := range tests {
|
||
|
t.Run(tCase.name, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
memoryInfo, err := diagnostic.ParseMemoryInformationFromKV(
|
||
|
tCase.output,
|
||
|
tCase.memoryMaximumKey,
|
||
|
tCase.memoryAvailableKey,
|
||
|
tCase.mapper,
|
||
|
)
|
||
|
|
||
|
if tCase.expectedErr {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
require.NoError(t, err)
|
||
|
assert.Equal(t, tCase.expected, memoryInfo)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParseUnameOutput(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
output string
|
||
|
os string
|
||
|
expected *diagnostic.OsInfo
|
||
|
expectedErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "darwin machine",
|
||
|
output: "Darwin APC 23.6.0 Darwin Kernel Version 99.6.0: Wed Jul 31 20:48:04 PDT 1997; root:xnu-66666.666.6.666.6~1/RELEASE_ARM64_T6666 arm64",
|
||
|
os: "darwin",
|
||
|
expected: &diagnostic.OsInfo{
|
||
|
Architecture: "arm64",
|
||
|
Name: "APC",
|
||
|
OsSystem: "Darwin",
|
||
|
OsRelease: "Darwin Kernel Version 99.6.0: Wed Jul 31 20:48:04 PDT 1997; root:xnu-66666.666.6.666.6~1/RELEASE_ARM64_T6666",
|
||
|
OsVersion: "23.6.0",
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
},
|
||
|
{
|
||
|
name: "linux machine",
|
||
|
output: "Linux dab00d565591 6.6.31-linuxkit #1 SMP Thu May 23 08:36:57 UTC 2024 aarch64 GNU/Linux",
|
||
|
os: "linux",
|
||
|
expected: &diagnostic.OsInfo{
|
||
|
Architecture: "aarch64",
|
||
|
Name: "dab00d565591",
|
||
|
OsSystem: "Linux",
|
||
|
OsRelease: "#1 SMP Thu May 23 08:36:57 UTC 2024",
|
||
|
OsVersion: "6.6.31-linuxkit",
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
},
|
||
|
{
|
||
|
name: "not enough fields",
|
||
|
output: "Linux ",
|
||
|
os: "linux",
|
||
|
expected: nil,
|
||
|
expectedErr: true,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tCase := range tests {
|
||
|
t.Run(tCase.name, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
memoryInfo, err := diagnostic.ParseUnameOutput(
|
||
|
tCase.output,
|
||
|
tCase.os,
|
||
|
)
|
||
|
|
||
|
if tCase.expectedErr {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
require.NoError(t, err)
|
||
|
assert.Equal(t, tCase.expected, memoryInfo)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParseFileDescriptorInformationFromKV(t *testing.T) {
|
||
|
const (
|
||
|
fileDescriptorMaximumKey = "kern.maxfiles"
|
||
|
fileDescriptorCurrentKey = "kern.num_files"
|
||
|
)
|
||
|
|
||
|
t.Parallel()
|
||
|
|
||
|
memoryOutput := `kern.maxfiles: 276480
|
||
|
kern.num_files: 11787`
|
||
|
memoryOutputWithMissingKey := `kern.maxfiles: 276480`
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
output string
|
||
|
expected *diagnostic.FileDescriptorInformation
|
||
|
expectedErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "parse memory values with missing key",
|
||
|
output: memoryOutputWithMissingKey,
|
||
|
expected: nil,
|
||
|
expectedErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "parse macos memory values",
|
||
|
output: memoryOutput,
|
||
|
expected: &diagnostic.FileDescriptorInformation{
|
||
|
276480,
|
||
|
11787,
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tCase := range tests {
|
||
|
t.Run(tCase.name, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
fdInfo, err := diagnostic.ParseFileDescriptorInformationFromKV(
|
||
|
tCase.output,
|
||
|
fileDescriptorMaximumKey,
|
||
|
fileDescriptorCurrentKey,
|
||
|
)
|
||
|
|
||
|
if tCase.expectedErr {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
require.NoError(t, err)
|
||
|
assert.Equal(t, tCase.expected, fdInfo)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParseSysctlFileDescriptorInformation(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
output string
|
||
|
expected *diagnostic.FileDescriptorInformation
|
||
|
expectedErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "expected output",
|
||
|
output: "111 0 1111111",
|
||
|
expected: &diagnostic.FileDescriptorInformation{
|
||
|
FileDescriptorMaximum: 1111111,
|
||
|
FileDescriptorCurrent: 111,
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
},
|
||
|
{
|
||
|
name: "not enough fields",
|
||
|
output: "111 111 ",
|
||
|
expected: nil,
|
||
|
expectedErr: true,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tCase := range tests {
|
||
|
t.Run(tCase.name, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
fdsInfo, err := diagnostic.ParseSysctlFileDescriptorInformation(
|
||
|
tCase.output,
|
||
|
)
|
||
|
|
||
|
if tCase.expectedErr {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
require.NoError(t, err)
|
||
|
assert.Equal(t, tCase.expected, fdsInfo)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParseWinOperatingSystemInfo(t *testing.T) {
|
||
|
const (
|
||
|
architecturePrefix = "OSArchitecture"
|
||
|
osSystemPrefix = "Caption"
|
||
|
osVersionPrefix = "Version"
|
||
|
osReleasePrefix = "BuildNumber"
|
||
|
namePrefix = "CSName"
|
||
|
)
|
||
|
|
||
|
t.Parallel()
|
||
|
|
||
|
windowsIncompleteOsInfo := `
|
||
|
OSArchitecture : ARM 64 bits
|
||
|
Caption : Microsoft Windows 11 Home
|
||
|
Morekeys : 121314
|
||
|
CSName : UTILIZA-QO859QP
|
||
|
`
|
||
|
windowsCompleteOsInfo := `
|
||
|
OSArchitecture : ARM 64 bits
|
||
|
Caption : Microsoft Windows 11 Home
|
||
|
Version : 10.0.22631
|
||
|
BuildNumber : 22631
|
||
|
Morekeys : 121314
|
||
|
CSName : UTILIZA-QO859QP
|
||
|
`
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
output string
|
||
|
expected *diagnostic.OsInfo
|
||
|
expectedErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "expected output",
|
||
|
output: windowsCompleteOsInfo,
|
||
|
expected: &diagnostic.OsInfo{
|
||
|
Architecture: "ARM 64 bits",
|
||
|
Name: "UTILIZA-QO859QP",
|
||
|
OsSystem: "Microsoft Windows 11 Home",
|
||
|
OsRelease: "22631",
|
||
|
OsVersion: "10.0.22631",
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
},
|
||
|
{
|
||
|
name: "missing keys",
|
||
|
output: windowsIncompleteOsInfo,
|
||
|
expected: nil,
|
||
|
expectedErr: true,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tCase := range tests {
|
||
|
t.Run(tCase.name, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
osInfo, err := diagnostic.ParseWinOperatingSystemInfo(
|
||
|
tCase.output,
|
||
|
architecturePrefix,
|
||
|
osSystemPrefix,
|
||
|
osVersionPrefix,
|
||
|
osReleasePrefix,
|
||
|
namePrefix,
|
||
|
)
|
||
|
|
||
|
if tCase.expectedErr {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
require.NoError(t, err)
|
||
|
assert.Equal(t, tCase.expected, osInfo)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestParseDiskVolumeInformationOutput(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
|
||
|
invalidUnixDiskVolumeInfo := `Filesystem Size Used Avail Use% Mounted on
|
||
|
overlay 59G 19G 38G 33% /
|
||
|
tmpfs 64M 0 64M 0% /dev
|
||
|
shm 64M 0 64M 0% /dev/shm
|
||
|
/run/host_mark/Users 461G 266G 195G 58% /tmp/cloudflared
|
||
|
/dev/vda1 59G 19G 38G 33% /etc/hosts
|
||
|
tmpfs 3.9G 0 3.9G 0% /sys/firmware
|
||
|
`
|
||
|
|
||
|
unixDiskVolumeInfo := `Filesystem Size Used Avail Use% Mounted on
|
||
|
overlay 61202244 18881444 39179476 33% /
|
||
|
tmpfs 65536 0 65536 0% /dev
|
||
|
shm 65536 0 65536 0% /dev/shm
|
||
|
/run/host_mark/Users 482797652 278648468 204149184 58% /tmp/cloudflared
|
||
|
/dev/vda1 61202244 18881444 39179476 33% /etc/hosts
|
||
|
tmpfs 4014428 0 4014428 0% /sys/firmware`
|
||
|
missingFields := ` DeviceID Size
|
||
|
-------- ----
|
||
|
C: size
|
||
|
E: 235563008
|
||
|
Z: 67754782720
|
||
|
`
|
||
|
invalidTypeField := ` DeviceID Size FreeSpace
|
||
|
-------- ---- ---------
|
||
|
C: size 31318736896
|
||
|
D:
|
||
|
E: 235563008 0
|
||
|
Z: 67754782720 31318732800
|
||
|
`
|
||
|
|
||
|
windowsDiskVolumeInfo := `
|
||
|
|
||
|
DeviceID Size FreeSpace
|
||
|
-------- ---- ---------
|
||
|
C: 67754782720 31318736896
|
||
|
E: 235563008 0
|
||
|
Z: 67754782720 31318732800`
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
output string
|
||
|
expected []*diagnostic.DiskVolumeInformation
|
||
|
skipLines int
|
||
|
expectedErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "invalid unix disk volume information (numbers have units)",
|
||
|
output: invalidUnixDiskVolumeInfo,
|
||
|
expected: []*diagnostic.DiskVolumeInformation{},
|
||
|
skipLines: 1,
|
||
|
expectedErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "unix disk volume information",
|
||
|
output: unixDiskVolumeInfo,
|
||
|
skipLines: 1,
|
||
|
expected: []*diagnostic.DiskVolumeInformation{
|
||
|
diagnostic.NewDiskVolumeInformation("overlay", 61202244, 18881444),
|
||
|
diagnostic.NewDiskVolumeInformation("tmpfs", 65536, 0),
|
||
|
diagnostic.NewDiskVolumeInformation("shm", 65536, 0),
|
||
|
diagnostic.NewDiskVolumeInformation("/run/host_mark/Users", 482797652, 278648468),
|
||
|
diagnostic.NewDiskVolumeInformation("/dev/vda1", 61202244, 18881444),
|
||
|
diagnostic.NewDiskVolumeInformation("tmpfs", 4014428, 0),
|
||
|
},
|
||
|
expectedErr: false,
|
||
|
},
|
||
|
{
|
||
|
name: "windows disk volume information",
|
||
|
output: windowsDiskVolumeInfo,
|
||
|
expected: []*diagnostic.DiskVolumeInformation{
|
||
|
diagnostic.NewDiskVolumeInformation("C:", 67754782720, 31318736896),
|
||
|
diagnostic.NewDiskVolumeInformation("E:", 235563008, 0),
|
||
|
diagnostic.NewDiskVolumeInformation("Z:", 67754782720, 31318732800),
|
||
|
},
|
||
|
skipLines: 4,
|
||
|
expectedErr: false,
|
||
|
},
|
||
|
{
|
||
|
name: "insuficient fields",
|
||
|
output: missingFields,
|
||
|
expected: nil,
|
||
|
skipLines: 2,
|
||
|
expectedErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "invalid field",
|
||
|
output: invalidTypeField,
|
||
|
expected: nil,
|
||
|
skipLines: 2,
|
||
|
expectedErr: true,
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tCase := range tests {
|
||
|
t.Run(tCase.name, func(t *testing.T) {
|
||
|
t.Parallel()
|
||
|
disks, err := diagnostic.ParseDiskVolumeInformationOutput(tCase.output, tCase.skipLines, 1)
|
||
|
|
||
|
if tCase.expectedErr {
|
||
|
assert.Error(t, err)
|
||
|
} else {
|
||
|
require.NoError(t, err)
|
||
|
assert.Equal(t, tCase.expected, disks)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|