Skip to content

Commit ed246f1

Browse files
committed
typo fix
1 parent 5da215b commit ed246f1

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
###############################################################################
2+
#
3+
# MIT License
4+
#
5+
# Copyright (c) 2025 Advanced Micro Devices, Inc.
6+
#
7+
# Permission is hereby granted, free of charge, to any person obtaining a copy
8+
# of this software and associated documentation files (the "Software"), to deal
9+
# in the Software without restriction, including without limitation the rights
10+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
# copies of the Software, and to permit persons to whom the Software is
12+
# furnished to do so, subject to the following conditions:
13+
#
14+
# The above copyright notice and this permission notice shall be included in all
15+
# copies or substantial portions of the Software.
16+
#
17+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
# SOFTWARE.
24+
#
25+
###############################################################################
26+
import types
27+
28+
from nodescraper.enums.systeminteraction import SystemInteractionLevel
29+
from nodescraper.plugins.inband.journal.journal_collector import JournalCollector
30+
from nodescraper.plugins.inband.journal.journaldata import JournalData
31+
32+
33+
class DummyRes:
34+
def __init__(self, command="", stdout="", exit_code=0, stderr=""):
35+
self.command = command
36+
self.stdout = stdout
37+
self.exit_code = exit_code
38+
self.stderr = stderr
39+
40+
41+
def get_collector(monkeypatch, run_map, system_info, conn_mock):
42+
c = JournalCollector(
43+
system_info=system_info,
44+
system_interaction_level=SystemInteractionLevel.INTERACTIVE,
45+
connection=conn_mock,
46+
)
47+
c.result = types.SimpleNamespace(artifacts=[], message=None)
48+
c._events = []
49+
50+
def _log_event(**kw):
51+
c._events.append(kw)
52+
53+
def _run_sut_cmd(cmd, *args, **kwargs):
54+
return run_map(cmd, *args, **kwargs)
55+
56+
monkeypatch.setattr(c, "_log_event", _log_event, raising=True)
57+
monkeypatch.setattr(c, "_run_sut_cmd", _run_sut_cmd, raising=True)
58+
59+
return c
60+
61+
62+
def test_get_journals_happy_path(monkeypatch, system_info, conn_mock):
63+
paths = [
64+
"/var/log/journal/m1/system.journal",
65+
"/var/log/journal/m1/[email protected]",
66+
"/var/log/journal/m2/system.journal",
67+
]
68+
ls_out = "\n".join(paths) + "\n"
69+
70+
def run_map(cmd, **kwargs):
71+
if cmd.startswith("ls -1 /var/log/journal"):
72+
return DummyRes(command=cmd, stdout=ls_out, exit_code=0)
73+
74+
if cmd.startswith("journalctl ") and "--file=" in cmd:
75+
if paths[0] in cmd:
76+
return DummyRes(cmd, stdout='{"MESSAGE":"a"}\n', exit_code=0)
77+
if paths[1] in cmd:
78+
return DummyRes(cmd, stdout=b'{"MESSAGE":"b"}\n', exit_code=0)
79+
if paths[2] in cmd:
80+
return DummyRes(cmd, stdout='{"MESSAGE":"c"}\n', exit_code=0)
81+
82+
return DummyRes(command=cmd, stdout="", exit_code=1, stderr="unexpected")
83+
84+
c = get_collector(monkeypatch, run_map, system_info, conn_mock)
85+
86+
collected = c._get_journals()
87+
assert len(collected) == 3
88+
89+
expected_names = {
90+
"journalctl__var__log__journal__m1__system.journal.json",
91+
"journalctl__var__log__journal__m1__system@0000000000000001-0000000000000002.journal.json",
92+
"journalctl__var__log__journal__m2__system.journal.json",
93+
}
94+
names = {a.filename for a in c.result.artifacts}
95+
assert names == expected_names
96+
97+
contents = {a.filename: a.contents for a in c.result.artifacts}
98+
assert (
99+
contents["journalctl__var__log__journal__m1__system.journal.json"].strip()
100+
== '{"MESSAGE":"a"}'
101+
)
102+
assert (
103+
contents[
104+
"journalctl__var__log__journal__m1__system@0000000000000001-0000000000000002.journal.json"
105+
].strip()
106+
== '{"MESSAGE":"b"}'
107+
)
108+
assert (
109+
contents["journalctl__var__log__journal__m2__system.journal.json"].strip()
110+
== '{"MESSAGE":"c"}'
111+
)
112+
113+
assert any(
114+
evt.get("description") == "Collected journal logs."
115+
and getattr(evt.get("priority"), "name", str(evt.get("priority"))) == "INFO"
116+
for evt in c._events
117+
)
118+
assert c.result.message == "journalctl logs collected"
119+
120+
121+
def test_get_journals_no_files(monkeypatch, system_info, conn_mock):
122+
def run_map(cmd, **kwargs):
123+
if cmd.startswith("ls -1 /var/log/journal"):
124+
return DummyRes(command=cmd, stdout="", exit_code=0)
125+
return DummyRes(command=cmd, stdout="", exit_code=1)
126+
127+
c = get_collector(monkeypatch, run_map, system_info, conn_mock)
128+
129+
collected = c._get_journals()
130+
assert collected == []
131+
assert c.result.artifacts == []
132+
133+
assert any(
134+
evt.get("description", "").startswith("No /var/log/journal files found")
135+
and getattr(evt.get("priority"), "name", str(evt.get("priority"))) == "WARNING"
136+
for evt in c._events
137+
)
138+
139+
140+
def test_get_journals_partial_failure(monkeypatch, system_info, conn_mock):
141+
ok_path = "/var/log/journal/m1/system.journal"
142+
bad_path = "/var/log/journal/m1/[email protected]"
143+
ls_out = ok_path + "\n" + bad_path + "\n"
144+
145+
def run_map(cmd, **kwargs):
146+
if cmd.startswith("ls -1 /var/log/journal"):
147+
return DummyRes(command=cmd, stdout=ls_out, exit_code=0)
148+
149+
if cmd.startswith("journalctl ") and "--file=" in cmd:
150+
if ok_path in cmd:
151+
return DummyRes(cmd, stdout='{"MESSAGE":"ok"}\n', exit_code=0)
152+
if bad_path in cmd:
153+
return DummyRes(cmd, stdout="", exit_code=1, stderr="cannot read")
154+
155+
return DummyRes(command=cmd, stdout="", exit_code=1)
156+
157+
c = get_collector(monkeypatch, run_map, system_info, conn_mock)
158+
159+
collected = c._get_journals()
160+
assert collected == ["journalctl__var__log__journal__m1__system.journal.json"]
161+
assert [a.filename for a in c.result.artifacts] == [
162+
"journalctl__var__log__journal__m1__system.journal.json"
163+
]
164+
165+
assert any(
166+
evt.get("description") == "Some journal files could not be read with journalctl."
167+
and getattr(evt.get("priority"), "name", str(evt.get("priority"))) == "WARNING"
168+
for evt in c._events
169+
)
170+
171+
172+
def test_collect_data_integration(monkeypatch, system_info, conn_mock):
173+
dummy_path = "/var/log/journal/m1/system.journal"
174+
ls_out = dummy_path + "\n"
175+
176+
def run_map(cmd, **kwargs):
177+
if cmd.startswith("ls -1 /var/log/journal"):
178+
return DummyRes(command=cmd, stdout=ls_out, exit_code=0)
179+
if cmd.startswith("journalctl ") and "--file=" in cmd and dummy_path in cmd:
180+
return DummyRes(command=cmd, stdout='{"MESSAGE":"hello"}\n', exit_code=0)
181+
return DummyRes(command=cmd, stdout="", exit_code=1)
182+
183+
c = get_collector(monkeypatch, run_map, system_info, conn_mock)
184+
185+
result, data = c.collect_data()
186+
assert isinstance(data, JournalData)
187+
188+
expected_name = "journalctl__var__log__journal__m1__system.journal.json"
189+
assert data.journal_logs == [expected_name]
190+
assert c.result.message == "journalctl logs collected"
191+
192+
assert [a.filename for a in c.result.artifacts] == [expected_name]

0 commit comments

Comments
 (0)