Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions glances/plugins/quicklook/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@
{'name': 'mem', 'description': 'MEM percent usage', 'y_unit': '%'},
{'name': 'swap', 'description': 'SWAP percent usage', 'y_unit': '%'},
{'name': 'load', 'description': 'LOAD percent usage', 'y_unit': '%'},
{'name': 'gpu_mem', 'description': 'GPU memory percent usage', 'y_unit': '%'},
{'name': 'gpu_proc', 'description': 'GPU processor percent usage', 'y_unit': '%'},
]


Expand Down
62 changes: 62 additions & 0 deletions tests/test_plugin_quicklook.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""Tests for the Quicklook plugin stats list configuration."""

import os
from argparse import Namespace

import pytest

Expand Down Expand Up @@ -224,3 +225,64 @@ def test_internal_spaces_are_kept(self, tmp_path):
plugin = QuicklookPlugin(args=None, config=Config(config_dir=os.fspath(config_file)))

assert plugin.get_limits('alias') == ['sda1:System Disk', 'sdb1:Data Disk']


class TestQuicklookGpuHistory:
"""`gpu_mem` and `gpu_proc` can be listed, so --sparkline must find a history for them.

Only the items in `items_history_list` are historised; for any other key
`get_raw_history()` returns None, and the sparkline branch of `_msg_cpu` iterates
over it: `[quicklook] list=cpu,gpu_mem` with --sparkline crashed the curses UI
with "'NoneType' object is not iterable".
"""

@staticmethod
def _plugin(tmp_path, list_value):
config_file = tmp_path / 'glances-gpu.conf'
config_file.write_text(f'[quicklook]\nlist={list_value}\n', encoding='utf-8')
args = Namespace(sparkline=True, client=None, disable_history=False, disable_quicklook=False, percpu=False)
plugin = QuicklookPlugin(args=args, config=Config(config_dir=os.fspath(config_file)))
for percent in (10.0, 20.0, 30.0):
plugin.stats = {
'cpu': percent,
'percpu': [],
'mem': percent,
'swap': percent,
'load': percent,
'gpu_mem': percent,
'gpu_proc': percent + 1,
}
plugin.update_stats_history()
plugin.update_views()
return plugin, args

GPU_HISTORY = [('gpu_mem', [10.0, 20.0, 30.0]), ('gpu_proc', [11.0, 21.0, 31.0])]

@pytest.mark.parametrize(('key', 'expected'), GPU_HISTORY)
def test_the_gpu_entries_are_historised(self, tmp_path, key, expected):
plugin, _ = self._plugin(tmp_path, f'cpu,{key}')

assert [value for _, value in plugin.get_raw_history(item=key)] == expected

@pytest.mark.parametrize(('key', 'expected'), GPU_HISTORY)
def test_a_gpu_entry_is_drawn_as_a_sparkline_of_its_history(self, tmp_path, key, expected):
sparklines = pytest.importorskip('sparklines').sparklines
plugin, args = self._plugin(tmp_path, f'cpu,{key}')

lines = [line['msg'] for line in plugin.msg_curse(args, max_width=40)]

# max_width=40 gives a 34-cell sparkline, padded on the right with None
drawn = sparklines(expected + [None] * (34 - len(expected)), minimum=0, maximum=100)[0]
assert lines[lines.index(f'{key.upper():4} ') + 2] == f'{drawn}{expected[-1]:5.1f}%'

@pytest.mark.parametrize(('key', 'expected'), GPU_HISTORY)
def test_a_gpu_entry_is_historised_even_when_not_in_the_list(self, tmp_path, key, expected):
"""History is per plugin, not per displayed stat -- exactly like `swap` today.

`update_stats_history` iterates `get_items_history_list()`, not `stats_list`,
so a GPU entry keeps building history while only `cpu` is in `list=`.
"""
plugin, _ = self._plugin(tmp_path, 'cpu')

assert key not in plugin.stats_list
assert [value for _, value in plugin.get_raw_history(item=key)] == expected
Loading