Test Failed
Push — master ( ce0fc3...e09530 )
by Nicolas
03:36
created

unittest-core.TestGlances._common_plugin_tests()   F

Complexity

Conditions 27

Size

Total Lines 115
Code Lines 87

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
eloc 87
nop 2
dl 0
loc 115
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

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