Test Failed
Push — develop ( 7f2e85...6bc087 )
by Nicolas
02:07
created

unitest   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 471
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 325
dl 0
loc 471
rs 6.96
c 0
b 0
f 0
wmc 53

30 Methods

Rating   Name   Duplication   Size   Complexity  
A TestGlances.test_004_load() 0 12 2
A TestGlances.test_012_ip() 0 6 1
A TestGlances.test_000_update() 0 19 3
A TestGlances.test_010_processes() 0 11 1
A TestGlances.test_009_fs() 0 7 1
A TestGlances.test_017_programs() 0 7 1
A TestGlances.test_002_system() 0 9 2
A TestGlances.test_008_diskio() 0 6 1
A TestGlances.test_017_hddsmart() 0 22 4
A TestGlances.setUp() 0 3 1
A TestGlances.test_013_irq() 0 7 1
A TestGlances.test_007_network() 0 6 1
A TestGlances.test_003_cpu() 0 12 2
A TestGlances.test_006_swap() 0 11 2
A TestGlances.test_015_sorted_stats() 0 27 2
A TestGlances.test_016_subsample() 0 11 2
A TestGlances.test_011_folders() 0 7 1
A TestGlances.test_014_gpu() 0 7 1
A TestGlances.test_001_plugins() 0 7 2
A TestGlances.test_005_mem() 0 11 2
A TestGlances.test_097_attribute() 0 22 1
A TestGlances.test_095_methods() 0 9 3
A TestGlances.test_094_thresholds() 0 16 1
A TestGlances.test_018_string_value_to_float() 0 9 1
A TestGlances.test_098_history() 0 17 1
A TestGlances.test_096_views() 0 9 2
A TestGlances.test_099_output_bars() 0 31 1
A TestGlances.test_100_secure() 0 12 2
B TestGlances.test_200_memory_leak() 0 39 7
A TestGlances.test_999_the_end() 0 5 1

How to fix   Complexity   

Complexity

Complex classes like unitest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
#
4
# Glances - An eye on your system
5
#
6
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
7
#
8
# SPDX-License-Identifier: LGPL-3.0-only
9
#
10
11
"""Glances unitary tests suite."""
12
13
import time
14
import unittest
15
import sys
16
17
# Check Python version
18
if sys.version_info < (3, 4):
19
    print('Glances requires at least Python 3.4 to run.')
20
    sys.exit(1)
21
22
from glances.main import GlancesMain
23
from glances.stats import GlancesStats
24
from glances import __version__
25
from glances.globals import WINDOWS, LINUX, subsample, string_value_to_float
26
from glances.outputs.glances_bars import Bar
27
from glances.thresholds import GlancesThresholdOk
28
from glances.thresholds import GlancesThresholdCareful
29
from glances.thresholds import GlancesThresholdWarning
30
from glances.thresholds import GlancesThresholdCritical
31
from glances.thresholds import GlancesThresholds
32
from glances.plugins.plugin.model import GlancesPluginModel
33
from glances.programs import processes_to_programs
34
from glances.secure import secure_popen
35
36
# Global variables
37
# =================
38
39
# Init Glances core
40
core = GlancesMain()
41
test_config = core.get_config()
42
test_args = core.get_args()
43
44
# Init Glances stats
45
stats = GlancesStats(config=test_config,
46
                     args=test_args)
47
48
# Unitest class
49
# ==============
50
print('Unitary tests for Glances %s' % __version__)
51
52
53
class TestGlances(unittest.TestCase):
54
    """Test Glances class."""
55
56
    def setUp(self):
57
        """The function is called *every time* before test_*."""
58
        print('\n' + '=' * 78)
59
60
    def test_000_update(self):
61
        """Update stats (mandatory step for all the stats).
62
63
        The update is made twice (for rate computation).
64
        """
65
        print('INFO: [TEST_000] Test the stats update function')
66
        try:
67
            stats.update()
68
        except Exception as e:
69
            print('ERROR: Stats update failed: %s' % e)
70
            self.assertTrue(False)
71
        time.sleep(1)
72
        try:
73
            stats.update()
74
        except Exception as e:
75
            print('ERROR: Stats update failed: %s' % e)
76
            self.assertTrue(False)
77
78
        self.assertTrue(True)
79
80
    def test_001_plugins(self):
81
        """Check mandatory plugins."""
82
        plugins_to_check = ['system', 'cpu', 'load', 'mem', 'memswap', 'network', 'diskio', 'fs']
83
        print('INFO: [TEST_001] Check the mandatory plugins list: %s' % ', '.join(plugins_to_check))
84
        plugins_list = stats.getPluginsList()
85
        for plugin in plugins_to_check:
86
            self.assertTrue(plugin in plugins_list)
87
88
    def test_002_system(self):
89
        """Check SYSTEM plugin."""
90
        stats_to_check = ['hostname', 'os_name']
91
        print('INFO: [TEST_002] Check SYSTEM stats: %s' % ', '.join(stats_to_check))
92
        stats_grab = stats.get_plugin('system').get_raw()
93
        for stat in stats_to_check:
94
            # Check that the key exist
95
            self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat)
96
        print('INFO: SYSTEM stats: %s' % stats_grab)
97
98
    def test_003_cpu(self):
99
        """Check CPU plugin."""
100
        stats_to_check = ['system', 'user', 'idle']
101
        print('INFO: [TEST_003] Check mandatory CPU stats: %s' % ', '.join(stats_to_check))
102
        stats_grab = stats.get_plugin('cpu').get_raw()
103
        for stat in stats_to_check:
104
            # Check that the key exist
105
            self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat)
106
            # Check that % is > 0 and < 100
107
            self.assertGreaterEqual(stats_grab[stat], 0)
108
            self.assertLessEqual(stats_grab[stat], 100)
109
        print('INFO: CPU stats: %s' % stats_grab)
110
111
    @unittest.skipIf(WINDOWS, "Load average not available on Windows")
112
    def test_004_load(self):
113
        """Check LOAD plugin."""
114
        stats_to_check = ['cpucore', 'min1', 'min5', 'min15']
115
        print('INFO: [TEST_004] Check LOAD stats: %s' % ', '.join(stats_to_check))
116
        stats_grab = stats.get_plugin('load').get_raw()
117
        for stat in stats_to_check:
118
            # Check that the key exist
119
            self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat)
120
            # Check that % is > 0
121
            self.assertGreaterEqual(stats_grab[stat], 0)
122
        print('INFO: LOAD stats: %s' % stats_grab)
123
124
    def test_005_mem(self):
125
        """Check MEM plugin."""
126
        stats_to_check = ['available', 'used', 'free', 'total']
127
        print('INFO: [TEST_005] Check MEM stats: %s' % ', '.join(stats_to_check))
128
        stats_grab = stats.get_plugin('mem').get_raw()
129
        for stat in stats_to_check:
130
            # Check that the key exist
131
            self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat)
132
            # Check that % is > 0
133
            self.assertGreaterEqual(stats_grab[stat], 0)
134
        print('INFO: MEM stats: %s' % stats_grab)
135
136
    def test_006_swap(self):
137
        """Check MEMSWAP plugin."""
138
        stats_to_check = ['used', 'free', 'total']
139
        print('INFO: [TEST_006] Check SWAP stats: %s' % ', '.join(stats_to_check))
140
        stats_grab = stats.get_plugin('memswap').get_raw()
141
        for stat in stats_to_check:
142
            # Check that the key exist
143
            self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat)
144
            # Check that % is > 0
145
            self.assertGreaterEqual(stats_grab[stat], 0)
146
        print('INFO: SWAP stats: %s' % stats_grab)
147
148
    def test_007_network(self):
149
        """Check NETWORK plugin."""
150
        print('INFO: [TEST_007] Check NETWORK stats')
151
        stats_grab = stats.get_plugin('network').get_raw()
152
        self.assertTrue(type(stats_grab) is list, msg='Network stats is not a list')
153
        print('INFO: NETWORK stats: %s' % stats_grab)
154
155
    def test_008_diskio(self):
156
        """Check DISKIO plugin."""
157
        print('INFO: [TEST_008] Check DISKIO stats')
158
        stats_grab = stats.get_plugin('diskio').get_raw()
159
        self.assertTrue(type(stats_grab) is list, msg='DiskIO stats is not a list')
160
        print('INFO: diskio stats: %s' % stats_grab)
161
162
    def test_009_fs(self):
163
        """Check File System plugin."""
164
        # stats_to_check = [ ]
165
        print('INFO: [TEST_009] Check FS stats')
166
        stats_grab = stats.get_plugin('fs').get_raw()
167
        self.assertTrue(type(stats_grab) is list, msg='FileSystem stats is not a list')
168
        print('INFO: FS stats: %s' % stats_grab)
169
170
    def test_010_processes(self):
171
        """Check Process plugin."""
172
        # stats_to_check = [ ]
173
        print('INFO: [TEST_010] Check PROCESS stats')
174
        stats_grab = stats.get_plugin('processcount').get_raw()
175
        # total = stats_grab['total']
176
        self.assertTrue(type(stats_grab) is dict, msg='Process count stats is not a dict')
177
        print('INFO: PROCESS count stats: %s' % stats_grab)
178
        stats_grab = stats.get_plugin('processlist').get_raw()
179
        self.assertTrue(type(stats_grab) is list, msg='Process count stats is not a list')
180
        print('INFO: PROCESS list stats: %s items in the list' % len(stats_grab))
181
        # Check if number of processes in the list equal counter
182
        # self.assertEqual(total, len(stats_grab))
183
184
    def test_011_folders(self):
185
        """Check File System plugin."""
186
        # stats_to_check = [ ]
187
        print('INFO: [TEST_011] Check FOLDER stats')
188
        stats_grab = stats.get_plugin('folders').get_raw()
189
        self.assertTrue(type(stats_grab) is list, msg='Folders stats is not a list')
190
        print('INFO: Folders stats: %s' % stats_grab)
191
192
    def test_012_ip(self):
193
        """Check IP plugin."""
194
        print('INFO: [TEST_012] Check IP stats')
195
        stats_grab = stats.get_plugin('ip').get_raw()
196
        self.assertTrue(type(stats_grab) is dict, msg='IP stats is not a dict')
197
        print('INFO: IP stats: %s' % stats_grab)
198
199
    @unittest.skipIf(not LINUX, "IRQs available only on Linux")
200
    def test_013_irq(self):
201
        """Check IRQ plugin."""
202
        print('INFO: [TEST_013] Check IRQ stats')
203
        stats_grab = stats.get_plugin('irq').get_raw()
204
        self.assertTrue(type(stats_grab) is list, msg='IRQ stats is not a list')
205
        print('INFO: IRQ stats: %s' % stats_grab)
206
207
    @unittest.skipIf(not LINUX, "GPU available only on Linux")
208
    def test_014_gpu(self):
209
        """Check GPU plugin."""
210
        print('INFO: [TEST_014] Check GPU stats')
211
        stats_grab = stats.get_plugin('gpu').get_raw()
212
        self.assertTrue(type(stats_grab) is list, msg='GPU stats is not a list')
213
        print('INFO: GPU stats: %s' % stats_grab)
214
215
    def test_015_sorted_stats(self):
216
        """Check sorted stats method."""
217
        print('INFO: [TEST_015] Check sorted stats method')
218
        aliases = {
219
            "key2": "alias11",
220
            "key5": "alias2",
221
        }
222
        unsorted_stats = [
223
            {"key": "key4"},
224
            {"key": "key2"},
225
            {"key": "key5"},
226
            {"key": "key21"},
227
            {"key": "key3"},
228
        ]
229
230
        gp = GlancesPluginModel()
231
        gp.get_key = lambda: "key"
232
        gp.has_alias = aliases.get
233
        gp.stats = unsorted_stats
234
235
        sorted_stats = gp.sorted_stats()
236
        self.assertEqual(len(sorted_stats), 5)
237
        self.assertEqual(sorted_stats[0]["key"], "key5")
238
        self.assertEqual(sorted_stats[1]["key"], "key2")
239
        self.assertEqual(sorted_stats[2]["key"], "key3")
240
        self.assertEqual(sorted_stats[3]["key"], "key4")
241
        self.assertEqual(sorted_stats[4]["key"], "key21")
242
243
    def test_016_subsample(self):
244
        """Test subsampling function."""
245
        print('INFO: [TEST_016] Subsampling')
246
        for l_test in [([1, 2, 3], 4),
247
                       ([1, 2, 3, 4], 4),
248
                       ([1, 2, 3, 4, 5, 6, 7], 4),
249
                       ([1, 2, 3, 4, 5, 6, 7, 8], 4),
250
                       (list(range(1, 800)), 4),
251
                       (list(range(1, 8000)), 800)]:
252
            l_subsample = subsample(l_test[0], l_test[1])
253
            self.assertLessEqual(len(l_subsample), l_test[1])
254
255
    def test_017_hddsmart(self):
256
        """Check hard disk SMART data plugin."""
257
        try:
258
            from glances.globals import is_admin
259
        except ImportError:
260
            print("INFO: [TEST_017] pySMART not found, not running SMART plugin test")
261
            return
262
263
        stat = 'DeviceName'
264
        print('INFO: [TEST_017] Check SMART stats: {}'.format(stat))
265
        stats_grab = stats.get_plugin('smart').get_raw()
266
        if not is_admin():
267
            print("INFO: Not admin, SMART list should be empty")
268
            assert len(stats_grab) == 0
269
        elif stats_grab == {}:
270
            print("INFO: Admin but SMART list is empty")
271
            assert len(stats_grab) == 0
272
        else:
273
            print(stats_grab)
274
            self.assertTrue(stat in stats_grab[0].keys(), msg='Cannot find key: %s' % stat)
275
276
        print('INFO: SMART stats: %s' % stats_grab)
277
278
    def test_017_programs(self):
279
        """Check Programs function (it's not a plugin)."""
280
        # stats_to_check = [ ]
281
        print('INFO: [TEST_017] Check PROGRAM stats')
282
        stats_grab = processes_to_programs(stats.get_plugin('processlist').get_raw())
283
        self.assertIsInstance(stats_grab, list, msg='Programs stats list is not a list')
284
        self.assertIsInstance(stats_grab[0], dict, msg='First item should be a dict')
285
286
    def test_018_string_value_to_float(self):
287
        """Check string_value_to_float function"""
288
        print('INFO: [TEST_018] Check string_value_to_float function')
289
        self.assertEqual(string_value_to_float('32kB'), 32000.0)
290
        self.assertEqual(string_value_to_float('32 KB'), 32000.0)
291
        self.assertEqual(string_value_to_float('15.5MB'), 15500000.0)
292
        self.assertEqual(string_value_to_float('25.9'), 25.9)
293
        self.assertEqual(string_value_to_float('12'), 12)
294
        self.assertEqual(string_value_to_float('--'), None)
295
296
    def test_094_thresholds(self):
297
        """Test thresholds classes"""
298
        print('INFO: [TEST_094] Thresholds')
299
        ok = GlancesThresholdOk()
300
        careful = GlancesThresholdCareful()
301
        warning = GlancesThresholdWarning()
302
        critical = GlancesThresholdCritical()
303
        self.assertTrue(ok < careful)
304
        self.assertTrue(careful < warning)
305
        self.assertTrue(warning < critical)
306
        self.assertFalse(ok > careful)
307
        self.assertEqual(ok, ok)
308
        self.assertEqual(str(ok), 'OK')
309
        thresholds = GlancesThresholds()
310
        thresholds.add('cpu_percent', 'OK')
311
        self.assertEqual(thresholds.get(stat_name='cpu_percent').description(), 'OK')
312
313
    def test_095_methods(self):
314
        """Test mandatories methods"""
315
        print('INFO: [TEST_095] Mandatories methods')
316
        mandatories_methods = ['reset', 'update']
317
        plugins_list = stats.getPluginsList()
318
        for plugin in plugins_list:
319
            for method in mandatories_methods:
320
                self.assertTrue(hasattr(stats.get_plugin(plugin), method),
321
                                msg='{} has no method {}()'.format(plugin, method))
322
323
    def test_096_views(self):
324
        """Test get_views method"""
325
        print('INFO: [TEST_096] Test views')
326
        plugins_list = stats.getPluginsList()
327
        for plugin in plugins_list:
328
            stats.get_plugin(plugin).get_raw()
329
            views_grab = stats.get_plugin(plugin).get_views()
330
            self.assertTrue(type(views_grab) is dict,
331
                            msg='{} view is not a dict'.format(plugin))
332
333
    def test_097_attribute(self):
334
        """Test GlancesAttribute classes"""
335
        print('INFO: [TEST_097] Test attribute')
336
        # GlancesAttribute
337
        from glances.attribute import GlancesAttribute
338
        a = GlancesAttribute('a', description='ad', history_max_size=3)
339
        self.assertEqual(a.name, 'a')
340
        self.assertEqual(a.description, 'ad')
341
        a.description = 'adn'
342
        self.assertEqual(a.description, 'adn')
343
        a.value = 1
344
        a.value = 2
345
        self.assertEqual(len(a.history), 2)
346
        a.value = 3
347
        self.assertEqual(len(a.history), 3)
348
        a.value = 4
349
        # Check if history_max_size=3 is OK
350
        self.assertEqual(len(a.history), 3)
351
        self.assertEqual(a.history_size(), 3)
352
        self.assertEqual(a.history_len(), 3)
353
        self.assertEqual(a.history_value()[1], 4)
354
        self.assertEqual(a.history_mean(nb=3), 4.5)
355
356
    def test_098_history(self):
357
        """Test GlancesHistory classes"""
358
        print('INFO: [TEST_098] Test history')
359
        # GlancesHistory
360
        from glances.history import GlancesHistory
361
        h = GlancesHistory()
362
        h.add('a', 1, history_max_size=100)
363
        h.add('a', 2, history_max_size=100)
364
        h.add('a', 3, history_max_size=100)
365
        h.add('b', 10, history_max_size=100)
366
        h.add('b', 20, history_max_size=100)
367
        h.add('b', 30, history_max_size=100)
368
        self.assertEqual(len(h.get()), 2)
369
        self.assertEqual(len(h.get()['a']), 3)
370
        h.reset()
371
        self.assertEqual(len(h.get()), 2)
372
        self.assertEqual(len(h.get()['a']), 0)
373
374
    def test_099_output_bars(self):
375
        """Test quick look plugin.
376
377
        > bar.min_value
378
        0
379
        > bar.max_value
380
        100
381
        > bar.percent = -1
382
        > bar.percent
383
        0
384
        """
385
        print('INFO: [TEST_099] Test progress bar')
386
387
        bar = Bar(size=1)
388
        # Percent value can not be lower than min_value
389
        bar.percent = -1
390
        self.assertLessEqual(bar.percent, bar.min_value)
391
        # but... percent value can be higher than max_value
392
        bar.percent = 101
393
        self.assertLessEqual(bar.percent, 101)
394
395
        # Test display
396
        bar = Bar(size=50)
397
        bar.percent = 0
398
        self.assertEqual(bar.get(), '                                              0.0%')
399
        bar.percent = 70
400
        self.assertEqual(bar.get(), '|||||||||||||||||||||||||||||||              70.0%')
401
        bar.percent = 100
402
        self.assertEqual(bar.get(), '||||||||||||||||||||||||||||||||||||||||||||  100%')
403
        bar.percent = 110
404
        self.assertEqual(bar.get(), '|||||||||||||||||||||||||||||||||||||||||||| >100%')
405
406
    def test_100_secure(self):
407
        """Test secure functions"""
408
        print('INFO: [TEST_100] Secure functions')
409
410
        if WINDOWS:
411
            self.assertIn(secure_popen('echo TEST'), ['TEST\n',
412
                                                      'TEST\r\n'])
413
            self.assertIn(secure_popen('echo TEST1 && echo TEST2'), ['TEST1\nTEST2\n',
414
                                                                     'TEST1\r\nTEST2\r\n'])
415
        else:
416
            self.assertEqual(secure_popen('echo -n TEST'), 'TEST')
417
            self.assertEqual(secure_popen('echo -n TEST1 && echo -n TEST2'), 'TEST1TEST2')
418
            # Make the test failed on Github (AssertionError: '' != 'FOO\n')
419
            # but not on my localLinux computer...
420
            # self.assertEqual(secure_popen('echo FOO | grep FOO'), 'FOO\n')
421
422
    def test_200_memory_leak(self):
423
        """Memory leak check"""
424
        import tracemalloc
425
        print('INFO: [TEST_200] Memory leak check')
426
        tracemalloc.start()
427
        # 3 iterations just to init the stats and fill the memory
428
        for _ in range(3):
429
            stats.update()
430
431
        # Start the memory leak check
432
        snapshot_begin = tracemalloc.take_snapshot()
433
        for _ in range(3):
434
            stats.update()
435
        snapshot_end = tracemalloc.take_snapshot()
436
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
437
        memory_leak = sum([s.size_diff for s in snapshot_diff])
438
        print('INFO: Memory leak: {} bytes'.format(memory_leak))
439
440
        # snapshot_begin = tracemalloc.take_snapshot()
441
        for _ in range(30):
442
            stats.update()
443
        snapshot_end = tracemalloc.take_snapshot()
444
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
445
        memory_leak = sum([s.size_diff for s in snapshot_diff])
446
        print('INFO: Memory leak: {} bytes'.format(memory_leak))
447
448
        # snapshot_begin = tracemalloc.take_snapshot()
449
        for _ in range(300):
450
            stats.update()
451
        snapshot_end = tracemalloc.take_snapshot()
452
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
453
        memory_leak = sum([s.size_diff for s in snapshot_diff])
454
        print('INFO: Memory leak: {} bytes'.format(memory_leak))
455
        snapshot_top = snapshot_end.compare_to(snapshot_begin, 'traceback')
456
        print("Memory consumption (top 5):")
457
        for stat in snapshot_top[:5]:
458
            print(stat)
459
            for line in stat.traceback.format():
460
                print(line)
461
462
    def test_999_the_end(self):
463
        """Free all the stats"""
464
        print('INFO: [TEST_999] Free the stats')
465
        stats.end()
466
        self.assertTrue(True)
467
468
469
if __name__ == '__main__':
470
    unittest.main()
471