master
go 282 lines 6.67 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package dovecot
4
5 import (
6 "context"
7 "errors"
8 "os"
9 "testing"
10
11 "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/collecttest"
12
13 "github.com/stretchr/testify/assert"
14 "github.com/stretchr/testify/require"
15 )
16
17 var (
18 dataConfigJSON, _ = os.ReadFile("testdata/config.json")
19 dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
20
21 dataExportGlobal, _ = os.ReadFile("testdata/export_global.txt")
22 )
23
24 func Test_testDataIsValid(t *testing.T) {
25 for name, data := range map[string][]byte{
26 "dataConfigJSON": dataConfigJSON,
27 "dataConfigYAML": dataConfigYAML,
28 "dataExportGlobal": dataExportGlobal,
29 } {
30 require.NotNil(t, data, name)
31 }
32 }
33
34 func TestCollector_ConfigurationSerialize(t *testing.T) {
35 collecttest.TestConfigurationSerialize(t, &Collector{}, dataConfigJSON, dataConfigYAML)
36 }
37
38 func TestCollector_Init(t *testing.T) {
39 tests := map[string]struct {
40 config Config
41 wantFail bool
42 }{
43 "success with default config": {
44 wantFail: false,
45 config: New().Config,
46 },
47 "fails if address not set": {
48 wantFail: true,
49 config: func() Config {
50 conf := New().Config
51 conf.Address = ""
52 return conf
53 }(),
54 },
55 }
56
57 for name, test := range tests {
58 t.Run(name, func(t *testing.T) {
59 collr := New()
60 collr.Config = test.config
61
62 if test.wantFail {
63 assert.Error(t, collr.Init(context.Background()))
64 } else {
65 assert.NoError(t, collr.Init(context.Background()))
66 }
67 })
68 }
69 }
70
71 func TestCollector_Cleanup(t *testing.T) {
72 tests := map[string]struct {
73 prepare func() *Collector
74 }{
75 "not initialized": {
76 prepare: func() *Collector {
77 return New()
78 },
79 },
80 "after check": {
81 prepare: func() *Collector {
82 collr := New()
83 collr.newConn = func(Config) dovecotConn { return prepareMockOk() }
84 _ = collr.Check(context.Background())
85 return collr
86 },
87 },
88 "after collect": {
89 prepare: func() *Collector {
90 collr := New()
91 collr.newConn = func(Config) dovecotConn { return prepareMockOk() }
92 _ = collr.Collect(context.Background())
93 return collr
94 },
95 },
96 }
97
98 for name, test := range tests {
99 t.Run(name, func(t *testing.T) {
100 collr := test.prepare()
101
102 assert.NotPanics(t, func() { collr.Cleanup(context.Background()) })
103 })
104 }
105 }
106
107 func TestCollector_Charts(t *testing.T) {
108 assert.NotNil(t, New().Charts())
109 }
110
111 func TestCollector_Check(t *testing.T) {
112 tests := map[string]struct {
113 prepareMock func() *mockDovecotConn
114 wantFail bool
115 }{
116 "success case": {
117 wantFail: false,
118 prepareMock: prepareMockOk,
119 },
120 "err on connect": {
121 wantFail: true,
122 prepareMock: prepareMockErrOnConnect,
123 },
124 "unexpected response": {
125 wantFail: true,
126 prepareMock: prepareMockUnexpectedResponse,
127 },
128 "empty response": {
129 wantFail: true,
130 prepareMock: prepareMockEmptyResponse,
131 },
132 }
133
134 for name, test := range tests {
135 t.Run(name, func(t *testing.T) {
136 collr := New()
137 mock := test.prepareMock()
138 collr.newConn = func(Config) dovecotConn { return mock }
139
140 if test.wantFail {
141 assert.Error(t, collr.Check(context.Background()))
142 } else {
143 assert.NoError(t, collr.Check(context.Background()))
144 }
145 })
146 }
147 }
148
149 func TestCollector_Collect(t *testing.T) {
150 tests := map[string]struct {
151 prepareMock func() *mockDovecotConn
152 wantMetrics map[string]int64
153 disconnectBeforeCleanup bool
154 disconnectAfterCleanup bool
155 }{
156 "success case": {
157 prepareMock: prepareMockOk,
158 disconnectBeforeCleanup: false,
159 disconnectAfterCleanup: true,
160 wantMetrics: map[string]int64{
161 "auth_cache_hits": 1,
162 "auth_cache_misses": 1,
163 "auth_db_tempfails": 1,
164 "auth_failures": 1,
165 "auth_master_successes": 1,
166 "auth_successes": 1,
167 "disk_input": 1,
168 "disk_output": 1,
169 "invol_cs": 1,
170 "mail_cache_hits": 1,
171 "mail_lookup_attr": 1,
172 "mail_lookup_path": 1,
173 "mail_read_bytes": 1,
174 "mail_read_count": 1,
175 "maj_faults": 1,
176 "min_faults": 1,
177 "num_cmds": 1,
178 "num_connected_sessions": 1,
179 "num_logins": 1,
180 "read_bytes": 1,
181 "read_count": 1,
182 "reset_timestamp": 1723481629,
183 "vol_cs": 1,
184 "write_bytes": 1,
185 "write_count": 1,
186 },
187 },
188 "unexpected response": {
189 prepareMock: prepareMockUnexpectedResponse,
190 disconnectBeforeCleanup: false,
191 disconnectAfterCleanup: true,
192 },
193 "empty response": {
194 prepareMock: prepareMockEmptyResponse,
195 disconnectBeforeCleanup: false,
196 disconnectAfterCleanup: true,
197 },
198 "err on connect": {
199 prepareMock: prepareMockErrOnConnect,
200 disconnectBeforeCleanup: false,
201 disconnectAfterCleanup: false,
202 },
203 "err on query stats": {
204 prepareMock: prepareMockErrOnQueryExportGlobal,
205 disconnectBeforeCleanup: true,
206 disconnectAfterCleanup: true,
207 },
208 }
209
210 for name, test := range tests {
211 t.Run(name, func(t *testing.T) {
212 collr := New()
213 mock := test.prepareMock()
214 collr.newConn = func(Config) dovecotConn { return mock }
215
216 mx := collr.Collect(context.Background())
217
218 require.Equal(t, test.wantMetrics, mx)
219
220 if len(test.wantMetrics) > 0 {
221 collecttest.TestMetricsHasAllChartsDims(t, collr.Charts(), mx)
222 }
223
224 assert.Equal(t, test.disconnectBeforeCleanup, mock.disconnectCalled, "disconnect before cleanup")
225 collr.Cleanup(context.Background())
226 assert.Equal(t, test.disconnectAfterCleanup, mock.disconnectCalled, "disconnect after cleanup")
227 })
228 }
229 }
230
231 func prepareMockOk() *mockDovecotConn {
232 return &mockDovecotConn{
233 exportGlobalResponse: dataExportGlobal,
234 }
235 }
236
237 func prepareMockErrOnConnect() *mockDovecotConn {
238 return &mockDovecotConn{
239 errOnConnect: true,
240 }
241 }
242
243 func prepareMockErrOnQueryExportGlobal() *mockDovecotConn {
244 return &mockDovecotConn{
245 errOnQueryExportGlobal: true,
246 }
247 }
248
249 func prepareMockUnexpectedResponse() *mockDovecotConn {
250 return &mockDovecotConn{
251 exportGlobalResponse: []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit."),
252 }
253 }
254
255 func prepareMockEmptyResponse() *mockDovecotConn {
256 return &mockDovecotConn{}
257 }
258
259 type mockDovecotConn struct {
260 errOnConnect bool
261 errOnQueryExportGlobal bool
262 exportGlobalResponse []byte
263 disconnectCalled bool
264 }
265
266 func (m *mockDovecotConn) connect() error {
267 if m.errOnConnect {
268 return errors.New("mock.connect() error")
269 }
270 return nil
271 }
272
273 func (m *mockDovecotConn) disconnect() {
274 m.disconnectCalled = true
275 }
276
277 func (m *mockDovecotConn) queryExportGlobal() ([]byte, error) {
278 if m.errOnQueryExportGlobal {
279 return nil, errors.New("mock.queryExportGlobal() error")
280 }
281 return m.exportGlobalResponse, nil
282 }