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
175
176
177
178
179
180
181
|
#!/bin/bash
# perf script ilist and perf list --tui test (no_mlock)
# SPDX-License-Identifier: GPL-2.0
set -e
shelldir=$(dirname "$0")
# shellcheck source=lib/setup_python.sh
. "${shelldir}"/lib/setup_python.sh
if ! "$PYTHON" -c 'import perf' > /dev/null 2>&1; then
echo "Skipping test, perf python module not found"
exit 2
fi
if ! "$PYTHON" -c 'import textual' > /dev/null 2>&1; then
echo "Skipping test, python textual library not found"
exit 2
fi
err=0
output=$(mktemp /tmp/__perf_ilist_test.output.XXXXX)
cleanup() {
rm -f "${output}"
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
test_plumbing() {
echo "ilist plumbing test"
# The script should be found and run by perf script, --help doesn't
# need a terminal.
if ! perf script ilist --help > "${output}" 2>&1; then
echo "ilist plumbing test [Failed: script failed]"
cat "${output}"
err=1
return
fi
if ! grep -q -- "--interval" "${output}"; then
echo "ilist plumbing test [Failed: script not launched]"
cat "${output}"
err=1
return
fi
echo "ilist plumbing test [Success]"
}
test_list_tui() {
echo "perf list --tui plumbing test"
# Arguments after -- are passed to the script launched by perf list.
if ! perf list --tui -- --help > "${output}" 2>&1; then
echo "perf list --tui plumbing test [Failed: script failed]"
cat "${output}"
err=1
return
fi
if ! grep -q -- "--interval" "${output}"; then
echo "perf list --tui plumbing test [Failed: script not launched]"
cat "${output}"
err=1
return
fi
echo "perf list --tui plumbing test [Success]"
}
test_headless_ui() {
echo "ilist headless UI test"
# Drive the textual app without a terminal. Opening counters may fail
# for want of permissions, in which case an error dialog is shown.
if ! "$PYTHON" > "${output}" 2>&1 <<'EOF'
import asyncio
import ilist
from textual.widgets import Label, Tree
async def dismiss_error(app, pilot) -> bool:
"""Close the error dialog if shown, returning whether it was."""
if not isinstance(app.screen, ilist.ErrorScreen):
return False
await pilot.click("#error")
await pilot.pause()
if isinstance(app.screen, ilist.ErrorScreen):
raise RuntimeError("Error dialog not dismissed")
return True
async def search(pilot, text: str) -> None:
await pilot.press("s")
await pilot.pause()
await pilot.press(*text, "enter")
await pilot.pause()
def find_leaf(node, cls):
"""Find the first node whose data is of type cls."""
if isinstance(node.data, cls):
return node
for child in node.children:
found = find_leaf(child, cls)
if found:
return found
return None
async def check_counting(app, pilot, name: str) -> None:
"""Check the selected event is shown and counting, or that it failed to open."""
await pilot.pause(0.5)
if await dismiss_error(app, pilot):
print(f"{name}: failed to open")
return
shown = str(app.query_one("#event_name", Label).render())
if shown != name:
raise RuntimeError(f"Selected {shown} rather than {name}")
if not app.query(ilist.CounterSparkline) or not app.query("#counter_total"):
raise RuntimeError(f"No counters shown for {name}")
print(f"{name}: total {app.query_one('#counter_total', Label).render()}")
async def run() -> None:
app = ilist.IListApp(0.1)
async with app.run_test(size=(120, 40)) as pilot:
await pilot.pause()
tree = app.query_one("#root", Tree)
top = [str(node.label) for node in tree.root.children]
if top != ["PMUs", "Metrics"]:
raise RuntimeError(f"Unexpected tree: {top}")
pmus = [str(node.label) for node in tree.root.children[0].children]
if "software" not in pmus:
raise RuntimeError(f"No software PMU in: {pmus}")
# Search for a software event, which exists everywhere. The search
# result is selected which opens the event.
await search(pilot, "task-clock")
found = app.cur_search_result
if not found or not isinstance(found.data, ilist.PmuEvent) or \
"task-clock" not in str(found.label):
raise RuntimeError(f"Search didn't find task-clock: {found}")
await check_counting(app, pilot, found.data.name())
if not app.query_one("#active_search", Label).display:
raise RuntimeError("Active search not shown")
await pilot.press("n", "p", "down", "up", "c")
await pilot.pause(0.2)
await dismiss_error(app, pilot)
# Searching for something that doesn't exist shows an error.
await search(pilot, "no-such-event-xyzzy")
if not await dismiss_error(app, pilot):
raise RuntimeError("No error for a failed search")
# Select a metric, if there are any.
metric = find_leaf(tree.root, ilist.Metric)
if metric:
app.expand_and_select(metric)
await check_counting(app, pilot, metric.data.name())
print("headless UI ok")
asyncio.run(run())
EOF
then
echo "ilist headless UI test [Failed: exception]"
cat "${output}"
err=1
return
fi
if ! grep -q "headless UI ok" "${output}"; then
echo "ilist headless UI test [Failed: unexpected output]"
cat "${output}"
err=1
return
fi
echo "ilist headless UI test [Success]"
}
test_plumbing
test_list_tui
test_headless_ui
cleanup
exit $err
|