test_core.TestGlances.test_098_history()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 18
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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