1 package reaper
2
3 import (
4 "maps"
5 "os"
6 "slices"
7 "testing"
8 "time"
9
10 "github.com/cybertec-postgresql/pgwatch/v6/internal/metrics"
11 "github.com/stretchr/testify/assert"
12 )
13
14 func TestGetGoPsutilCPU(t *testing.T) {
15 a := assert.New(t)
16
17
18 time.Sleep(100 * time.Millisecond)
19
20
21 result, err := GetGoPsutilCPU(time.Second)
22 a.NoError(err)
23 a.NotEmpty(result)
24
25
26 expectedKeys := []string{metrics.EpochColumnName, "cpu_utilization", "load_1m_norm", "load_1m", "load_5m_norm", "load_5m", "user", "system", "idle", "iowait", "irqs", "other"}
27 resultKeys := slices.Collect(maps.Keys(result[0]))
28 a.ElementsMatch(resultKeys, expectedKeys)
29
30
31 cpuUtilization := result[0]["cpu_utilization"].(float64)
32 a.GreaterOrEqual(cpuUtilization, 0.0)
33 a.LessOrEqual(cpuUtilization, 100.0)
34 }
35
36 func TestGetGoPsutilMem(t *testing.T) {
37 a := assert.New(t)
38
39
40 result, err := GetGoPsutilMem()
41 a.NoError(err)
42 a.NotEmpty(result)
43
44
45 expectedKeys := []string{metrics.EpochColumnName, "total", "used", "free", "buff_cache", "available", "percent", "swap_total", "swap_used", "swap_free", "swap_percent"}
46 resultKeys := slices.Collect(maps.Keys(result[0]))
47 a.ElementsMatch(resultKeys, expectedKeys)
48 }
49
50 func TestGetGoPsutilDiskTotals(t *testing.T) {
51 a := assert.New(t)
52
53
54 result, err := GetGoPsutilDiskTotals()
55 if err != nil {
56 t.Skip("skipping test; disk.IOCounters() failed")
57 }
58 a.NotEmpty(result)
59
60
61 expectedKeys := []string{metrics.EpochColumnName, "read_bytes", "write_bytes", "read_count", "write_count"}
62 resultKeys := slices.Collect(maps.Keys(result[0]))
63 a.ElementsMatch(resultKeys, expectedKeys)
64 }
65
66 func TestGetLoadAvgLocal(t *testing.T) {
67 a := assert.New(t)
68
69
70 result, err := GetLoadAvgLocal()
71 a.NoError(err)
72 a.NotEmpty(result)
73
74
75 expectedKeys := []string{metrics.EpochColumnName, "load_1min", "load_5min", "load_15min"}
76 resultKeys := slices.Collect(maps.Keys(result[0]))
77 a.ElementsMatch(resultKeys, expectedKeys)
78 }
79
80 func TestGetPathUnderlyingDeviceID(t *testing.T) {
81 a := assert.New(t)
82 tmpDir := t.TempDir()
83 createFile := func(name string) string {
84 f, err := os.CreateTemp(tmpDir, name)
85 a.NoError(err)
86 defer f.Close()
87 return f.Name()
88 }
89
90 file1Path := createFile("file1")
91 devID1, err := GetPathUnderlyingDeviceID(file1Path)
92 a.NoError(err)
93
94 file2Path := createFile("file2")
95 devID2, err := GetPathUnderlyingDeviceID(file2Path)
96 a.NoError(err)
97 a.Equal(devID1, devID2)
98 }
99
100 func TestGetPathUnderlyingDeviceID_NotFound(t *testing.T) {
101 _, err := GetPathUnderlyingDeviceID("/this/path/should/not/exist/nofile")
102 assert.Error(t, err)
103 }
104
105 func TestGetGoPsutilDiskPG_Basic(t *testing.T) {
106 a := assert.New(t)
107 tmpDir := t.TempDir()
108
109 a.True(CheckFolderExistsAndReadable(tmpDir))
110 a.False(CheckFolderExistsAndReadable(""))
111
112 pgDirs := metrics.Measurements{
113 {"name": "data_directory", "path": tmpDir},
114 }
115 result, err := GetGoPsutilDiskPG(pgDirs)
116 a.NoError(err)
117 a.Len(result, 1)
118 a.Equal("data_directory", result[0]["tag_dir_or_tablespace"])
119 a.Equal(tmpDir, result[0]["tag_path"])
120
121 expectedKeys := []string{metrics.EpochColumnName, "tag_dir_or_tablespace", "tag_path", "total", "used", "free", "percent"}
122 resultKeys := slices.Collect(maps.Keys(result[0]))
123 a.ElementsMatch(expectedKeys, resultKeys)
124 }
125
126 func TestGetGoPsutilDiskPG_SameDeviceCachedUsage(t *testing.T) {
127 a := assert.New(t)
128 tmpDir := t.TempDir()
129
130
131 pgDirs := metrics.Measurements{
132 {"name": "data_directory", "path": tmpDir},
133 {"name": "pg_wal", "path": tmpDir},
134 }
135 result, err := GetGoPsutilDiskPG(pgDirs)
136 a.NoError(err)
137 a.Len(result, 2)
138 a.Equal("data_directory", result[0]["tag_dir_or_tablespace"])
139 a.Equal("pg_wal", result[1]["tag_dir_or_tablespace"])
140
141 a.Equal(result[0]["total"], result[1]["total"])
142 a.Equal(result[0]["used"], result[1]["used"])
143 }
144
145 func TestGetGoPsutilDiskPG_NonExistentPathSkipped(t *testing.T) {
146 a := assert.New(t)
147 tmpDir := t.TempDir()
148
149 pgDirs := metrics.Measurements{
150 {"name": "log_directory", "path": "/this/path/does/not/exist"},
151 {"name": "data_directory", "path": tmpDir},
152 }
153 result, err := GetGoPsutilDiskPG(pgDirs)
154 a.NoError(err)
155 a.Len(result, 1)
156 a.Equal("data_directory", result[0]["tag_dir_or_tablespace"])
157 }
158
159 func TestGetGoPsutilDiskPG_Empty(t *testing.T) {
160 result, err := GetGoPsutilDiskPG(metrics.Measurements{})
161 assert.NoError(t, err)
162 assert.Empty(t, result)
163 }
164