python3 fixes and testing support (#1916)
* python3: check ksymname calls with _assert_is_bytes
Fixes a bytes/string concatenation error when get/fix_syscall_fnname is
called from a python3 system.
* python3: use env python invocation in tools
In order to facilitate testing, but not necessarily as an example of
good practice, I am changing the invocation of the test tools to use
`/usr/bin/env python`, so that we can control which python (2 vs 3)
gets invoked for the test. On the buildbots, I plan to add an optional
`ln -s /usr/bin/python3 /usr/local/bin/python` on systems that have
python3-bcc package built. This way, we get more test coverage. Having a
cmake mechanism to enable both python2 and python3 testing could be a
further enhancement.
* tools/memleak: add an explicit stdout.flush to print loop
The stdout flush behavior seems to have changed in python3, breaking one
of the tests. I think it makes sense to flush stdout at the end of each
timed interval loop anyway, so adding that to the tool itself.
* tests: add b'' strings and fix dangling handles
Add b'' strings in a few places in the test tools, and fix one dangling
process handle in the memleak test tool runner.
diff --git a/tests/python/test_stackid.py b/tests/python/test_stackid.py
index 4d258d7..2587293 100755
--- a/tests/python/test_stackid.py
+++ b/tests/python/test_stackid.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
diff --git a/tests/python/test_tools_memleak.py b/tests/python/test_tools_memleak.py
index acdc6f6..bbc0a83 100755
--- a/tests/python/test_tools_memleak.py
+++ b/tests/python/test_tools_memleak.py
@@ -56,30 +56,33 @@
@skipUnless(kernel_version_ge(4, 6), "requires kernel >= 4.6")
class MemleakToolTests(TestCase):
+ def tearDown(self):
+ if self.p:
+ del(self.p)
def run_leaker(self, leak_kind):
# Starting memleak.py, which in turn launches the leaking application.
- p = subprocess.Popen(cfg.cmd_format.format(leak_kind),
- stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- shell=True)
+ self.p = subprocess.Popen(cfg.cmd_format.format(leak_kind),
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ shell=True)
# Waiting for the first report.
while True:
- p.poll()
- if p.returncode is not None:
+ self.p.poll()
+ if self.p.returncode is not None:
break
- line = p.stdout.readline()
- if "with outstanding allocations" in line:
+ line = self.p.stdout.readline()
+ if b"with outstanding allocations" in line:
break
# At this point, memleak.py have already launched application and set
# probes. Sending command to the leaking application to make its
# allocations.
- out = p.communicate(input="\n")[0]
+ out = self.p.communicate(input=b"\n")[0]
# If there were memory leaks, they are in the output. Filter the lines
# containing "byte" substring. Every interesting line is expected to
# start with "N bytes from"
- x = [x for x in out.split('\n') if 'byte' in x]
+ x = [x for x in out.split(b'\n') if b'byte' in x]
self.assertTrue(len(x) >= 1,
msg="At least one line should have 'byte' substring.")
diff --git a/tests/python/test_trace4.py b/tests/python/test_trace4.py
index 68497b3..6836047 100755
--- a/tests/python/test_trace4.py
+++ b/tests/python/test_trace4.py
@@ -9,7 +9,7 @@
class TestKprobeRgx(TestCase):
def setUp(self):
- self.b = BPF(text="""
+ self.b = BPF(text=b"""
typedef struct { int idx; } Key;
typedef struct { u64 val; } Val;
BPF_HASH(stats, Key, Val, 3);
@@ -22,23 +22,23 @@
return 0;
}
""")
- self.b.attach_kprobe(event_re="^" + self.b.get_syscall_prefix() + "bp.*",
- fn_name="hello")
- self.b.attach_kretprobe(event_re="^" + self.b.get_syscall_prefix() + "bp.*",
- fn_name="goodbye")
+ self.b.attach_kprobe(event_re=b"^" + self.b.get_syscall_prefix() + b"bp.*",
+ fn_name=b"hello")
+ self.b.attach_kretprobe(event_re=b"^" + self.b.get_syscall_prefix() + b"bp.*",
+ fn_name=b"goodbye")
def test_send1(self):
- k1 = self.b["stats"].Key(1)
- k2 = self.b["stats"].Key(2)
- self.assertTrue(self.b["stats"][k1].val >= 2)
- self.assertTrue(self.b["stats"][k2].val == 1)
+ k1 = self.b[b"stats"].Key(1)
+ k2 = self.b[b"stats"].Key(2)
+ self.assertTrue(self.b[b"stats"][k1].val >= 2)
+ self.assertTrue(self.b[b"stats"][k2].val == 1)
class TestKprobeReplace(TestCase):
def setUp(self):
- self.b = BPF(text="int empty(void *ctx) { return 0; }")
+ self.b = BPF(text=b"int empty(void *ctx) { return 0; }")
def test_periods(self):
- self.b.attach_kprobe(event_re="^tcp_enter_cwr.*", fn_name="empty")
+ self.b.attach_kprobe(event_re=b"^tcp_enter_cwr.*", fn_name=b"empty")
if __name__ == "__main__":
main()
diff --git a/tests/python/test_usdt.py b/tests/python/test_usdt.py
index ef578c3..27a0e47 100755
--- a/tests/python/test_usdt.py
+++ b/tests/python/test_usdt.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# USAGE: test_usdt.py
#
diff --git a/tests/python/test_usdt2.py b/tests/python/test_usdt2.py
index 066b167..a2f4611 100755
--- a/tests/python/test_usdt2.py
+++ b/tests/python/test_usdt2.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# USAGE: test_usdt2.py
#
diff --git a/tests/python/test_usdt3.py b/tests/python/test_usdt3.py
index 864d706..82df4bc 100755
--- a/tests/python/test_usdt3.py
+++ b/tests/python/test_usdt3.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
#
# USAGE: test_usdt3.py
#
diff --git a/tests/python/test_utils.py b/tests/python/test_utils.py
index 2959482..69dddf6 100755
--- a/tests/python/test_utils.py
+++ b/tests/python/test_utils.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
# Copyright (c) Catalysts GmbH
# Licensed under the Apache License, Version 2.0 (the "License")