Commit 7b500622 authored by Luke Macken's avatar Luke Macken

Optimize our unit tests. Ensure python is fully loaded before we inject into it.

parent c5fe99f8
...@@ -52,11 +52,11 @@ class TestCodeInjection(unittest.TestCase): ...@@ -52,11 +52,11 @@ class TestCodeInjection(unittest.TestCase):
self.stop_program = stop_program = self.generate_program_stopper() self.stop_program = stop_program = self.generate_program_stopper()
self.default_program = default_program = self.generate_program() self.default_program = default_program = self.generate_program()
def generate_program(self, cpu_threads=1, io_threads=1): def generate_program(self, threads=1):
(fd, filename) = tempfile.mkstemp() (fd, filename) = tempfile.mkstemp()
tmp = os.fdopen(fd, 'w') tmp = os.fdopen(fd, 'w')
script = textwrap.dedent(""" script = textwrap.dedent("""
import time, threading, random import os, time, threading, random
running = True running = True
def cpu_bound(): def cpu_bound():
i = 2 i = 2
...@@ -66,17 +66,15 @@ class TestCodeInjection(unittest.TestCase): ...@@ -66,17 +66,15 @@ class TestCodeInjection(unittest.TestCase):
while running: while running:
y += fib(i) y += fib(i)
i += 1 i += 1
def io_bound(): def sleeper():
rand = SystemRandom()
while running: while running:
rand.random() time.sleep(random.random())
threading.Thread(target=sleeper).start()
""") """)
# CPU-bound threads # CPU-bound threads
for t in range(cpu_threads): for t in range(threads):
script += "threading.Thread(target=cpu_bound).start()\n" script += "threading.Thread(target=cpu_bound).start()\n"
# I/O bound (/dev/urandom) script += "open('/tmp/pyrasite_%d' % os.getpid(), 'w').close()"
for t in range(io_threads):
script += "threading.Thread(target=io_bound).start()\n"
tmp.write(script) tmp.write(script)
tmp.close() tmp.close()
return filename return filename
...@@ -100,11 +98,10 @@ class TestCodeInjection(unittest.TestCase): ...@@ -100,11 +98,10 @@ class TestCodeInjection(unittest.TestCase):
shell=True, stdout=subprocess.PIPE, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
pids.append(p.pid) pids.append(p.pid)
# FIXME: Hack to ensure that python (3, specifically) fully loads flag = '/tmp/pyrasite_%d' % p.pid
# before we inject code into it. To optimize this, we should while not os.path.exists(flag):
# have the program print something out once it's loaded, then time.sleep(0.1)
# we should ensure this happens before injecting. os.unlink(flag)
time.sleep(0.5)
return p return p
def assert_output_contains(self, stdout, stderr, text): def assert_output_contains(self, stdout, stderr, text):
...@@ -119,18 +116,8 @@ class TestCodeInjection(unittest.TestCase): ...@@ -119,18 +116,8 @@ class TestCodeInjection(unittest.TestCase):
continue # skip python2.7-config, etc continue # skip python2.7-config, etc
yield exe yield exe
def test_injection_into_all_interpreters_with_no_threads(self): def test_injecting_into_all_interpreters(self):
for exe in self.interpreters(): program = self.generate_program(threads=3)
print("sys.executable = %s" % sys.executable)
print("injecting into %s" % exe)
p = self.run_python('-c "import time; time.sleep(2.0)"', exe=exe)
pyrasite.inject(p.pid,
'pyrasite/payloads/helloworld.py', verbose=True)
stdout, stderr = p.communicate()
self.assert_output_contains(stdout, stderr, 'Hello World!')
def test_injecting_into_all_interpreters_with_gil_contention(self):
program = self.generate_program(cpu_threads=3, io_threads=3)
try: try:
for exe in self.interpreters(): for exe in self.interpreters():
print("sys.executable = %s" % sys.executable) print("sys.executable = %s" % sys.executable)
...@@ -145,11 +132,10 @@ class TestCodeInjection(unittest.TestCase): ...@@ -145,11 +132,10 @@ class TestCodeInjection(unittest.TestCase):
os.unlink(program) os.unlink(program)
def test_many_payloads_into_program_with_many_threads(self): def test_many_payloads_into_program_with_many_threads(self):
program = self.generate_program(cpu_threads=3, io_threads=3) program = self.generate_program(threads=50)
for exe in self.interpreters(): for exe in self.interpreters():
p = self.run_python(program, exe=exe) p = self.run_python(program, exe=exe)
total = 50
total = 100
for i in range(total): for i in range(total):
pyrasite.inject(p.pid, pyrasite.inject(p.pid,
'pyrasite/payloads/helloworld.py', verbose=True) 'pyrasite/payloads/helloworld.py', verbose=True)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment