Yann Weber 5 days ago
parent
commit
f4b7558f77
1 changed files with 267 additions and 180 deletions
  1. 267
    180
      rspamd_

+ 267
- 180
rspamd_ View File

@@ -1,21 +1,29 @@
1 1
 #!/usr/bin/env python3
2
-#%# family=auto
3
-#%# capabilities=autoconf suggest
4
-
5
-# Rpsamd munin plugin
6
-#
7
-# Can be use as
8
-# - rspamd_actions
9
-# - rspamd_results
10
-# - rspamd_scantime
11
-# - rspamd_uptime
12
-# - rspamd_memory_usage
13
-# - rspamd_memory_stats
14
-# - rspamd_connections
15
-# - rspamd_ctrl_connections
16
-# - rspamd_statfiles
17
-# - rspamd_fuzzy_hashes
18
-#
2
+# %# family=auto
3
+# %# capabilities=autoconf suggest
4
+
5
+"""
6
+Rpsamd munin plugin
7
+
8
+Can be use as
9
+- rspamd_actions
10
+- rspamd_results
11
+- rspamd_scantime
12
+- rspamd_uptime
13
+- rspamd_memory_usage
14
+- rspamd_memory_stats
15
+- rspamd_connections
16
+- rspamd_ctrl_connections
17
+- rspamd_statfiles
18
+- rspamd_fuzzy_hashes
19
+
20
+Config :
21
+
22
+[rspamd_*]
23
+env.rspamc = "/usr/bin/rspamc"
24
+env.cache_file = "/tmp/munin_rspamd.cache"
25
+env.cache_time = 240
26
+"""
19 27
 
20 28
 import json
21 29
 import os
@@ -27,24 +35,32 @@ import io
27 35
 import unittest
28 36
 import unittest.mock
29 37
 import tempfile
38
+from typing import Final
30 39
 import contextlib
31 40
 
41
+
32 42
 def usage():
33
-    return '''You should ln -s /usr/share/munin/plugins/rspamd_ /etc/munin/plugins/rspamd_FUNC
34
-With FUNC one of %s''' % (', '.join(CONFIGS.keys()))
43
+    """Return simple help"""
44
+    return """You should ln -s /usr/share/munin/plugins/rspamd_ /etc/munin/plugins/rspamd_FUNC
45
+With FUNC one of %s""" % (
46
+        ", ".join(CONFIGS.keys())
47
+    )
48
+
35 49
 
36 50
 def avg_scantime(scantimes):
51
+    """Returns average, min, max scantimes"""
37 52
     total = [float(t) for t in scantimes if t]
38 53
     return sum(total) / len(total), min(total), max(total)
39 54
 
40 55
 
41 56
 def storage2name(name):
42
-    return re.sub('[\.\- ]', '_', name)
57
+    """Format storage name"""
58
+    return re.sub(r"[\.\- ]", "_", name)
43 59
 
44 60
 
45
-CONFIGS = {
46
-        'actions': [
47
-            lambda data: '''\
61
+CONFIGS: Final = {
62
+    "actions": [
63
+        lambda data: """\
48 64
 graph_title Rspamd actions
49 65
 graph_vlabel mails
50 66
 graph_args --base 1000 -l 0
@@ -52,24 +68,32 @@ graph_category antispam
52 68
 graph_scale yes
53 69
 scanned.label Scanned/total
54 70
 learned.label Learned
55
-%s''' %     (
56
-                '\n'.join(['%s.label %s' % (action.replace(' ', '_'),
57
-                                            action.title())
58
-                           for action in data['actions']])
59
-            ),
60
-            lambda data: '''\
71
+%s"""
72
+        % (
73
+            "\n".join(
74
+                [
75
+                    "%s.label %s" % (action.replace(" ", "_"), action.title())
76
+                    for action in data["actions"]
77
+                ]
78
+            )
79
+        ),
80
+        lambda data: """\
61 81
 scanned.value %d
62 82
 learned.value %d
63
-%s''' %     (
64
-                data['scanned'],
65
-                data['learned'],
66
-                '\n'.join(['%s.value %d' % (action.replace(' ', '_'),
67
-                                            value)
68
-                           for action, value in data['actions'].items()])
83
+%s"""
84
+        % (
85
+            data["scanned"],
86
+            data["learned"],
87
+            "\n".join(
88
+                [
89
+                    "%s.value %d" % (action.replace(" ", "_"), value)
90
+                    for action, value in data["actions"].items()
91
+                ]
69 92
             ),
70
-        ],
71
-        'results': [
72
-            '''\
93
+        ),
94
+    ],
95
+    "results": [
96
+        """\
73 97
 graph_title Rspamd results
74 98
 graph_vlabel mails
75 99
 graph_args --base 1000 -l 0
@@ -78,13 +102,14 @@ graph_scale yes
78 102
 spam.label Spams
79 103
 spam.draw STACK
80 104
 ham.label Ham
81
-ham.draw STACK''',
82
-            lambda data: '''\
105
+ham.draw STACK""",
106
+        lambda data: """\
83 107
 spam.value %d
84
-ham.value %d''' % (data['spam_count'], data['ham_count']),
85
-        ],
86
-        'scantime': [
87
-            '''\
108
+ham.value %d"""
109
+        % (data["spam_count"], data["ham_count"]),
110
+    ],
111
+    "scantime": [
112
+        """\
88 113
 graph_title Rspamd scantime
89 114
 graph_args --base 1000 -l 0
90 115
 graph_category antispam
@@ -93,14 +118,15 @@ graph_vlabel seconds
93 118
 scantime.label Average scantime
94 119
 min.label Minimum scantime
95 120
 max.label Maximum scantime
96
-''',
97
-            lambda data: '''\
121
+""",
122
+        lambda data: """\
98 123
 scantime.value %f
99 124
 min.value %f
100
-max.value %f''' % avg_scantime(data['scan_times']),
101
-        ],
102
-        'uptime': [
103
-            '''\
125
+max.value %f"""
126
+        % avg_scantime(data["scan_times"]),
127
+    ],
128
+    "uptime": [
129
+        """\
104 130
 graph_title Rspamd uptime
105 131
 graph_args --base 1000 -l 0
106 132
 graph_category antispam
@@ -108,22 +134,22 @@ graph_scale no
108 134
 graph_vlabel uptime in days
109 135
 uptime.label uptime
110 136
 uptime.draw AREA
111
-''',
112
-            lambda data: 'uptime.value %f' % (data['uptime']/(3600*24)),
113
-        ],
114
-        'memory_usage': [
115
-            '''\
137
+""",
138
+        lambda data: "uptime.value %f" % (data["uptime"] / (3600 * 24)),
139
+    ],
140
+    "memory_usage": [
141
+        """\
116 142
 graph_title Rspamd memory usage
117 143
 graph_args --base 1024 -l 0
118 144
 graph_category antispam
119 145
 graph_scale yes
120 146
 graph_vlabel bytes
121 147
 memory.label Memory usage
122
-''',
123
-            lambda data: 'memory.value %d' % data['bytes_allocated'],
124
-        ],
125
-        'memory_stats': [
126
-            '''\
148
+""",
149
+        lambda data: "memory.value %d" % data["bytes_allocated"],
150
+    ],
151
+    "memory_stats": [
152
+        """\
127 153
 graph_title Rspamd memory stats
128 154
 graph_args --base 1000 -l 0
129 155
 graph_category antispam
@@ -131,224 +157,285 @@ graph_scale yes
131 157
 pools.label Pools allocated - freed
132 158
 chunks.label Chunks allocated - freed
133 159
 shared_chunks_allocated.label Shared chunks allocated
134
-''',
135
-            lambda data: '''\
160
+""",
161
+        lambda data: """\
136 162
 pools.value %d
137 163
 chunks.value %d
138
-shared_chunks_allocated.value %d''' % (data['pools_allocated'] - data['pools_freed'],
139
-                                       data['chunks_allocated'] - data['chunks_freed'],
140
-                                       data['shared_chunks_allocated']),
141
-        ],
142
-        'connections': [
143
-            '''\
164
+shared_chunks_allocated.value %d"""
165
+        % (
166
+            data["pools_allocated"] - data["pools_freed"],
167
+            data["chunks_allocated"] - data["chunks_freed"],
168
+            data["shared_chunks_allocated"],
169
+        ),
170
+    ],
171
+    "connections": [
172
+        """\
144 173
 graph_title Rspamd connections
145 174
 graph_args --base 1000 -l 0
146 175
 graph_category antispam
147 176
 graph_scale yes
148 177
 graph_vlabel connections
149 178
 connections.label opened connections
150
-''',
151
-            lambda data: 'connections.value %d' % data['connections'],
152
-        ],
153
-        'ctrl_connections': [
154
-            '''\
179
+""",
180
+        lambda data: "connections.value %d" % data["connections"],
181
+    ],
182
+    "ctrl_connections": [
183
+        """\
155 184
 graph_title Rspamd control connections count
156 185
 graph_args --base 1000 -l 0
157 186
 graph_category antispam
158 187
 graph_scale yes
159 188
 graph_vlabel connections
160 189
 connections.label control connections count
161
-''',
162
-            lambda data: 'connections.value %d' % data['control_connections'],
163
-        ],
164
-        'statfiles': [
165
-            lambda data:'''\
190
+""",
191
+        lambda data: "connections.value %d" % data["control_connections"],
192
+    ],
193
+    "statfiles": [
194
+        lambda data: """\
166 195
 graph_title rspamd bayes statfiles
167 196
 graph_args --base 1000 -l 0
168 197
 graph_scale yes
169 198
 graph_category antispam
170 199
 graph_vlabel learned mails
171
-%s''' % (
172
-            '\n'.join(['''learned_{sym}.label {sym} learned
173
-users_{sym}.label {sym} users'''.format(sym=stat['symbol'])
174
-                       for stat in data['statfiles']])
200
+%s"""
201
+        % (
202
+            "\n".join(
203
+                [
204
+                    """learned_{sym}.label {sym} learned
205
+users_{sym}.label {sym} users""".format(
206
+                        sym=stat["symbol"]
207
+                    )
208
+                    for stat in data["statfiles"]
209
+                ]
210
+            )
175 211
         ),
176
-            lambda data: '\n'.join('''\
212
+        lambda data: "\n".join(
213
+            """\
177 214
 learned_{sym}.value {lv}
178
-users_{sym}.value {uv}'''.format(sym=stat['symbol'], lv=stat['revision'], uv=stat['users']) for stat in data['statfiles']),
179
-        ],
180
-        'fuzzy_hashes': [
181
-            lambda data:'''\
215
+users_{sym}.value {uv}""".format(
216
+                sym=stat["symbol"], lv=stat["revision"], uv=stat["users"]
217
+            )
218
+            for stat in data["statfiles"]
219
+        ),
220
+    ],
221
+    "fuzzy_hashes": [
222
+        lambda data: """\
182 223
 graph_title rspamd fuzzy hases storage
183 224
 graph_args --base 1000 -l 0
184 225
 graph_scale yes
185 226
 graph_category antispam
186 227
 graph_vlabel hashes
187
-%s''' % (
188
-            '\n'.join(['%s.label %s' % (storage2name(storage), storage)
189
-                       for storage in data['fuzzy_hashes']])
228
+%s"""
229
+        % (
230
+            "\n".join(
231
+                [
232
+                    "%s.label %s" % (storage2name(storage), storage)
233
+                    for storage in data["fuzzy_hashes"]
234
+                ]
235
+            )
236
+        ),
237
+        lambda data: "\n".join(
238
+            [
239
+                "%s.value %d" % (storage2name(storage), count)
240
+                for storage, count in data["fuzzy_hashes"].items()
241
+            ]
190 242
         ),
191
-            lambda data: '\n'.join(['%s.value %d' % (storage2name(storage), count)
192
-                                    for storage, count in data['fuzzy_hashes'].items()]),
193
-        ],
243
+    ],
194 244
 }
195 245
 
196 246
 
197 247
 def main(argv, environ):
198
-    rspamc = environ.get('rspamc', '/usr/bin/rspamc')
199
-    cache_file = environ.get('cache_file', '/tmp/munin_rspamd.cache')
200
-    cache_time = int(environ.get('cache_time', 60 * 4))
248
+    """main function"""
249
+    rspamc = environ.get("rspamc", "/usr/bin/rspamc")
250
+    cache_file = environ.get("cache_file", "/tmp/munin_rspamd.cache")
251
+    cache_time = int(environ.get("cache_time", 60 * 4))
201 252
 
202
-    rspamc_cmd = shlex.join([rspamc, '--json', 'stat'])
253
+    rspamc_cmd = shlex.join([rspamc, "--json", "stat"])
203 254
 
204 255
     if len(argv) > 1:
205
-        if argv[1] == 'autoconf':
256
+        if argv[1] == "autoconf":
206 257
             if os.path.exists(rspamc):
207
-                return 'yes'
208
-            else:
209
-                return 'no (%s not found)' % rspamc
210
-        elif argv[1] == 'suggest':
211
-            return '#./rspamd_ suggest\n' + ('\n'.join(CONFIGS.keys()))
258
+                return "yes"
259
+            return "no (%s not found)" % rspamc
260
+        if argv[1] == "suggest":
261
+            return "#./rspamd_ suggest\n" + ("\n".join(CONFIGS.keys()))
212 262
 
213 263
     data = None
214 264
     if os.path.exists(cache_file):
215 265
         cache_stat = os.stat(cache_file)
216 266
         if cache_stat.st_mtime > time.time() - cache_time:
217
-            with open(cache_file, 'r') as cache:
267
+            with open(cache_file, "r", encoding="utf-8") as cache:
218 268
                 try:
219 269
                     data = json.loads(cache.read())
220 270
                 except json.JSONDecodeError:
221 271
                     pass
222 272
 
223 273
     if data is None:
224
-        with open(cache_file, 'w') as cache:
225
-            with os.popen(rspamc_cmd, mode='r') as pipe:
274
+        with open(cache_file, "w", encoding="utf-8") as cache:
275
+            with os.popen(rspamc_cmd, mode="r") as pipe:
226 276
                 data = pipe.read()
227 277
                 cache.write(data)
228 278
                 data = json.loads(data)
229 279
 
230
-
231
-    spl = argv[0].split('_')[1:]
280
+    spl = argv[0].split("_")[1:]
232 281
     if len(spl) == 0:
233 282
         raise NameError(usage())
234
-    cmd = '_'.join(spl)
283
+    cmd = "_".join(spl)
235 284
     if cmd not in CONFIGS:
236
-        raise NameError('Unknown command %r. %s' % (cmd, usage()))
285
+        raise NameError("Unknown command %r. %s" % (cmd, usage()))
237 286
 
238
-    CONFIG = CONFIGS[cmd][0]
239
-    ACT = CONFIGS[cmd][1]
287
+    config = CONFIGS[cmd][0]
288
+    act = CONFIGS[cmd][1]
240 289
 
241
-    if len(argv) > 1 and argv[1] == 'config':
242
-        if not isinstance(CONFIG, str):
243
-            CONFIG = CONFIG(data)
244
-        return CONFIG
245
-    else:
246
-        return ACT(data)
290
+    if len(argv) > 1 and argv[1] == "config":
291
+        if not isinstance(config, str):
292
+            config = config(data)
293
+        return config
247 294
 
295
+    return act(data)
248 296
 
249
-if __name__ == '__main__':
297
+
298
+if __name__ == "__main__":
250 299
     try:
251 300
         print(main(sys.argv, os.environ))
252
-    except Exception as expt:
253
-        print(expt)
301
+    except NameError as main_expt:
302
+        print(main_expt)
254 303
 
255 304
 #
256 305
 # Tests
257 306
 #
258 307
 
259
-JSON='{"version":"3.4","config_id":"1234","uptime":16991,"read_only":false,"scanned":43,"learned":43,"actions":{"reject":0,"soft reject":0,"rewrite subject":0,"add header":5,"greylist":4,"no action":34},"scan_times":[0.910916,1.291352,1.241323,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"spam_count":5,"ham_count":38,"connections":2,"control_connections":265,"pools_allocated":538,"pools_freed":512,"bytes_allocated":27817136,"chunks_allocated":110,"shared_chunks_allocated":3,"chunks_freed":0,"chunks_oversized":1,"fragmented":0,"total_learns":40,"statfiles":[{"revision":33,"used":0,"total":0,"size":0,"symbol":"BAYES_SPAM","type":"redis","languages":0,"users":1},{"revision":7,"used":0,"total":0,"size":0,"symbol":"BAYES_HAM","type":"redis","languages":0,"users":1}],"fuzzy_hashes":{"local":0,"rspamd.com":1872513971},"scan_time":0.02}'
260
-
261
-EXPTS = {
262
-        'actions': ['reject.value 0',
263
-                    'soft_reject.value 0',
264
-                    'rewrite_subject.value 0',
265
-                    'add_header.value 5',
266
-                    'greylist.value 4',
267
-                    'no_action.value 34',
268
-                    'learned.value 43',
269
-                    'scanned.value 43'],
270
-        'results': ['spam.value 5', 'ham.value 38'],
271
-        'scantime': ['scantime.value 1.147864',
272
-                     'min.value 0.910916',
273
-                     'max.value 1.291352'],
274
-        'uptime': ['uptime.value 0.196655',],
275
-        'memory_usage': ['memory.value 27817136',],
276
-        'memory_stats': ['chunks.value 110',
277
-                         'shared_chunks_allocated.value 3',
278
-                         'pools.value 26'],
279
-        'connections': ['connections.value 2'],
280
-        'ctrl_connections': ['connections.value 265'],
281
-        'statfiles': ['users_BAYES_SPAM.value 1',
282
-                      'learned_BAYES_HAM.value 7',
283
-                      'learned_BAYES_SPAM.value 33',
284
-                      'users_BAYES_HAM.value 1'],
285
-        'fuzzy_hashes': ['local.value 0', 'rspamd_com.value 1872513971'],
286
-    }
308
+JSON: Final = r"""{\
309
+"version":"3.4","config_id":"1234","uptime":16991,"read_only":false,\
310
+"scanned":43,"learned":43,"actions":\
311
+{"reject":0,"soft reject":0,"rewrite subject":0,"add header":5,\
312
+"greylist":4,"no action":34},"scan_times":\
313
+[0.910916,1.291352,1.241323,null,null,null,null,null,null,null,\
314
+null,null,null,null,null,null,null,null,null,null,null,null,null\
315
+,null,null,null,null,null,null,null,null],\
316
+"spam_count":5,"ham_count":38,"connections":2,\
317
+"control_connections":265,"pools_allocated":538,"pools_freed":512,\
318
+"bytes_allocated":27817136,"chunks_allocated":110,\
319
+"shared_chunks_allocated":3,"chunks_freed":0,"chunks_oversized":1,\
320
+"fragmented":0,"total_learns":40,"statfiles":\
321
+[{"revision":33,"used":0,"total":0,"size":0,"symbol":"BAYES_SPAM",\
322
+"type":"redis","languages":0,"users":1},\
323
+{"revision":7,"used":0,"total":0,"size":0,"symbol":"BAYES_HAM",\
324
+"type":"redis","languages":0,"users":1}],\
325
+"fuzzy_hashes":{"local":0,"rspamd.com":1872513971},"scan_time":0.02}"""
326
+
327
+EXPTS: Final = {
328
+    "actions": [
329
+        "reject.value 0",
330
+        "soft_reject.value 0",
331
+        "rewrite_subject.value 0",
332
+        "add_header.value 5",
333
+        "greylist.value 4",
334
+        "no_action.value 34",
335
+        "learned.value 43",
336
+        "scanned.value 43",
337
+    ],
338
+    "results": ["spam.value 5", "ham.value 38"],
339
+    "scantime": ["scantime.value 1.147864", "min.value 0.910916", "max.value 1.291352"],
340
+    "uptime": [
341
+        "uptime.value 0.196655",
342
+    ],
343
+    "memory_usage": [
344
+        "memory.value 27817136",
345
+    ],
346
+    "memory_stats": [
347
+        "chunks.value 110",
348
+        "shared_chunks_allocated.value 3",
349
+        "pools.value 26",
350
+    ],
351
+    "connections": ["connections.value 2"],
352
+    "ctrl_connections": ["connections.value 265"],
353
+    "statfiles": [
354
+        "users_BAYES_SPAM.value 1",
355
+        "learned_BAYES_HAM.value 7",
356
+        "learned_BAYES_SPAM.value 33",
357
+        "users_BAYES_HAM.value 1",
358
+    ],
359
+    "fuzzy_hashes": ["local.value 0", "rspamd_com.value 1872513971"],
360
+}
361
+
287 362
 
288 363
 @contextlib.contextmanager
289 364
 def json_sample():
365
+    """Mock rspamc --json stat result"""
290 366
     return io.StringIO(JSON)
291 367
 
368
+
292 369
 class MuninRspamdTests(unittest.TestCase):
370
+    """Plugin selftest"""
293 371
 
294 372
     def setUp(self):
295
-        self.JSON = lambda: io.StringIO(JSON)
296
-        fd, self.tmpcache = tempfile.mkstemp()
297
-        os.close(fd)
373
+        """Prepare cache file & environment"""
374
+        self.json = lambda: io.StringIO(JSON)
375
+        tmpfd, self.tmpcache = tempfile.mkstemp()
376
+        os.close(tmpfd)
298 377
         os.unlink(self.tmpcache)
299
-        self.environ = {'cache_file': self.tmpcache}
378
+        self.environ = {"cache_file": self.tmpcache}
300 379
 
301 380
     def tearDown(self):
381
+        """Remove cache file"""
302 382
         if os.path.isfile(self.tmpcache):
303 383
             os.unlink(self.tmpcache)
304 384
 
305 385
     def test_configs(self):
306
-        for cmd in CONFIGS.keys():
386
+        """check plugin config runs without error and returns
387
+        expected fields
388
+        """
389
+        for cmd in CONFIGS:
307 390
             with self.subTest(cmd=cmd):
308
-                with unittest.mock.patch('os.popen', return_value=self.JSON()) as mock_popen:
309
-                    ret = main(['rspamd_%s' % cmd, 'config'], self.environ)
310
-                    self.assertIn('graph_title', ret)
311
-                    self.assertIn('graph_args', ret)
312
-                    self.assertIn('graph_scale', ret)
313
-                    self.assertIn('graph_category antispam', ret)
391
+                with unittest.mock.patch("os.popen", return_value=self.json()):
392
+                    ret = main(["rspamd_%s" % cmd, "config"], self.environ)
393
+                    self.assertIn("graph_title", ret)
394
+                    self.assertIn("graph_args", ret)
395
+                    self.assertIn("graph_scale", ret)
396
+                    self.assertIn("graph_category antispam", ret)
314 397
                 self.tearDown()
315 398
 
316 399
     def test_values(self):
317
-        for cmd in CONFIGS.keys():
400
+        """check plugin runs without error"""
401
+        for cmd in CONFIGS:
318 402
             with self.subTest(cmd=cmd):
319
-                with unittest.mock.patch('os.popen', return_value=self.JSON()) as mock_popen:
320
-                    ret = main(['rspamd_%s' % cmd], self.environ)
403
+                with unittest.mock.patch("os.popen", return_value=self.json()):
404
+                    ret = main(["rspamd_%s" % cmd], self.environ)
321 405
                     self.assertNotEqual(len(ret), 0)
322 406
 
323 407
     def test_consistency(self):
324
-        for cmd in CONFIGS.keys():
408
+        """check config & values matches"""
409
+        for cmd in CONFIGS:
325 410
             with self.subTest(cmd=cmd):
326
-                with unittest.mock.patch('os.popen', return_value=self.JSON()) as mock_popen:
327
-                    conf = main(['rspamd_%s' % cmd, 'config'], self.environ)
328
-                    values = main(['rspamd_%s' % cmd], self.environ)
411
+                with unittest.mock.patch("os.popen", return_value=self.json()):
412
+                    conf = main([f"rspamd_{cmd}", "config"], self.environ)
413
+                    values = main([f"rspamd_{cmd}"], self.environ)
329 414
 
330 415
                     keys = []
331
-                    for line in conf.split('\n'):
332
-                        prefix = line.split(' ')[0]
333
-                        if '.' not in prefix:
416
+                    for line in conf.split("\n"):
417
+                        prefix = line.split(" ")[0]
418
+                        if "." not in prefix:
334 419
                             continue
335
-                        spl = prefix.split('.')
336
-                        if len(spl) < 2 or spl[1] != 'label':
420
+                        spl = prefix.split(".")
421
+                        if len(spl) < 2 or spl[1] != "label":
337 422
                             continue
338 423
                         keys.append(spl[0])
339 424
 
340 425
                     for name in keys:
341
-                        self.assertIn('%s.value ' % name, values)
426
+                        self.assertIn(f"{name}.value ", values)
342 427
 
343 428
     def test_results(self):
429
+        """munin values"""
344 430
         for cmd, expt in EXPTS.items():
345 431
             with self.subTest(cmd=cmd):
346
-                with unittest.mock.patch('os.popen', return_value=self.JSON()) as mock_popen:
347
-                    ret = main([f'rspamd_{cmd}'], self.environ)
348
-                    self.assertEqual(set(ret.split('\n')), set(expt))
349
-
432
+                with unittest.mock.patch("os.popen", return_value=self.json()):
433
+                    ret = main([f"rspamd_{cmd}"], self.environ)
434
+                    self.assertEqual(set(ret.split("\n")), set(expt))
350 435
 
351 436
     def test_suggest(self):
352
-        ret = main(['rspamd_', 'suggest'], self.environ)
353
-        self.assertEqual(set(ret.split('\n')), set(CONFIGS.keys()) | set(['#./rspamd_ suggest']))
354
-
437
+        """munin suggest autoconf test"""
438
+        ret = main(["rspamd_", "suggest"], self.environ)
439
+        self.assertEqual(
440
+            set(ret.split("\n")), set(CONFIGS.keys()) | set(["#./rspamd_ suggest"])
441
+        )

Loading…
Cancel
Save