-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest_run_plugins.py
More file actions
174 lines (145 loc) · 6.32 KB
/
test_run_plugins.py
File metadata and controls
174 lines (145 loc) · 6.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
###############################################################################
#
# MIT License
#
# Copyright (c) 2025 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
###############################################################################
"""Functional tests for running individual plugins."""
import csv
from pathlib import Path
import pytest
from nodescraper.pluginregistry import PluginRegistry
@pytest.fixture(scope="module")
def all_plugins():
"""Get list of all available plugin names."""
registry = PluginRegistry()
return sorted(registry.plugins.keys())
def test_plugin_registry_has_plugins(all_plugins):
"""Verify that plugins are available for testing."""
assert len(all_plugins) > 0
@pytest.mark.parametrize(
"plugin_name",
[
"BiosPlugin",
"CmdlinePlugin",
"DimmPlugin",
"DkmsPlugin",
"DmesgPlugin",
"JournalPlugin",
"KernelPlugin",
"KernelModulePlugin",
"MemoryPlugin",
"NetworkPlugin",
"NvmePlugin",
"OsPlugin",
"PackagePlugin",
"ProcessPlugin",
"RocmPlugin",
"StoragePlugin",
"SysctlPlugin",
"SyslogPlugin",
"UptimePlugin",
],
)
def test_run_individual_plugin(run_cli_command, plugin_name, tmp_path):
"""Test running each plugin individually."""
log_path = str(tmp_path / f"logs_{plugin_name}")
result = run_cli_command(["--log-path", log_path, "run-plugins", plugin_name], check=False)
assert result.returncode in [0, 1, 2]
output = result.stdout + result.stderr
assert len(output) > 0
assert plugin_name.lower() in output.lower()
def test_run_all_plugins_together(run_cli_command, all_plugins, tmp_path):
"""Test running all plugins together."""
plugins_to_run = all_plugins[:3]
log_path = str(tmp_path / "logs_multiple")
result = run_cli_command(["--log-path", log_path, "run-plugins"] + plugins_to_run, check=False)
assert result.returncode in [0, 1, 2]
output = result.stdout + result.stderr
assert len(output) > 0
def test_run_plugin_with_invalid_name(run_cli_command):
"""Test that running a non-existent plugin logs a warning and falls back to default config."""
result = run_cli_command(["run-plugins", "NonExistentPlugin"], check=False)
# Invalid plugin is ignored and default config runs instead
# Exit code depends on whether default config plugins succeed
output = result.stdout + result.stderr
# Check that warning was logged for invalid plugin
assert "Invalid plugin name(s) ignored: NonExistentPlugin" in output
# Check that default config was used
assert "running default config" in output.lower() or "NodeStatus" in output
# Verify it didn't crash
assert "Data written to csv file" in output
def test_run_comma_separated_plugins_with_invalid(run_cli_command):
"""Test that comma-separated plugins run valid ones and ignore invalid ones."""
result = run_cli_command(["run-plugins", "AmdSmiPlugin,SomePlugin"], check=False)
output = result.stdout + result.stderr
# Check that warning was logged for invalid plugin
assert "Invalid plugin name(s) ignored: SomePlugin" in output
# Check that AmdSmiPlugin actually ran
assert "Running plugin AmdSmiPlugin" in output
# Verify it didn't crash
assert "Data written to csv file" in output
def test_run_plugin_with_data_file_no_collection(run_cli_command, tmp_path):
"""Test running plugin with --data argument and --collection False."""
fixtures_dir = Path(__file__).parent / "fixtures"
dmesg_fixture = fixtures_dir / "dmesg_sample.log"
assert dmesg_fixture.exists(), f"Fixture file not found: {dmesg_fixture}"
analyze_log_path = str(tmp_path / "analyze_logs")
result = run_cli_command(
[
"--log-path",
analyze_log_path,
"run-plugins",
"DmesgPlugin",
"--data",
str(dmesg_fixture),
"--collection",
"False",
],
check=False,
)
output = result.stdout + result.stderr
assert (
result.returncode == 1
), f"Expected return code 1 (errors found), got: {result.returncode}"
assert "Running data analyzer: DmesgAnalyzer" in output, "Analyzer should have run"
assert "Data written to csv file" in output, "CSV file should be created"
if "Plugin tasks not ran" in output:
pytest.fail(
"Bug regression: Plugin reported 'tasks not ran' with --data file. "
"Analysis should load data from --data parameter before checking if data is None."
)
analyze_path = Path(analyze_log_path)
csv_files = list(analyze_path.glob("*/nodescraper.csv"))
assert len(csv_files) > 0, "CSV results file should exist"
csv_file = csv_files[0]
with open(csv_file, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
rows = list(reader)
dmesg_rows = [row for row in rows if "DmesgPlugin" in row.get("plugin", "")]
assert len(dmesg_rows) > 0, "DmesgPlugin should have results in CSV"
dmesg_row = dmesg_rows[0]
status = dmesg_row.get("status", "")
assert status != "NOT_RAN", (
f"Bug regression: DmesgPlugin status is NOT_RAN with --data file. "
f"Analysis should have run on provided data. Status: {status}"
)