1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# 4# Glances - An eye on your system 5# 6# Copyright (C) 2019 Nicolargo <nicolas@nicolargo.com> 7# 8# Glances is free software; you can redistribute it and/or modify 9# it under the terms of the GNU Lesser General Public License as published by 10# the Free Software Foundation, either version 3 of the License, or 11# (at your option) any later version. 12# 13# Glances is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU Lesser General Public License for more details. 17# 18# You should have received a copy of the GNU Lesser General Public License 19# along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21"""Glances unitary tests suite.""" 22 23import time 24import unittest 25 26from glances.main import GlancesMain 27from glances.stats import GlancesStats 28from glances import __version__ 29from glances.globals import WINDOWS, LINUX 30from glances.outputs.glances_bars import Bar 31from glances.thresholds import GlancesThresholdOk 32from glances.thresholds import GlancesThresholdCareful 33from glances.thresholds import GlancesThresholdWarning 34from glances.thresholds import GlancesThresholdCritical 35from glances.thresholds import GlancesThresholds 36from glances.plugins.glances_plugin import GlancesPlugin 37from glances.compat import subsample, range 38 39# Global variables 40# ================= 41 42 43# Init Glances core 44core = GlancesMain() 45 46# Init Glances stats 47stats = GlancesStats(config=core.get_config(), 48 args=core.get_args()) 49 50# Unitest class 51# ============== 52print('Unitary tests for Glances %s' % __version__) 53 54 55class TestGlances(unittest.TestCase): 56 """Test Glances class.""" 57 58 def setUp(self): 59 """The function is called *every time* before test_*.""" 60 print('\n' + '=' * 78) 61 62 def test_000_update(self): 63 """Update stats (mandatory step for all the stats). 64 65 The update is made twice (for rate computation). 66 """ 67 print('INFO: [TEST_000] Test the stats update function') 68 try: 69 stats.update() 70 except Exception as e: 71 print('ERROR: Stats update failed: %s' % e) 72 self.assertTrue(False) 73 time.sleep(1) 74 try: 75 stats.update() 76 except Exception as e: 77 print('ERROR: Stats update failed: %s' % e) 78 self.assertTrue(False) 79 80 self.assertTrue(True) 81 82 def test_001_plugins(self): 83 """Check mandatory plugins.""" 84 plugins_to_check = ['system', 'cpu', 'load', 'mem', 'memswap', 'network', 'diskio', 'fs', 'irq'] 85 print('INFO: [TEST_001] Check the mandatory plugins list: %s' % ', '.join(plugins_to_check)) 86 plugins_list = stats.getPluginsList() 87 for plugin in plugins_to_check: 88 self.assertTrue(plugin in plugins_list) 89 90 def test_002_system(self): 91 """Check SYSTEM plugin.""" 92 stats_to_check = ['hostname', 'os_name'] 93 print('INFO: [TEST_002] Check SYSTEM stats: %s' % ', '.join(stats_to_check)) 94 stats_grab = stats.get_plugin('system').get_raw() 95 for stat in stats_to_check: 96 # Check that the key exist 97 self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) 98 print('INFO: SYSTEM stats: %s' % stats_grab) 99 100 def test_003_cpu(self): 101 """Check CPU plugin.""" 102 stats_to_check = ['system', 'user', 'idle'] 103 print('INFO: [TEST_003] Check mandatory CPU stats: %s' % ', '.join(stats_to_check)) 104 stats_grab = stats.get_plugin('cpu').get_raw() 105 for stat in stats_to_check: 106 # Check that the key exist 107 self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) 108 # Check that % is > 0 and < 100 109 self.assertGreaterEqual(stats_grab[stat], 0) 110 self.assertLessEqual(stats_grab[stat], 100) 111 print('INFO: CPU stats: %s' % stats_grab) 112 113 @unittest.skipIf(WINDOWS, "Load average not available on Windows") 114 def test_004_load(self): 115 """Check LOAD plugin.""" 116 stats_to_check = ['cpucore', 'min1', 'min5', 'min15'] 117 print('INFO: [TEST_004] Check LOAD stats: %s' % ', '.join(stats_to_check)) 118 stats_grab = stats.get_plugin('load').get_raw() 119 for stat in stats_to_check: 120 # Check that the key exist 121 self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) 122 # Check that % is > 0 123 self.assertGreaterEqual(stats_grab[stat], 0) 124 print('INFO: LOAD stats: %s' % stats_grab) 125 126 def test_005_mem(self): 127 """Check MEM plugin.""" 128 stats_to_check = ['available', 'used', 'free', 'total'] 129 print('INFO: [TEST_005] Check MEM stats: %s' % ', '.join(stats_to_check)) 130 stats_grab = stats.get_plugin('mem').get_raw() 131 for stat in stats_to_check: 132 # Check that the key exist 133 self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) 134 # Check that % is > 0 135 self.assertGreaterEqual(stats_grab[stat], 0) 136 print('INFO: MEM stats: %s' % stats_grab) 137 138 def test_006_swap(self): 139 """Check MEMSWAP plugin.""" 140 stats_to_check = ['used', 'free', 'total'] 141 print('INFO: [TEST_006] Check SWAP stats: %s' % ', '.join(stats_to_check)) 142 stats_grab = stats.get_plugin('memswap').get_raw() 143 for stat in stats_to_check: 144 # Check that the key exist 145 self.assertTrue(stat in stats_grab, msg='Cannot find key: %s' % stat) 146 # Check that % is > 0 147 self.assertGreaterEqual(stats_grab[stat], 0) 148 print('INFO: SWAP stats: %s' % stats_grab) 149 150 def test_007_network(self): 151 """Check NETWORK plugin.""" 152 print('INFO: [TEST_007] Check NETWORK stats') 153 stats_grab = stats.get_plugin('network').get_raw() 154 self.assertTrue(type(stats_grab) is list, msg='Network stats is not a list') 155 print('INFO: NETWORK stats: %s' % stats_grab) 156 157 def test_008_diskio(self): 158 """Check DISKIO plugin.""" 159 print('INFO: [TEST_008] Check DISKIO stats') 160 stats_grab = stats.get_plugin('diskio').get_raw() 161 self.assertTrue(type(stats_grab) is list, msg='DiskIO stats is not a list') 162 print('INFO: diskio stats: %s' % stats_grab) 163 164 def test_009_fs(self): 165 """Check File System plugin.""" 166 # stats_to_check = [ ] 167 print('INFO: [TEST_009] Check FS stats') 168 stats_grab = stats.get_plugin('fs').get_raw() 169 self.assertTrue(type(stats_grab) is list, msg='FileSystem stats is not a list') 170 print('INFO: FS stats: %s' % stats_grab) 171 172 def test_010_processes(self): 173 """Check Process plugin.""" 174 # stats_to_check = [ ] 175 print('INFO: [TEST_010] Check PROCESS stats') 176 stats_grab = stats.get_plugin('processcount').get_raw() 177 # total = stats_grab['total'] 178 self.assertTrue(type(stats_grab) is dict, msg='Process count stats is not a dict') 179 print('INFO: PROCESS count stats: %s' % stats_grab) 180 stats_grab = stats.get_plugin('processlist').get_raw() 181 self.assertTrue(type(stats_grab) is list, msg='Process count stats is not a list') 182 print('INFO: PROCESS list stats: %s items in the list' % len(stats_grab)) 183 # Check if number of processes in the list equal counter 184 # self.assertEqual(total, len(stats_grab)) 185 186 def test_011_folders(self): 187 """Check File System plugin.""" 188 # stats_to_check = [ ] 189 print('INFO: [TEST_011] Check FOLDER stats') 190 stats_grab = stats.get_plugin('folders').get_raw() 191 self.assertTrue(type(stats_grab) is list, msg='Folders stats is not a list') 192 print('INFO: Folders stats: %s' % stats_grab) 193 194 def test_012_ip(self): 195 """Check IP plugin.""" 196 print('INFO: [TEST_012] Check IP stats') 197 stats_grab = stats.get_plugin('ip').get_raw() 198 self.assertTrue(type(stats_grab) is dict, msg='IP stats is not a dict') 199 print('INFO: IP stats: %s' % stats_grab) 200 201 @unittest.skipIf(not LINUX, "IRQs available only on Linux") 202 def test_013_irq(self): 203 """Check IRQ plugin.""" 204 print('INFO: [TEST_013] Check IRQ stats') 205 stats_grab = stats.get_plugin('irq').get_raw() 206 self.assertTrue(type(stats_grab) is list, msg='IRQ stats is not a list') 207 print('INFO: IRQ stats: %s' % stats_grab) 208 209 @unittest.skipIf(not LINUX, "GPU available only on Linux") 210 def test_013_gpu(self): 211 """Check GPU plugin.""" 212 print('INFO: [TEST_014] Check GPU stats') 213 stats_grab = stats.get_plugin('gpu').get_raw() 214 self.assertTrue(type(stats_grab) is list, msg='GPU stats is not a list') 215 print('INFO: GPU stats: %s' % stats_grab) 216 217 def test_014_sorted_stats(self): 218 """Check sorted stats method.""" 219 print('INFO: [TEST_015] Check sorted stats method') 220 aliases = { 221 "key2": "alias11", 222 "key5": "alias2", 223 } 224 unsorted_stats = [ 225 {"key": "key4"}, 226 {"key": "key2"}, 227 {"key": "key5"}, 228 {"key": "key21"}, 229 {"key": "key3"}, 230 ] 231 232 gp = GlancesPlugin() 233 gp.get_key = lambda: "key" 234 gp.has_alias = aliases.get 235 gp.stats = unsorted_stats 236 237 sorted_stats = gp.sorted_stats() 238 self.assertEqual(len(sorted_stats), 5) 239 self.assertEqual(sorted_stats[0]["key"], "key5") 240 self.assertEqual(sorted_stats[1]["key"], "key2") 241 self.assertEqual(sorted_stats[2]["key"], "key3") 242 self.assertEqual(sorted_stats[3]["key"], "key4") 243 self.assertEqual(sorted_stats[4]["key"], "key21") 244 245 def test_015_subsample(self): 246 """Test subsampling function.""" 247 print('INFO: [TEST_015] Subsampling') 248 for l in [([1, 2, 3], 4), 249 ([1, 2, 3, 4], 4), 250 ([1, 2, 3, 4, 5, 6, 7], 4), 251 ([1, 2, 3, 4, 5, 6, 7, 8], 4), 252 (list(range(1, 800)), 4), 253 (list(range(1, 8000)), 800)]: 254 l_subsample = subsample(l[0], l[1]) 255 self.assertLessEqual(len(l_subsample), l[1]) 256 257 def test_016_hddsmart(self): 258 """Check hard disk SMART data plugin.""" 259 try: 260 from glances.compat import is_admin 261 except ImportError: 262 print("INFO: [TEST_016] pySMART not found, not running SMART plugin test") 263 return 264 265 stat = 'DeviceName' 266 print('INFO: [TEST_016] Check SMART stats: {}'.format(stat)) 267 stats_grab = stats.get_plugin('smart').get_raw() 268 if not is_admin(): 269 print("INFO: Not admin, SMART list should be empty") 270 assert len(stats_grab) == 0 271 elif stats_grab == {}: 272 print("INFO: Admin but SMART list is empty") 273 assert len(stats_grab) == 0 274 else: 275 print(stats_grab) 276 self.assertTrue(stat in stats_grab[0].keys(), msg='Cannot find key: %s' % stat) 277 278 print('INFO: SMART stats: %s' % stats_grab) 279 280 def test_094_thresholds(self): 281 """Test thresholds classes""" 282 print('INFO: [TEST_094] Thresholds') 283 ok = GlancesThresholdOk() 284 careful = GlancesThresholdCareful() 285 warning = GlancesThresholdWarning() 286 critical = GlancesThresholdCritical() 287 self.assertTrue(ok < careful) 288 self.assertTrue(careful < warning) 289 self.assertTrue(warning < critical) 290 self.assertFalse(ok > careful) 291 self.assertEqual(ok, ok) 292 self.assertEqual(str(ok), 'OK') 293 thresholds = GlancesThresholds() 294 thresholds.add('cpu_percent', 'OK') 295 self.assertEqual(thresholds.get(stat_name='cpu_percent').description(), 'OK') 296 297 def test_095_methods(self): 298 """Test mandatories methods""" 299 print('INFO: [TEST_095] Mandatories methods') 300 mandatories_methods = ['reset', 'update'] 301 plugins_list = stats.getPluginsList() 302 for plugin in plugins_list: 303 for method in mandatories_methods: 304 self.assertTrue(hasattr(stats.get_plugin(plugin), method), 305 msg='{} has no method {}()'.format(plugin, method)) 306 307 def test_096_views(self): 308 """Test get_views method""" 309 print('INFO: [TEST_096] Test views') 310 plugins_list = stats.getPluginsList() 311 for plugin in plugins_list: 312 stats_grab = stats.get_plugin(plugin).get_raw() 313 views_grab = stats.get_plugin(plugin).get_views() 314 self.assertTrue(type(views_grab) is dict, 315 msg='{} view is not a dict'.format(plugin)) 316 317 def test_097_attribute(self): 318 """Test GlancesAttribute classe""" 319 print('INFO: [TEST_097] Test attribute') 320 # GlancesAttribute 321 from glances.attribute import GlancesAttribute 322 a = GlancesAttribute('a', description='ad', history_max_size=3) 323 self.assertEqual(a.name, 'a') 324 self.assertEqual(a.description, 'ad') 325 a.description = 'adn' 326 self.assertEqual(a.description, 'adn') 327 a.value = 1 328 a.value = 2 329 self.assertEqual(len(a.history), 2) 330 a.value = 3 331 self.assertEqual(len(a.history), 3) 332 a.value = 4 333 # Check if history_max_size=3 is OK 334 self.assertEqual(len(a.history), 3) 335 self.assertEqual(a.history_size(), 3) 336 self.assertEqual(a.history_len(), 3) 337 self.assertEqual(a.history_value()[1], 4) 338 self.assertEqual(a.history_mean(nb=3), 4.5) 339 340 def test_098_history(self): 341 """Test GlancesHistory classe""" 342 print('INFO: [TEST_098] Test history') 343 # GlancesHistory 344 from glances.history import GlancesHistory 345 h = GlancesHistory() 346 h.add('a', 1) 347 h.add('a', 2) 348 h.add('a', 3) 349 h.add('b', 10) 350 h.add('b', 20) 351 h.add('b', 30) 352 self.assertEqual(len(h.get()), 2) 353 self.assertEqual(len(h.get()['a']), 3) 354 h.reset() 355 self.assertEqual(len(h.get()), 2) 356 self.assertEqual(len(h.get()['a']), 0) 357 358 def test_099_output_bars_must_be_between_0_and_100_percent(self): 359 """Test quick look plugin. 360 361 > bar.min_value 362 0 363 > bar.max_value 364 100 365 > bar.percent = -1 366 > bar.percent 367 0 368 > bar.percent = 101 369 > bar.percent 370 100 371 """ 372 print('INFO: [TEST_099] Test progress bar') 373 bar = Bar(size=1) 374 bar.percent = -1 375 self.assertLessEqual(bar.percent, bar.min_value) 376 bar.percent = 101 377 self.assertGreaterEqual(bar.percent, bar.max_value) 378 379 def test_999_the_end(self): 380 """Free all the stats""" 381 print('INFO: [TEST_999] Free the stats') 382 stats.end() 383 self.assertTrue(True) 384 385 386if __name__ == '__main__': 387 unittest.main() 388