-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
Copy pathtest_tools_smoke.py
executable file
·454 lines (355 loc) · 16.2 KB
/
test_tools_smoke.py
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
#!/usr/bin/env python3
# Copyright (c) Sasha Goldshtein, 2017
# Licensed under the Apache License, Version 2.0 (the "License")
import subprocess
import os
import re
from unittest import main, skipUnless, TestCase
from utils import mayFail, kernel_version_ge
TOOLS_DIR = "/bcc/tools/"
if not os.path.exists("/bcc/tools/"):
TOOLS_DIR = "../../tools/"
def _helpful_rc_msg(rc, allow_early, kill):
s = "rc was %d\n" % rc
if rc == 0:
s += "\tMeaning: command returned successfully before test timeout\n"
elif rc == 124:
s += "\tMeaning: command was killed by INT signal\n"
elif rc == 137:
s += "\tMeaning: command was killed by KILL signal\n"
s += "Command was expected to do one of:\n"
s += "\tBe killed by SIGINT\n"
if kill:
s += "\tBe killed by SIGKILL\n"
if allow_early:
s += "\tSuccessfully return before being killed\n"
return s
@skipUnless(kernel_version_ge(4,1), "requires kernel >= 4.1")
class SmokeTests(TestCase):
# Use this for commands that have a built-in timeout, so they only need
# to be killed in case of a hard hang.
def run_with_duration(self, command, timeout=10):
full_command = TOOLS_DIR + command
self.assertEqual(0, # clean exit
subprocess.call("timeout -s KILL %ds %s > /dev/null" %
(timeout, full_command), shell=True))
# Use this for commands that don't have a built-in timeout, so we have
# to Ctrl-C out of them by sending SIGINT. If that still doesn't stop
# them, send a kill signal 5 seconds later.
def run_with_int(self, command, timeout=5, kill_timeout=5,
allow_early=False, kill=False):
full_command = TOOLS_DIR + command
signal = "KILL" if kill else "INT"
rc = subprocess.call("timeout -s %s -k %ds %ds %s > /dev/null" %
(signal, kill_timeout, timeout, full_command), shell=True)
# timeout returns 124 if the program did not terminate prematurely,
# and returns 137 if we used KILL instead of INT. So there are three
# sensible scenarios:
# 1. The script is allowed to return early, and it did, with a
# success return code.
# 2. The script timed out and was killed by the SIGINT signal.
# 3. The script timed out and was killed by the SIGKILL signal, and
# this was what we asked for using kill=True.
self.assertTrue((rc == 0 and allow_early) or rc == 124
or (rc == 137 and kill), _helpful_rc_msg(rc,
allow_early, kill))
def kmod_loaded(self, mod):
with open("/proc/modules", "r") as mods:
reg = re.compile(r'^%s\s' % mod)
for line in mods:
if reg.match(line):
return 1
return 0
def setUp(self):
pass
def tearDown(self):
pass
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_argdist(self):
self.run_with_duration("argdist.py -v -C 'p::do_sys_open()' -n 1 -i 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_bashreadline(self):
self.run_with_int("bashreadline.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_bindsnoop(self):
self.run_with_int("bindsnoop.py")
def test_biolatency(self):
self.run_with_duration("biolatency.py 1 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_biosnoop(self):
self.run_with_int("biosnoop.py")
def test_biotop(self):
self.run_with_duration("biotop.py 1 1")
def test_bitesize(self):
self.run_with_int("biotop.py")
def test_bpflist(self):
self.run_with_duration("bpflist.py")
def test_btrfsdist(self):
# Will attempt to do anything meaningful only when btrfs is installed.
self.run_with_duration("btrfsdist.py 1 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_btrfsslower(self):
# Will attempt to do anything meaningful only when btrfs is installed.
self.run_with_int("btrfsslower.py", allow_early=True)
def test_cachestat(self):
self.run_with_duration("cachestat.py 1 1")
def test_cachetop(self):
# TODO cachetop doesn't like to run without a terminal, disabled
# for now.
# self.run_with_int("cachetop.py 1")
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_capable(self):
self.run_with_int("capable.py")
def test_cpudist(self):
self.run_with_duration("cpudist.py 1 1")
@skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
def test_cpuunclaimed(self):
self.run_with_duration("cpuunclaimed.py 1 1")
@skipUnless(kernel_version_ge(4,17), "requires kernel >= 4.17")
def test_compactsnoop(self):
self.run_with_int("compactsnoop.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_dbslower(self):
# Deliberately left empty -- dbslower requires an instance of either
# MySQL or PostgreSQL to be running, or it fails to attach.
pass
@skipUnless(kernel_version_ge(4,3), "requires kernel >= 4.3")
def test_dbstat(self):
# Deliberately left empty -- dbstat requires an instance of either
# MySQL or PostgreSQL to be running, or it fails to attach.
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_dcsnoop(self):
self.run_with_int("dcsnoop.py")
def test_dcstat(self):
self.run_with_duration("dcstat.py 1 1")
@skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
def test_deadlock(self):
# TODO This tool requires a massive BPF stack traces table allocation,
# which might fail the run or even trigger the oomkiller to kill some
# other processes. Disabling for now.
# self.run_with_int("deadlock.py $(pgrep -n bash)", timeout=10)
pass
@skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
def test_drsnoop(self):
self.run_with_int("drsnoop.py")
@skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
def test_execsnoop(self):
self.run_with_int("execsnoop.py")
def test_ext4dist(self):
self.run_with_duration("ext4dist.py 1 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_ext4slower(self):
self.run_with_int("ext4slower.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_f2fsslower(self):
self.run_with_int("f2fsslower.py", allow_early=True)
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_filelife(self):
self.run_with_int("filelife.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_fileslower(self):
self.run_with_int("fileslower.py")
def test_filetop(self):
self.run_with_duration("filetop.py 1 1")
def test_funccount(self):
self.run_with_int("funccount.py __kmalloc -i 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_funclatency(self):
self.run_with_int("funclatency.py __kmalloc -i 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_funcslower(self):
self.run_with_int("funcslower.py __kmalloc")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_gethostlatency(self):
self.run_with_int("gethostlatency.py")
@skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
def test_hardirqs(self):
self.run_with_duration("hardirqs.py 1 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_killsnoop(self):
# Because killsnoop intercepts signals, if we send it a SIGINT we we
# we likely catch it while it is handling the data packet from the
# BPF program, and the exception from the SIGINT will be swallowed by
# ctypes. Therefore, we use SIGKILL.
# To reproduce the above issue, run killsnoop and in another shell run
# `kill -s SIGINT $(pidof python)`. As a result, killsnoop will print
# a traceback but will not exit.
self.run_with_int("killsnoop.py", kill=True)
@skipUnless(kernel_version_ge(4,18), "requires kernel >= 4.18")
def test_klockstat(self):
self.run_with_int("klockstat.py")
@skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
def test_llcstat(self):
# Requires PMU, which is not available in virtual machines.
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_mdflush(self):
self.run_with_int("mdflush.py")
@skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
def test_memleak(self):
self.run_with_duration("memleak.py 1 1")
@skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
def test_mountsnoop(self):
self.run_with_int("mountsnoop.py")
@skipUnless(kernel_version_ge(4,3), "requires kernel >= 4.3")
def test_mysqld_qslower(self):
# Deliberately left empty -- mysqld_qslower requires an instance of
# MySQL to be running, or it fails to attach.
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_nfsslower(self):
if(self.kmod_loaded("nfs")):
self.run_with_int("nfsslower.py")
else:
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_nfsdist(self):
if(self.kmod_loaded("nfs")):
self.run_with_duration("nfsdist.py 1 1")
else:
pass
@skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_offcputime(self):
self.run_with_duration("offcputime.py 1")
@skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
def test_offwaketime(self):
self.run_with_duration("offwaketime.py 1", timeout=30)
@skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
def test_oomkill(self):
self.run_with_int("oomkill.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_opensnoop(self):
self.run_with_int("opensnoop.py")
def test_pidpersec(self):
self.run_with_int("pidpersec.py")
@skipUnless(kernel_version_ge(4,17), "requires kernel >= 4.17")
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_syscount(self):
self.run_with_int("ppchcalls.py -i 1")
@skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
def test_profile(self):
self.run_with_duration("profile.py 1")
def test_runqlat(self):
self.run_with_duration("runqlat.py 1 1")
@skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9")
def test_runqlen(self):
self.run_with_duration("runqlen.py 1 1")
@skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
def test_shmsnoop(self):
self.run_with_int("shmsnoop.py")
@skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
def test_sofdsnoop(self):
self.run_with_int("sofdsnoop.py")
def test_slabratetop(self):
self.run_with_duration("slabratetop.py 1 1")
@skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
def test_softirqs(self):
self.run_with_duration("softirqs.py 1 1")
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_solisten(self):
self.run_with_int("solisten.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_sslsniff(self):
self.run_with_int("sslsniff.py")
@skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
def test_stackcount(self):
self.run_with_int("stackcount.py __kmalloc -i 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_statsnoop(self):
self.run_with_int("statsnoop.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_syncsnoop(self):
self.run_with_int("syncsnoop.py")
@skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
def test_syscount(self):
self.run_with_int("syscount.py -i 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_tcpaccept(self):
self.run_with_int("tcpaccept.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_tcpconnect(self):
self.run_with_int("tcpconnect.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_tcpconnlat(self):
self.run_with_int("tcpconnlat.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_tcplife(self):
self.run_with_int("tcplife.py")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_tcpretrans(self):
self.run_with_int("tcpretrans.py")
@skipUnless(kernel_version_ge(4, 7), "requires kernel >= 4.7")
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_tcpdrop(self):
self.run_with_int("tcpdrop.py")
def test_tcptop(self):
self.run_with_duration("tcptop.py 1 1")
def test_tcpcong(self):
self.run_with_duration("tcpcong.py 1 1")
def test_tplist(self):
self.run_with_duration("tplist.py -p %d" % os.getpid())
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_trace(self):
self.run_with_int("trace.py do_sys_open")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_ttysnoop(self):
self.run_with_int("ttysnoop.py /dev/console")
@skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
def test_ucalls(self):
self.run_with_int("lib/ucalls.py -l none -S %d" % os.getpid())
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_uflow(self):
# The Python installed on the Ubuntu buildbot doesn't have USDT
# probes, so we can't run uflow.
# self.run_with_int("pythonflow.py %d" % os.getpid())
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_ugc(self):
# This requires a runtime that has GC probes to be installed.
# Python has them, but only in very recent versions. Skip.
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_uobjnew(self):
self.run_with_int("cobjnew.sh %d" % os.getpid())
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_ustat(self):
self.run_with_duration("lib/ustat.py 1 1")
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_uthreads(self):
self.run_with_int("lib/uthreads.py %d" % os.getpid())
def test_vfscount(self):
self.run_with_int("vfscount.py", timeout=15, kill_timeout=15)
def test_vfsstat(self):
self.run_with_duration("vfsstat.py 1 1")
@skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
def test_wakeuptime(self):
self.run_with_duration("wakeuptime.py 1")
@skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
def test_wqlat(self):
self.run_with_int("wqlat.py 1 1", allow_early=True)
def test_xfsdist(self):
# Doesn't work on build bot because xfs functions not present in the
# kernel image.
# self.run_with_duration("xfsdist.py 1 1")
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_xfsslower(self):
# Doesn't work on build bot because xfs functions not present in the
# kernel image.
# self.run_with_int("xfsslower.py")
pass
def test_zfsdist(self):
# Fails to attach the probe if zfs is not installed.
pass
@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
def test_zfsslower(self):
# Fails to attach the probe if zfs is not installed.
pass
if __name__ == "__main__":
main()