mirror of
https://github.com/nicolargo/glances.git
synced 2026-09-15 06:40:25 -04:00
170 lines
4.9 KiB
Python
Executable File
170 lines
4.9 KiB
Python
Executable File
#!/usr/bin/env python
|
|
#
|
|
# Glances - An eye on your system
|
|
#
|
|
# SPDX-FileCopyrightText: 2026 Nicolas Hennion <nicolas@nicolargo.com>
|
|
#
|
|
# SPDX-License-Identifier: LGPL-3.0-only
|
|
#
|
|
|
|
"""Glances v5 — unit tests for the JSON export module."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from glances.config_v5 import GlancesConfigV5
|
|
from glances.plugins.plugin.base_v5 import GlancesPluginBase
|
|
from glances.stats_store_v5 import StatsStoreV5
|
|
|
|
|
|
class FakeScalarPlugin(GlancesPluginBase[dict]):
|
|
plugin_name = "fakescalar"
|
|
IS_COLLECTION = False
|
|
fields_description = {
|
|
"percent": {"description": "p", "unit": "percent"},
|
|
"total": {"description": "t", "unit": "bytes"},
|
|
}
|
|
|
|
async def _grab_stats(self) -> dict:
|
|
return {"percent": 50.0, "total": 1024}
|
|
|
|
|
|
class FakeCollectionPlugin(GlancesPluginBase[list]):
|
|
plugin_name = "fakecollection"
|
|
IS_COLLECTION = True
|
|
fields_description = {
|
|
"name": {"description": "n", "unit": "string", "primary_key": True},
|
|
"rx": {"description": "r", "unit": "bytespers"},
|
|
}
|
|
|
|
async def _grab_stats(self) -> list:
|
|
return [{"name": "eth0", "rx": 10}]
|
|
|
|
|
|
def make_config(sections: dict) -> GlancesConfigV5:
|
|
config = GlancesConfigV5()
|
|
config._merged = {s: dict(opts) for s, opts in sections.items()}
|
|
return config
|
|
|
|
|
|
def make_args(path) -> argparse.Namespace:
|
|
return argparse.Namespace(export_json_file=str(path))
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_json_writes_one_object_per_cycle(tmp_path):
|
|
from glances.exports.glances_json.export_v5 import Export
|
|
|
|
store = StatsStoreV5()
|
|
config = make_config({})
|
|
plugin = FakeScalarPlugin(store, config)
|
|
await plugin.update()
|
|
|
|
path = tmp_path / "glances.json"
|
|
exporter = Export(config, make_args(path))
|
|
exporter.update([plugin])
|
|
exporter.exit()
|
|
|
|
payload = json.loads(path.read_text())
|
|
assert payload["fakescalar"]["percent"] == 50.0
|
|
assert payload["fakescalar"]["total"] == 1024
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_json_rewrites_the_file_each_cycle(tmp_path):
|
|
from glances.exports.glances_json.export_v5 import Export
|
|
|
|
store = StatsStoreV5()
|
|
config = make_config({})
|
|
plugin = FakeScalarPlugin(store, config)
|
|
await plugin.update()
|
|
|
|
path = tmp_path / "glances.json"
|
|
exporter = Export(config, make_args(path))
|
|
exporter.update([plugin])
|
|
exporter.update([plugin])
|
|
exporter.exit()
|
|
|
|
assert len(path.read_text().strip().splitlines()) == 1
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_json_carries_the_merged_limits(tmp_path):
|
|
"""Unlike CSV, the JSON exporter inherits v4's limits merge."""
|
|
from glances.exports.glances_json.export_v5 import Export
|
|
|
|
store = StatsStoreV5()
|
|
config = make_config({"fakescalar": {"careful": "50"}})
|
|
plugin = FakeScalarPlugin(store, config)
|
|
await plugin.update()
|
|
|
|
path = tmp_path / "glances.json"
|
|
exporter = Export(config, make_args(path))
|
|
exporter.update([plugin])
|
|
exporter.exit()
|
|
|
|
payload = json.loads(path.read_text())
|
|
assert payload["fakescalar"]["fakescalar_careful"] == 50.0
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_json_never_carries_action_templates(tmp_path):
|
|
from glances.exports.glances_json.export_v5 import Export
|
|
|
|
store = StatsStoreV5()
|
|
config = make_config({"fakescalar": {"careful": "50", "critical_action": "/usr/bin/mail ops@example.com"}})
|
|
plugin = FakeScalarPlugin(store, config)
|
|
await plugin.update()
|
|
|
|
path = tmp_path / "glances.json"
|
|
exporter = Export(config, make_args(path))
|
|
exporter.update([plugin])
|
|
exporter.exit()
|
|
|
|
assert "/usr/bin/mail" not in path.read_text()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_json_prefixes_collection_items(tmp_path):
|
|
from glances.exports.glances_json.export_v5 import Export
|
|
|
|
store = StatsStoreV5()
|
|
config = make_config({})
|
|
plugin = FakeCollectionPlugin(store, config)
|
|
await plugin.update()
|
|
|
|
path = tmp_path / "glances.json"
|
|
exporter = Export(config, make_args(path))
|
|
exporter.update([plugin])
|
|
exporter.exit()
|
|
|
|
payload = json.loads(path.read_text())
|
|
assert payload["fakecollection"]["eth0.rx"] == 10
|
|
|
|
|
|
def test_json_exits_when_the_file_cannot_be_created(tmp_path):
|
|
from glances.exports.glances_json.export_v5 import Export
|
|
|
|
unreachable = tmp_path / "no-such-dir" / "glances.json"
|
|
with pytest.raises(SystemExit) as excinfo:
|
|
Export(make_config({}), make_args(unreachable))
|
|
assert excinfo.value.code == 2
|
|
|
|
|
|
def test_json_exit_calls_super_first(tmp_path, monkeypatch):
|
|
from glances.exports.export_base_v5 import GlancesExportBase
|
|
from glances.exports.glances_json.export_v5 import Export
|
|
|
|
calls = []
|
|
real_exit = GlancesExportBase.exit
|
|
monkeypatch.setattr(GlancesExportBase, "exit", lambda self: (calls.append("base"), real_exit(self))[1])
|
|
|
|
exporter = Export(make_config({}), make_args(tmp_path / "g.json"))
|
|
exporter.exit()
|
|
|
|
assert calls == ["base"], "Export.exit() must call super().exit()"
|