Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up tests for IssueCommand timeout handling. #299

Merged
merged 1 commit into from
Jun 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ nose>=1.3
nose-progressive>=1.5
flake8>=2.1.0
futures>=2.1.0
psutil
59 changes: 57 additions & 2 deletions tests/vm_util_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

"""Tests for perfkitbenchmarker.vm_util."""

import os
import psutil
import subprocess
import threading
import time
import unittest

import mock
Expand Down Expand Up @@ -68,25 +72,76 @@ def testReachable_Unreachable(self):
False, vm_util.IpAddressSubset.REACHABLE, False)


def HaveSleepSubprocess():
"""Checks if the current process has a sleep subprocess."""

for child in psutil.Process(os.getpid()).get_children(recursive=True):
if 'sleep' in child.cmdline:
return True
return False


class WaitUntilSleepTimer(threading.Thread):
"""Timer that waits for a sleep subprocess to appear.

This is intended for specific tests that want to trigger timer
expiry as soon as it detects that a subprocess is executing a
"sleep" command.

It assumes that the test driver is not parallelizing the tests using
this method since that may lead to inconsistent results.
TODO(klausw): If that's an issue, could add a unique fractional part
to the sleep command args to distinguish them.
"""
def __init__(self, interval, function):
threading.Thread.__init__(self)
self.end_time = time.time() + interval
self.function = function
self.finished = threading.Event()
self.have_sleep = threading.Event()

def WaitForSleep():
while not self.finished.is_set():
if HaveSleepSubprocess():
self.have_sleep.set()
break
time.sleep(0) # yield to other Python threads

threading.Thread(target=WaitForSleep).run()

def cancel(self):
self.finished.set()

def run(self):
while time.time() < self.end_time and not self.have_sleep.is_set():
time.sleep(0) # yield to other Python threads
if not self.finished.is_set():
self.function()
self.finished.set()


class IssueCommandTestCase(unittest.TestCase):

def testTimeoutNotReached(self):
_, _, retcode = vm_util.IssueCommand(['sleep', '2s'])
_, _, retcode = vm_util.IssueCommand(['sleep', '0s'])
self.assertEqual(retcode, 0)

@mock.patch('threading.Timer', new=WaitUntilSleepTimer)
def testTimeoutReached(self):
_, _, retcode = vm_util.IssueCommand(['sleep', '2s'], timeout=1)
self.assertEqual(retcode, -9)
self.assertFalse(HaveSleepSubprocess())

def testNoTimeout(self):
_, _, retcode = vm_util.IssueCommand(['sleep', '2s'], timeout=None)
_, _, retcode = vm_util.IssueCommand(['sleep', '0s'], timeout=None)
self.assertEqual(retcode, 0)

def testNoTimeout_ExceptionRaised(self):
with mock.patch('subprocess.Popen', spec=subprocess.Popen) as mock_popen:
mock_popen.return_value.communicate.side_effect = KeyboardInterrupt()
with self.assertRaises(KeyboardInterrupt):
vm_util.IssueCommand(['sleep', '2s'], timeout=None)
self.assertFalse(HaveSleepSubprocess())


if __name__ == '__main__':
Expand Down