Test Failed
Pull Request — develop (#2898)
by
unknown
02:12
created

unittest-core.TestGlances._common_plugin_tests()   A

Complexity

Conditions 1

Size

Total Lines 27
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nop 2
dl 0
loc 27
rs 9.95
c 0
b 0
f 0
1
#!/usr/bin/env python
2
#
3
# Glances - An eye on your system
4
#
5
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
6
#
7
# SPDX-License-Identifier: LGPL-3.0-only
8
#
9
10
"""Glances unitary tests suite."""
11
12
import functools
13
import json
14
import time
15
import unittest
16
17
from glances import __version__
18
from glances.events_list import GlancesEventsList
19
from glances.filter import GlancesFilter, GlancesFilterList
20
from glances.globals import LINUX, WINDOWS, string_value_to_float, subsample
21
from glances.main import GlancesMain
22
from glances.outputs.glances_bars import Bar
23
from glances.plugins.plugin.model import GlancesPluginModel
24
from glances.programs import processes_to_programs
25
from glances.secure import secure_popen
26
from glances.stats import GlancesStats
27
from glances.thresholds import (
28
    GlancesThresholdCareful,
29
    GlancesThresholdCritical,
30
    GlancesThresholdOk,
31
    GlancesThresholds,
32
    GlancesThresholdWarning,
33
)
34
35
# Global variables
36
# =================
37
38
# Init Glances core
39
core = GlancesMain()
40
test_config = core.get_config()
41
test_args = core.get_args()
42
43
# Init Glances stats
44
stats = GlancesStats(config=test_config, args=test_args)
45
46
# Unitest class
47
# ==============
48
print(f'Unitary tests for Glances {__version__}')
49
50
51
class TestGlances(unittest.TestCase):
52
    """Test Glances class."""
53
54
    def setUp(self):
55
        """The function is called *every time* before test_*."""
56
        print('\n' + '=' * 78)
57
58
    def reset_stats_history_and_views(self, plugin):
59
        plugin_instance = stats.get_plugin(plugin)
60
        plugin_instance.reset()  # reset stats
61
        plugin_instance.reset_views()  # reset views
62
        plugin_instance.reset_stats_history()  # reset history
63
64
        return plugin_instance
65
66
    def zipWith(self, method, elems, values):
67
        [method(elem, value) for elem,value in zip(elems, values)]
68
69
    def do_checks_before_update(self, plugin_instance):
70
        elems = [
71
            plugin_instance.get_raw(),
72
            plugin_instance.is_enabled(),
73
            plugin_instance.is_disabled(),
74
            plugin_instance.get_views()
75
        ]
76
77
        values = [
78
            plugin_instance.stats_init_value,
79
            True,
80
            False,
81
            {}
82
        ]
83
84
        self.zipWith(self.assertEqual, elems, values)
85
86
        self.assertIsInstance(plugin_instance.get_raw(), (dict, list))
87
88
        if plugin_instance.history_enable() and isinstance(plugin_instance.get_raw(), dict):
89
            self.assertEqual(plugin_instance.get_key(), None)
90
            self.assertTrue(
91
                all(
92
                    f in [h['name'] for h in plugin_instance.items_history_list]
93
                    for f in plugin_instance.get_raw_history()
94
                )
95
            )
96
        elif plugin_instance.history_enable() and isinstance(plugin_instance.get_raw(), list):
97
            self.assertNotEqual(plugin_instance.get_key(), None)
98
99
    def update_stats(self, plugin_instance):
100
        plugin_instance.update()
101
        plugin_instance.update_stats_history()
102
        plugin_instance.update_views()
103
104
        return plugin_instance
105
106
    def is_field_in_plugin(self, plugin_instance):
107
        def is_in_description(result, f):
108
            return True if f in plugin_instance.fields_description else result
109
110
        def is_field_in_this_description(result, i):
111
            return functools.reduce(is_in_description, i, False)
112
113
        return is_field_in_this_description
114
115
    def is_field_in_stats(self, plugin_instance, plugin):
116
        def is_field_in_this_plugin(result, f):
117
            if f not in plugin_instance.get_raw():
118
                print(f"WARNING: {f} field not found in {plugin} plugin stats")
119
            else:
120
                result = True
121
122
            return result
123
124
        return is_field_in_this_plugin
125
126
    def check_stats(self, plugin_instance, plugin):
127
        self.assertIsInstance(plugin_instance.get_raw(), (dict, list))
128
        if isinstance(plugin_instance.get_raw(), dict) and plugin_instance.get_raw() != {}:
129
            init = False
130
            is_field_present = self.is_field_in_stats(plugin_instance, plugin)
131
            field_description = plugin_instance.fields_description
132
            result = functools.reduce(is_field_present, field_description, init)
133
134
            self.assertTrue(result)
135
136
        elif isinstance(plugin_instance.get_raw(), list) and len(plugin_instance.get_raw()) > 0:
137
            init = False
138
            is_field_present = self.is_field_in_plugin(plugin_instance)
139
            raw_from_instance = plugin_instance.get_raw()
140
            result = functools.reduce(is_field_present, raw_from_instance, init)
141
142
            self.assertTrue(result)
143
144
        elems = [
145
            plugin_instance.get_raw(),
146
            plugin_instance.get_stats(),
147
            json.loads(plugin_instance.get_stats())
148
        ]
149
150
        values = [
151
            plugin_instance.get_export(),
152
            plugin_instance.get_json(),
153
            plugin_instance.get_raw()
154
        ]
155
156
        self.zipWith(self.assertEqual, elems, values)
157
158
        if len(plugin_instance.fields_description) > 0:
159
            # Get first item of the fields_description
160
            first_field = list(plugin_instance.fields_description.keys())[0]
161
162
            elems = [
163
                plugin_instance.get_raw_stats_item(first_field),
164
                json.loads(plugin_instance.get_stats_item(first_field)),
165
                plugin_instance.get_item_info(first_field, 'description')
166
            ]
167
168
            values = [
169
                dict,
170
                dict,
171
                str
172
            ]
173
174
            self.zipWith(self.assertIsInstance, elems, values)
175
176
    def filter_stats(self, plugin_instance):
177
        current_stats = plugin_instance.get_raw()
178
        if isinstance(plugin_instance.get_raw(), dict):
179
            current_stats['foo'] = 'bar'
180
            current_stats = plugin_instance.filter_stats(current_stats)
181
            self.assertTrue('foo' not in current_stats)
182
        elif isinstance(plugin_instance.get_raw(), list) and len(plugin_instance.get_raw()) > 0:
183
            current_stats[0]['foo'] = 'bar'
184
            current_stats = plugin_instance.filter_stats(current_stats)
185
            self.assertTrue('foo' not in current_stats[0])
186
187
    def get_first_history_field(self, plugin_instance):
188
        if isinstance(plugin_instance.get_raw(), dict):
189
            first_history_field = plugin_instance.get_items_history_list()[0]['name']
190
        elif isinstance(plugin_instance.get_raw(), list) and len(plugin_instance.get_raw()) > 0:
191
            first_history_field = '_'.join(
192
                [
193
                    plugin_instance.get_raw()[0][plugin_instance.get_key()],
194
                    plugin_instance.get_items_history_list()[0]['name'],
195
                ]
196
            )
197
198
        return first_history_field
0 ignored issues
show
introduced by
The variable first_history_field does not seem to be defined for all execution paths.
Loading history...
199
200
    def maybe_assert_first_for_raw(self, plugin_instance, first_history_field):
201
        if len(plugin_instance.get_raw()) > 0:
202
            self.assertEqual(len(plugin_instance.get_raw_history(first_history_field)), 2)
203
            self.assertGreater(
204
                plugin_instance.get_raw_history(first_history_field)[1][0],
205
                plugin_instance.get_raw_history(first_history_field)[0][0],
206
            )
207
208
    def maybe_assert_first_for_stats(self, plugin_instance, first_history_field):
209
        if len(plugin_instance.get_raw()) > 0:
210
            self.assertEqual(len(plugin_instance.get_raw_history(first_history_field)), 3)
211
            self.assertEqual(len(plugin_instance.get_raw_history(first_history_field, 2)), 2)
212
            self.assertIsInstance(json.loads(plugin_instance.get_stats_history()), dict)
213
214
    def chk_hist_maybe_add_third_elem(self, plugin_instance):
215
        if plugin_instance.history_enable():
216
            first_history_field = self.get_first_history_field(plugin_instance)
217
            self.maybe_assert_first_for_raw(plugin_instance, first_history_field)
218
219
            # Update stats (add third element)
220
            plugin_instance = self.update_stats(plugin_instance)
221
222
            self.maybe_assert_first_for_stats(plugin_instance, first_history_field)
223
224
        return first_history_field
0 ignored issues
show
introduced by
The variable first_history_field does not seem to be defined in case plugin_instance.history_enable() on line 215 is False. Are you sure this can never be the case?
Loading history...
225
226
    def check_views(self, plugin_instance, first_history_field):
227
        self.assertIsInstance(plugin_instance.get_views(), dict)
228
        if isinstance(plugin_instance.get_raw(), dict):
229
            self.assertIsInstance(plugin_instance.get_views(first_history_field), dict)
230
            self.assertTrue('decoration' in plugin_instance.get_views(first_history_field))
231
        elif isinstance(plugin_instance.get_raw(), list) and len(plugin_instance.get_raw()) > 0:
232
            first_history_field = plugin_instance.get_items_history_list()[0]['name']
233
            first_item = plugin_instance.get_raw()[0][plugin_instance.get_key()]
234
            self.assertIsInstance(plugin_instance.get_views(item=first_item, key=first_history_field), dict)
235
            self.assertTrue('decoration' in plugin_instance.get_views(item=first_item, key=first_history_field))
236
        self.assertIsInstance(json.loads(plugin_instance.get_json_views()), dict)
237
        self.assertEqual(json.loads(plugin_instance.get_json_views()), plugin_instance.get_views())
238
239
    def _common_plugin_tests(self, plugin):
240
        """Common method to test a Glances plugin
241
        This method is called multiple time by test 100 to 1xx"""
242
243
        # Reset all the stats, history and views
244
        plugin_instance = self.reset_stats_history_and_views(plugin)
245
246
        # Check before update
247
        self.do_checks_before_update(plugin_instance)
248
249
        # Update stats (add first element)
250
        plugin_instance = self.update_stats(plugin_instance)
251
252
        # Check stats
253
        self.check_stats(plugin_instance, plugin)
254
255
        # Filter stats
256
        self.filter_stats(plugin_instance)
257
258
        # Update stats (add second element)
259
        plugin_instance = self.update_stats(plugin_instance)
260
261
        # Check history
262
        first_history_field = self.chk_hist_maybe_add_third_elem(plugin_instance)
263
264
        # Check views
265
        self.check_views(plugin_instance, first_history_field)
266
267
    def test_000_update(self):
268
        """Update stats (mandatory step for all the stats).
269
270
        The update is made twice (for rate computation).
271
        """
272
        print('INFO: [TEST_000] Test the stats update function')
273
        try:
274
            stats.update()
275
        except Exception as e:
276
            print(f'ERROR: Stats update failed: {e}')
277
            self.assertTrue(False)
278
        time.sleep(1)
279
        try:
280
            stats.update()
281
        except Exception as e:
282
            print(f'ERROR: Stats update failed: {e}')
283
            self.assertTrue(False)
284
285
        self.assertTrue(True)
286
287
    def test_001_plugins(self):
288
        """Check mandatory plugins."""
289
        plugins_to_check = ['system', 'cpu', 'load', 'mem', 'memswap', 'network', 'diskio', 'fs']
290
        print('INFO: [TEST_001] Check the mandatory plugins list: {}'.format(', '.join(plugins_to_check)))
291
        plugins_list = stats.getPluginsList()
292
        for plugin in plugins_to_check:
293
            self.assertTrue(plugin in plugins_list)
294
295
    def test_002_system(self):
296
        """Check SYSTEM plugin."""
297
        stats_to_check = ['hostname', 'os_name']
298
        print('INFO: [TEST_002] Check SYSTEM stats: {}'.format(', '.join(stats_to_check)))
299
        stats_grab = stats.get_plugin('system').get_raw()
300
        for stat in stats_to_check:
301
            # Check that the key exist
302
            self.assertTrue(stat in stats_grab, msg=f'Cannot find key: {stat}')
303
        print(f'INFO: SYSTEM stats: {stats_grab}')
304
305
    def test_003_cpu(self):
306
        """Check CPU plugin."""
307
        stats_to_check = ['system', 'user', 'idle']
308
        print('INFO: [TEST_003] Check mandatory CPU stats: {}'.format(', '.join(stats_to_check)))
309
        stats_grab = stats.get_plugin('cpu').get_raw()
310
        for stat in stats_to_check:
311
            # Check that the key exist
312
            self.assertTrue(stat in stats_grab, msg=f'Cannot find key: {stat}')
313
            # Check that % is > 0 and < 100
314
            self.assertGreaterEqual(stats_grab[stat], 0)
315
            self.assertLessEqual(stats_grab[stat], 100)
316
        print(f'INFO: CPU stats: {stats_grab}')
317
318
    @unittest.skipIf(WINDOWS, "Load average not available on Windows")
319
    def test_004_load(self):
320
        """Check LOAD plugin."""
321
        stats_to_check = ['cpucore', 'min1', 'min5', 'min15']
322
        print('INFO: [TEST_004] Check LOAD stats: {}'.format(', '.join(stats_to_check)))
323
        stats_grab = stats.get_plugin('load').get_raw()
324
        for stat in stats_to_check:
325
            # Check that the key exist
326
            self.assertTrue(stat in stats_grab, msg=f'Cannot find key: {stat}')
327
            # Check that % is > 0
328
            self.assertGreaterEqual(stats_grab[stat], 0)
329
        print(f'INFO: LOAD stats: {stats_grab}')
330
331
    def test_005_mem(self):
332
        """Check MEM plugin."""
333
        plugin_name = 'mem'
334
        stats_to_check = ['available', 'used', 'free', 'total']
335
        print('INFO: [TEST_005] Check {} stats: {}'.format(plugin_name, ', '.join(stats_to_check)))
336
        stats_grab = stats.get_plugin('mem').get_raw()
337
        for stat in stats_to_check:
338
            # Check that the key exist
339
            self.assertTrue(stat in stats_grab, msg=f'Cannot find key: {stat}')
340
            # Check that % is > 0
341
            self.assertGreaterEqual(stats_grab[stat], 0)
342
        print(f'INFO: MEM stats: {stats_grab}')
343
344
    def test_006_memswap(self):
345
        """Check MEMSWAP plugin."""
346
        stats_to_check = ['used', 'free', 'total']
347
        print('INFO: [TEST_006] Check MEMSWAP stats: {}'.format(', '.join(stats_to_check)))
348
        stats_grab = stats.get_plugin('memswap').get_raw()
349
        for stat in stats_to_check:
350
            # Check that the key exist
351
            self.assertTrue(stat in stats_grab, msg=f'Cannot find key: {stat}')
352
            # Check that % is > 0
353
            self.assertGreaterEqual(stats_grab[stat], 0)
354
        print(f'INFO: MEMSWAP stats: {stats_grab}')
355
356
    def test_007_network(self):
357
        """Check NETWORK plugin."""
358
        print('INFO: [TEST_007] Check NETWORK stats')
359
        stats_grab = stats.get_plugin('network').get_raw()
360
        self.assertTrue(isinstance(stats_grab, list), msg='Network stats is not a list')
361
        print(f'INFO: NETWORK stats: {stats_grab}')
362
363
    def test_008_diskio(self):
364
        """Check DISKIO plugin."""
365
        print('INFO: [TEST_008] Check DISKIO stats')
366
        stats_grab = stats.get_plugin('diskio').get_raw()
367
        self.assertTrue(isinstance(stats_grab, list), msg='DiskIO stats is not a list')
368
        print(f'INFO: diskio stats: {stats_grab}')
369
370
    def test_009_fs(self):
371
        """Check File System plugin."""
372
        # stats_to_check = [ ]
373
        print('INFO: [TEST_009] Check FS stats')
374
        stats_grab = stats.get_plugin('fs').get_raw()
375
        self.assertTrue(isinstance(stats_grab, list), msg='FileSystem stats is not a list')
376
        print(f'INFO: FS stats: {stats_grab}')
377
378
    def test_010_processes(self):
379
        """Check Process plugin."""
380
        # stats_to_check = [ ]
381
        print('INFO: [TEST_010] Check PROCESS stats')
382
        stats_grab = stats.get_plugin('processcount').get_raw()
383
        # total = stats_grab['total']
384
        self.assertTrue(isinstance(stats_grab, dict), msg='Process count stats is not a dict')
385
        print(f'INFO: PROCESS count stats: {stats_grab}')
386
        stats_grab = stats.get_plugin('processlist').get_raw()
387
        self.assertTrue(isinstance(stats_grab, list), msg='Process count stats is not a list')
388
        print(f'INFO: PROCESS list stats: {len(stats_grab)} items in the list')
389
        # Check if number of processes in the list equal counter
390
        # self.assertEqual(total, len(stats_grab))
391
392
    def test_011_folders(self):
393
        """Check File System plugin."""
394
        # stats_to_check = [ ]
395
        print('INFO: [TEST_011] Check FOLDER stats')
396
        stats_grab = stats.get_plugin('folders').get_raw()
397
        self.assertTrue(isinstance(stats_grab, list), msg='Folders stats is not a list')
398
        print(f'INFO: Folders stats: {stats_grab}')
399
400
    def test_012_ip(self):
401
        """Check IP plugin."""
402
        print('INFO: [TEST_012] Check IP stats')
403
        stats_grab = stats.get_plugin('ip').get_raw()
404
        self.assertTrue(isinstance(stats_grab, dict), msg='IP stats is not a dict')
405
        print(f'INFO: IP stats: {stats_grab}')
406
407
    @unittest.skipIf(not LINUX, "IRQs available only on Linux")
408
    def test_013_irq(self):
409
        """Check IRQ plugin."""
410
        print('INFO: [TEST_013] Check IRQ stats')
411
        stats_grab = stats.get_plugin('irq').get_raw()
412
        self.assertTrue(isinstance(stats_grab, list), msg='IRQ stats is not a list')
413
        print(f'INFO: IRQ stats: {stats_grab}')
414
415
    @unittest.skipIf(not LINUX, "GPU available only on Linux")
416
    def test_014_gpu(self):
417
        """Check GPU plugin."""
418
        print('INFO: [TEST_014] Check GPU stats')
419
        stats_grab = stats.get_plugin('gpu').get_raw()
420
        self.assertTrue(isinstance(stats_grab, list), msg='GPU stats is not a list')
421
        print(f'INFO: GPU stats: {stats_grab}')
422
423
    def test_015_sorted_stats(self):
424
        """Check sorted stats method."""
425
        print('INFO: [TEST_015] Check sorted stats method')
426
        aliases = {
427
            "key2": "alias11",
428
            "key5": "alias2",
429
        }
430
        unsorted_stats = [
431
            {"key": "key4"},
432
            {"key": "key2"},
433
            {"key": "key5"},
434
            {"key": "key21"},
435
            {"key": "key3"},
436
        ]
437
438
        gp = GlancesPluginModel()
439
        gp.get_key = lambda: "key"
440
        gp.has_alias = aliases.get
441
        gp.stats = unsorted_stats
442
443
        sorted_stats = gp.sorted_stats()
444
        self.assertEqual(len(sorted_stats), 5)
445
        self.assertEqual(sorted_stats[0]["key"], "key5")
446
        self.assertEqual(sorted_stats[1]["key"], "key2")
447
        self.assertEqual(sorted_stats[2]["key"], "key3")
448
        self.assertEqual(sorted_stats[3]["key"], "key4")
449
        self.assertEqual(sorted_stats[4]["key"], "key21")
450
451
    def test_016_subsample(self):
452
        """Test subsampling function."""
453
        print('INFO: [TEST_016] Subsampling')
454
        for l_test in [
455
            ([1, 2, 3], 4),
456
            ([1, 2, 3, 4], 4),
457
            ([1, 2, 3, 4, 5, 6, 7], 4),
458
            ([1, 2, 3, 4, 5, 6, 7, 8], 4),
459
            (list(range(1, 800)), 4),
460
            (list(range(1, 8000)), 800),
461
        ]:
462
            l_subsample = subsample(l_test[0], l_test[1])
463
            self.assertLessEqual(len(l_subsample), l_test[1])
464
465
    def test_017_hddsmart(self):
466
        """Check hard disk SMART data plugin."""
467
        try:
468
            from glances.globals import is_admin
469
        except ImportError:
470
            print("INFO: [TEST_017] pySMART not found, not running SMART plugin test")
471
            return
472
473
        stat = 'DeviceName'
474
        print(f'INFO: [TEST_017] Check SMART stats: {stat}')
475
        stats_grab = stats.get_plugin('smart').get_raw()
476
        if not is_admin():
477
            print("INFO: Not admin, SMART list should be empty")
478
            assert len(stats_grab) == 0
479
        elif stats_grab == {}:
480
            print("INFO: Admin but SMART list is empty")
481
            assert len(stats_grab) == 0
482
        else:
483
            print(stats_grab)
484
            self.assertTrue(stat in stats_grab[0].keys(), msg=f'Cannot find key: {stat}')
485
486
        print(f'INFO: SMART stats: {stats_grab}')
487
488
    def test_017_programs(self):
489
        """Check Programs function (it's not a plugin)."""
490
        # stats_to_check = [ ]
491
        print('INFO: [TEST_017] Check PROGRAM stats')
492
        stats_grab = processes_to_programs(stats.get_plugin('processlist').get_raw())
493
        self.assertIsInstance(stats_grab, list, msg='Programs stats list is not a list')
494
        self.assertIsInstance(stats_grab[0], dict, msg='First item should be a dict')
495
496
    def test_018_string_value_to_float(self):
497
        """Check string_value_to_float function"""
498
        print('INFO: [TEST_018] Check string_value_to_float function')
499
        self.assertEqual(string_value_to_float('32kB'), 32000.0)
500
        self.assertEqual(string_value_to_float('32 KB'), 32000.0)
501
        self.assertEqual(string_value_to_float('15.5MB'), 15500000.0)
502
        self.assertEqual(string_value_to_float('25.9'), 25.9)
503
        self.assertEqual(string_value_to_float('12'), 12)
504
        self.assertEqual(string_value_to_float('--'), None)
505
506
    def test_019_events(self):
507
        """Test events class"""
508
        print('INFO: [TEST_019] Test events')
509
        # Init events
510
        events = GlancesEventsList(max_events=5, min_duration=1, min_interval=3)
511
        # Minimal event duration not reached
512
        events.add('WARNING', 'LOAD', 4)
513
        events.add('CRITICAL', 'LOAD', 5)
514
        events.add('OK', 'LOAD', 1)
515
        self.assertEqual(len(events.get()), 0)
516
        # Minimal event duration LOAD reached
517
        events.add('WARNING', 'LOAD', 4)
518
        time.sleep(1)
519
        events.add('CRITICAL', 'LOAD', 5)
520
        time.sleep(1)
521
        events.add('OK', 'LOAD', 1)
522
        self.assertEqual(len(events.get()), 1)
523
        self.assertEqual(events.get()[0]['type'], 'LOAD')
524
        self.assertEqual(events.get()[0]['state'], 'CRITICAL')
525
        self.assertEqual(events.get()[0]['max'], 5)
526
        # Minimal event duration CPU reached
527
        events.add('WARNING', 'CPU', 60)
528
        time.sleep(1)
529
        events.add('WARNING', 'CPU', 70)
530
        time.sleep(1)
531
        events.add('OK', 'CPU', 10)
532
        self.assertEqual(len(events.get()), 2)
533
        self.assertEqual(events.get()[0]['type'], 'CPU')
534
        self.assertEqual(events.get()[0]['state'], 'WARNING')
535
        self.assertEqual(events.get()[0]['min'], 60)
536
        self.assertEqual(events.get()[0]['max'], 70)
537
        self.assertEqual(events.get()[0]['count'], 2)
538
        # Minimal event duration CPU reached (again)
539
        # but time between two events (min_interval) is too short
540
        # a merge will be done
541
        time.sleep(0.5)
542
        events.add('WARNING', 'CPU', 60)
543
        time.sleep(1)
544
        events.add('WARNING', 'CPU', 80)
545
        time.sleep(1)
546
        events.add('OK', 'CPU', 10)
547
        self.assertEqual(len(events.get()), 2)
548
        self.assertEqual(events.get()[0]['type'], 'CPU')
549
        self.assertEqual(events.get()[0]['state'], 'WARNING')
550
        self.assertEqual(events.get()[0]['min'], 60)
551
        self.assertEqual(events.get()[0]['max'], 80)
552
        self.assertEqual(events.get()[0]['count'], 4)
553
        # Clean WARNING events
554
        events.clean()
555
        self.assertEqual(len(events.get()), 1)
556
557
    def test_020_filter(self):
558
        """Test filter classes"""
559
        print('INFO: [TEST_020] Test filter')
560
        gf = GlancesFilter()
561
        gf.filter = '.*python.*'
562
        self.assertEqual(gf.filter, '.*python.*')
563
        self.assertEqual(gf.filter_key, None)
564
        self.assertTrue(gf.is_filtered({'name': 'python'}))
565
        self.assertTrue(gf.is_filtered({'name': '/usr/bin/python -m glances'}))
566
        self.assertFalse(gf.is_filtered({'noname': 'python'}))
567
        self.assertFalse(gf.is_filtered({'name': 'snake'}))
568
        gf.filter = 'username:nicolargo'
569
        self.assertEqual(gf.filter, 'nicolargo')
570
        self.assertEqual(gf.filter_key, 'username')
571
        self.assertTrue(gf.is_filtered({'username': 'nicolargo'}))
572
        self.assertFalse(gf.is_filtered({'username': 'notme'}))
573
        self.assertFalse(gf.is_filtered({'notuser': 'nicolargo'}))
574
        gfl = GlancesFilterList()
575
        gfl.filter = '.*python.*,username:nicolargo'
576
        self.assertTrue(gfl.is_filtered({'name': 'python is in the place'}))
577
        self.assertFalse(gfl.is_filtered({'name': 'snake is in the place'}))
578
        self.assertTrue(gfl.is_filtered({'name': 'snake is in the place', 'username': 'nicolargo'}))
579
        self.assertFalse(gfl.is_filtered({'name': 'snake is in the place', 'username': 'notme'}))
580
581
    def test_094_thresholds(self):
582
        """Test thresholds classes"""
583
        print('INFO: [TEST_094] Thresholds')
584
        ok = GlancesThresholdOk()
585
        careful = GlancesThresholdCareful()
586
        warning = GlancesThresholdWarning()
587
        critical = GlancesThresholdCritical()
588
        self.assertTrue(ok < careful)
589
        self.assertTrue(careful < warning)
590
        self.assertTrue(warning < critical)
591
        self.assertFalse(ok > careful)
592
        self.assertEqual(ok, ok)
593
        self.assertEqual(str(ok), 'OK')
594
        thresholds = GlancesThresholds()
595
        thresholds.add('cpu_percent', 'OK')
596
        self.assertEqual(thresholds.get(stat_name='cpu_percent').description(), 'OK')
597
598
    def test_095_methods(self):
599
        """Test mandatories methods"""
600
        print('INFO: [TEST_095] Mandatories methods')
601
        mandatories_methods = ['reset', 'update']
602
        plugins_list = stats.getPluginsList()
603
        for plugin in plugins_list:
604
            for method in mandatories_methods:
605
                self.assertTrue(hasattr(stats.get_plugin(plugin), method), msg=f'{plugin} has no method {method}()')
606
607
    def test_096_views(self):
608
        """Test get_views method"""
609
        print('INFO: [TEST_096] Test views')
610
        plugins_list = stats.getPluginsList()
611
        for plugin in plugins_list:
612
            stats.get_plugin(plugin).get_raw()
613
            views_grab = stats.get_plugin(plugin).get_views()
614
            self.assertTrue(isinstance(views_grab, dict), msg=f'{plugin} view is not a dict')
615
616
    def test_097_attribute(self):
617
        """Test GlancesAttribute classes"""
618
        print('INFO: [TEST_097] Test attribute')
619
        # GlancesAttribute
620
        from glances.attribute import GlancesAttribute
621
622
        a = GlancesAttribute('a', description='ad', history_max_size=3)
623
        self.assertEqual(a.name, 'a')
624
        self.assertEqual(a.description, 'ad')
625
        a.description = 'adn'
626
        self.assertEqual(a.description, 'adn')
627
        a.value = 1
628
        a.value = 2
629
        self.assertEqual(len(a.history), 2)
630
        a.value = 3
631
        self.assertEqual(len(a.history), 3)
632
        a.value = 4
633
        # Check if history_max_size=3 is OK
634
        self.assertEqual(len(a.history), 3)
635
        self.assertEqual(a.history_size(), 3)
636
        self.assertEqual(a.history_len(), 3)
637
        self.assertEqual(a.history_value()[1], 4)
638
        self.assertEqual(a.history_mean(nb=3), 4.5)
639
640
    def test_098_history(self):
641
        """Test GlancesHistory classes"""
642
        print('INFO: [TEST_098] Test history')
643
        # GlancesHistory
644
        from glances.history import GlancesHistory
645
646
        h = GlancesHistory()
647
        h.add('a', 1, history_max_size=100)
648
        h.add('a', 2, history_max_size=100)
649
        h.add('a', 3, history_max_size=100)
650
        h.add('b', 10, history_max_size=100)
651
        h.add('b', 20, history_max_size=100)
652
        h.add('b', 30, history_max_size=100)
653
        self.assertEqual(len(h.get()), 2)
654
        self.assertEqual(len(h.get()['a']), 3)
655
        h.reset()
656
        self.assertEqual(len(h.get()), 2)
657
        self.assertEqual(len(h.get()['a']), 0)
658
659
    def test_099_output_bars(self):
660
        """Test quick look plugin.
661
662
        > bar.min_value
663
        0
664
        > bar.max_value
665
        100
666
        > bar.percent = -1
667
        > bar.percent
668
        0
669
        """
670
        print('INFO: [TEST_099] Test progress bar')
671
672
        bar = Bar(size=1)
673
        # Percent value can not be lower than min_value
674
        bar.percent = -1
675
        self.assertLessEqual(bar.percent, bar.min_value)
676
        # but... percent value can be higher than max_value
677
        bar.percent = 101
678
        self.assertLessEqual(bar.percent, 101)
679
680
        # Test display
681
        bar = Bar(size=50)
682
        bar.percent = 0
683
        self.assertEqual(bar.get(), '                                              0.0%')
684
        bar.percent = 70
685
        self.assertEqual(bar.get(), '|||||||||||||||||||||||||||||||              70.0%')
686
        bar.percent = 100
687
        self.assertEqual(bar.get(), '||||||||||||||||||||||||||||||||||||||||||||  100%')
688
        bar.percent = 110
689
        self.assertEqual(bar.get(), '|||||||||||||||||||||||||||||||||||||||||||| >100%')
690
691
    # Error in Github Action. Do not remove the comment.
692
    # def test_100_system_plugin_method(self):
693
    #     """Test system plugin methods"""
694
    #     print('INFO: [TEST_100] Test system plugin methods')
695
    #     self._common_plugin_tests('system')
696
697
    def test_101_cpu_plugin_method(self):
698
        """Test cpu plugin methods"""
699
        print('INFO: [TEST_100] Test cpu plugin methods')
700
        self._common_plugin_tests('cpu')
701
702
    @unittest.skipIf(WINDOWS, "Load average not available on Windows")
703
    def test_102_load_plugin_method(self):
704
        """Test load plugin methods"""
705
        print('INFO: [TEST_102] Test load plugin methods')
706
        self._common_plugin_tests('load')
707
708
    def test_103_mem_plugin_method(self):
709
        """Test mem plugin methods"""
710
        print('INFO: [TEST_103] Test mem plugin methods')
711
        self._common_plugin_tests('mem')
712
713
    def test_104_memswap_plugin_method(self):
714
        """Test memswap plugin methods"""
715
        print('INFO: [TEST_104] Test memswap plugin methods')
716
        self._common_plugin_tests('memswap')
717
718
    def test_105_network_plugin_method(self):
719
        """Test network plugin methods"""
720
        print('INFO: [TEST_105] Test network plugin methods')
721
        self._common_plugin_tests('network')
722
723
    # Error in Github Action. Do not remove the comment.
724
    # def test_106_diskio_plugin_method(self):
725
    #     """Test diskio plugin methods"""
726
    #     print('INFO: [TEST_106] Test diskio plugin methods')
727
    #     self._common_plugin_tests('diskio')
728
729
    def test_107_fs_plugin_method(self):
730
        """Test fs plugin methods"""
731
        print('INFO: [TEST_107] Test fs plugin methods')
732
        self._common_plugin_tests('fs')
733
734
    def test_700_secure(self):
735
        """Test secure functions"""
736
        print('INFO: [TEST_700] Secure functions')
737
738
        if WINDOWS:
739
            self.assertIn(secure_popen('echo TEST'), ['TEST\n', 'TEST\r\n'])
740
            self.assertIn(secure_popen('echo TEST1 && echo TEST2'), ['TEST1\nTEST2\n', 'TEST1\r\nTEST2\r\n'])
741
        else:
742
            self.assertEqual(secure_popen('echo -n TEST'), 'TEST')
743
            self.assertEqual(secure_popen('echo -n TEST1 && echo -n TEST2'), 'TEST1TEST2')
744
            # Make the test failed on Github (AssertionError: '' != 'FOO\n')
745
            # but not on my localLinux computer...
746
            # self.assertEqual(secure_popen('echo FOO | grep FOO'), 'FOO\n')
747
748
    def test_800_memory_leak(self):
749
        """Memory leak check"""
750
        import tracemalloc
751
752
        print('INFO: [TEST_800] Memory leak check')
753
        tracemalloc.start()
754
        # 3 iterations just to init the stats and fill the memory
755
        for _ in range(3):
756
            stats.update()
757
758
        # Start the memory leak check
759
        snapshot_begin = tracemalloc.take_snapshot()
760
        for _ in range(3):
761
            stats.update()
762
        snapshot_end = tracemalloc.take_snapshot()
763
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
764
        memory_leak = sum([s.size_diff for s in snapshot_diff])
765
        print(f'INFO: Memory leak: {memory_leak} bytes')
766
767
        # snapshot_begin = tracemalloc.take_snapshot()
768
        for _ in range(30):
769
            stats.update()
770
        snapshot_end = tracemalloc.take_snapshot()
771
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
772
        memory_leak = sum([s.size_diff for s in snapshot_diff])
773
        print(f'INFO: Memory leak: {memory_leak} bytes')
774
775
        # snapshot_begin = tracemalloc.take_snapshot()
776
        for _ in range(300):
777
            stats.update()
778
        snapshot_end = tracemalloc.take_snapshot()
779
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
780
        memory_leak = sum([s.size_diff for s in snapshot_diff])
781
        print(f'INFO: Memory leak: {memory_leak} bytes')
782
        snapshot_top = snapshot_end.compare_to(snapshot_begin, 'traceback')
783
        print("Memory consumption (top 5):")
784
        for stat in snapshot_top[:5]:
785
            print(stat)
786
            for line in stat.traceback.format():
787
                print(line)
788
789
    def test_999_the_end(self):
790
        """Free all the stats"""
791
        print('INFO: [TEST_999] Free the stats')
792
        stats.end()
793
        self.assertTrue(True)
794
795
796
if __name__ == '__main__':
797
    unittest.main()
798