You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by jd...@apache.org on 2019/11/06 11:16:24 UTC
[qpid-proton] branch master updated: PROTON-2115 [c] fix prlimit
test and do PEP8 reformat in related files (#198)
This is an automated email from the ASF dual-hosted git repository.
jdanek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git
The following commit(s) were added to refs/heads/master by this push:
new bdf9b1a PROTON-2115 [c] fix prlimit test and do PEP8 reformat in related files (#198)
bdf9b1a is described below
commit bdf9b1a4a0b3f080387362f7391617199af6b203
Author: Jiří Daněk <jd...@redhat.com>
AuthorDate: Wed Nov 6 12:16:12 2019 +0100
PROTON-2115 [c] fix prlimit test and do PEP8 reformat in related files (#198)
This fixes prlimit test, adds some more useful 2.7 unittest methods,
and does some PEP8 formatting in related files.
---
c/tests/CMakeLists.txt | 7 +++-
c/tests/fdlimit.py | 94 +++++++++++++++++++++++++++------------------
scripts/env.py | 8 ++--
tests/py/test_subprocess.py | 15 ++++++--
tests/py/test_unittest.py | 31 +++++++++++++--
5 files changed, 106 insertions(+), 49 deletions(-)
diff --git a/c/tests/CMakeLists.txt b/c/tests/CMakeLists.txt
index 457022f..6a754c7 100644
--- a/c/tests/CMakeLists.txt
+++ b/c/tests/CMakeLists.txt
@@ -97,7 +97,12 @@ if (CMAKE_CXX_COMPILER)
set(path "$<TARGET_FILE_DIR:c-broker>:$ENV{PATH}")
endif(WIN32)
- add_test(NAME c-fdlimit-tests COMMAND ${PN_ENV_SCRIPT} -- "PATH=${path}" "PYTHONPATH=${pypath}" ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/fdlimit.py)
+ set(pypath "${CMAKE_SOURCE_DIR}/tests/py")
+
+ add_test(
+ NAME c-fdlimit-tests
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMAND ${PN_ENV_SCRIPT} -- "PATH=${path}" "PYTHONPATH=${pypath}" ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/fdlimit.py)
endif(HAS_PROACTOR)
else (CMAKE_CXX_COMPILER)
message(WARNING "No C++ compiler, some C library tests were not built")
diff --git a/c/tests/fdlimit.py b/c/tests/fdlimit.py
index e5cedac..c4408b9 100644
--- a/c/tests/fdlimit.py
+++ b/c/tests/fdlimit.py
@@ -16,58 +16,76 @@
# specific language governing permissions and limitations
# under the License
#
+from __future__ import absolute_import
+from __future__ import division
from __future__ import print_function
-import os, sys
-from subprocess import Popen, PIPE
+import os
+import subprocess
+import time
-def wait_listening(p):
- return re.search(b"listening on ([0-9]+)$", p.stdout.readline()).group(1)
+import test_subprocess
+from test_unittest import unittest
-class LimitedBroker(Popen):
- def __init__(self, fdlimit):
- super(LimitedBroker, self).__init__(["broker", "", "0"], stdout=PIPE, stderr=open(os.devnull))
- self.fdlimit = fdlimit
+# Check if we can run prlimit to control resources
+try:
+ assert subprocess.check_call(["prlimit"], stdout=open(os.devnull, 'w')) == 0, 'prlimit is present, but broken'
+ prlimit_available = True
+except OSError:
+ prlimit_available = False
- def __enter__(self):
- self.port = wait_listening(self)
- return self
- def __exit__(self, *args):
- self.kill()
+class PRLimitedBroker(test_subprocess.Server):
+ def __init__(self, fdlimit, *args, **kwargs):
+ super(PRLimitedBroker, self).__init__(
+ ['prlimit', '-n{0:d}'.format(fdlimit), "broker", "", "0"],
+ stdout=subprocess.PIPE, universal_newlines=True, *args, **kwargs)
+ self.fdlimit = fdlimit
-# Check if we can run prlimit to control resources
-try:
- Proc(["prlimit"]).wait_exit()
-except:
- print("Skipping test: prlimit not available")
- sys.exit(0)
-class FdLimitTest(ProcTestCase):
+class FdLimitTest(unittest.TestCase):
+ devnull = open(os.devnull, 'w')
+
+ @classmethod
+ def tearDownClass(cls):
+ if cls.devnull:
+ cls.devnull.close()
+ @unittest.skipUnless(prlimit_available, "prlimit not available")
def test_fd_limit_broker(self):
"""Check behaviour when running out of file descriptors on accept"""
# Not too many FDs but not too few either, some are used for system purposes.
fdlimit = 256
- with LimitedBroker(fdlimit) as b:
+ with PRLimitedBroker(fdlimit, kill_me=True) as b:
receivers = []
- # Start enough receivers to use all FDs, make sure the broker logs an error
- for i in range(fdlimit+1):
- receivers.append(Popen(["receive", "", b.port, str(i)], stdout=PIPE))
-
- # All FDs are now in use, send attempt should fail or hang
- self.assertIn(Popen(["send", "", b.port, "x"], stdout=PIPE, stderr=STDOUT).poll(), [1, None])
-
- # Kill receivers to free up FDs
- for r in receivers:
- r.kill()
- for r in receivers:
- r.wait()
- # send/receive should succeed now
- self.assertIn("10 messages sent", check_output(["send", "", b.port]))
- self.assertIn("10 messages received", check_output(["receive", "", b.port]))
-if __name__ == "__main__":
- main()
+ # Start enough receivers to use all FDs
+ # NOTE: broker does not log a file descriptor related error at any point in the test, only
+ # PN_TRANSPORT_CLOSED: amqp:connection:framing-error: connection aborted
+ # PN_TRANSPORT_CLOSED: proton:io: Connection reset by peer - disconnected :5672 (connection aborted)
+ for i in range(fdlimit + 1):
+ receiver = test_subprocess.Popen(["receive", "", b.port, str(i)], stdout=self.devnull)
+ receivers.append(receiver)
+
+ # All FDs are now in use, send attempt will (with present implementation) hang
+ with test_subprocess.Popen(["send", "", b.port, "x"],
+ stdout=self.devnull, stderr=subprocess.STDOUT) as sender:
+ time.sleep(1) # polling for None immediately would always succeed, regardless whether send hangs or not
+ self.assertIsNone(sender.poll())
+
+ # Kill receivers to free up FDs
+ for r in receivers:
+ r.kill()
+ for r in receivers:
+ r.wait()
+ # Sender now succeeded and exited
+ self.assertEqual(sender.wait(), 0)
+ # Additional send/receive should succeed now
+ self.assertIn("10 messages sent", test_subprocess.check_output(["send", "", b.port], universal_newlines=True))
+ self.assertIn("10 messages received", test_subprocess.check_output(["receive", "", b.port], universal_newlines=True))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/scripts/env.py b/scripts/env.py
index 14df6d1..443bdca 100644
--- a/scripts/env.py
+++ b/scripts/env.py
@@ -26,6 +26,7 @@ import os
import subprocess
from optparse import OptionParser
+
def main(argv=None):
parser = OptionParser(usage="Usage: %prog [options] [--] VAR=VALUE... command [options] arg1 arg2...")
@@ -41,10 +42,10 @@ def main(argv=None):
new_env = os.environ.copy()
# pull out each name value pair
- while (len(args)):
- z = args[0].split("=",1)
+ while len(args):
+ z = args[0].split("=", 1)
if len(z) != 2:
- break; # done with env args
+ break # done with env args
if len(z[0]) == 0:
raise Exception("Error: incorrect format for env var: '%s'" % str(args[x]))
del args[0]
@@ -61,5 +62,6 @@ def main(argv=None):
p = subprocess.Popen(args, env=new_env)
return p.wait()
+
if __name__ == "__main__":
sys.exit(main())
diff --git a/tests/py/test_subprocess.py b/tests/py/test_subprocess.py
index 4905107..6e84f01 100644
--- a/tests/py/test_subprocess.py
+++ b/tests/py/test_subprocess.py
@@ -19,10 +19,13 @@
# Extends the subprocess module to use runtime checkers, and report stderr output.
-import subprocess, re, os, tempfile
-
+import os
+import re
+import subprocess
+import tempfile
from subprocess import PIPE
+
def in_path(name):
"""Look for name in the PATH"""
for path in os.environ["PATH"].split(os.pathsep):
@@ -30,6 +33,7 @@ def in_path(name):
if os.path.isfile(f) and os.access(f, os.X_OK):
return f
+
class TestProcessError(Exception):
def __init__(self, proc, what, output=None):
self.output = output
@@ -38,6 +42,7 @@ class TestProcessError(Exception):
super(TestProcessError, self).__init__("%s pid=%s exit=%s: %s%s" % (
proc.cmd, proc.pid, proc.returncode, what, error))
+
class Popen(subprocess.Popen):
"""
Add TEST_EXE_PREFIX to the command, check stderr for runtime checker output.
@@ -92,8 +97,8 @@ class Popen(subprocess.Popen):
"""Return stderr as string, may only be used after process has terminated."""
assert(self.poll is not None)
if not hasattr(self, "_error"):
- self.errfile.close() # Not auto-deleted
- with open(self.errfile.name) as f: # Re-open to read
+ self.errfile.close() # Not auto-deleted
+ with open(self.errfile.name) as f: # Re-open to read
self._error = f.read().strip()
os.unlink(self.errfile.name)
return self._error
@@ -104,9 +109,11 @@ class Popen(subprocess.Popen):
def __exit__(self, *args):
self.on_exit()
+
def check_output(*args, **kwargs):
return Popen(*args, **kwargs).communicate()[0]
+
class Server(Popen):
"""A process that prints 'listening on <port>' to stdout"""
def __init__(self, *args, **kwargs):
diff --git a/tests/py/test_unittest.py b/tests/py/test_unittest.py
index ebb8efc..bc372f6 100644
--- a/tests/py/test_unittest.py
+++ b/tests/py/test_unittest.py
@@ -17,19 +17,44 @@
# under the License
#
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
import unittest
# Monkey-patch a few unittest 2.7 features for Python 2.6.
#
-# These are note the pretty versions provided by 2.7 but they do the
+# These are not the pretty versions provided by 2.7 but they do the
# same job as far as correctness is concerned.
if not hasattr(unittest.TestCase, "assertMultiLineEqual"):
- def assertMultiLineEqual(self, a, b, msg=None): self.assertEqual(a,b,msg)
+ def assertMultiLineEqual(self, a, b, msg=None): self.assertEqual(a, b, msg)
unittest.TestCase.assertMultiLineEqual = assertMultiLineEqual
if not hasattr(unittest.TestCase, "assertIn"):
- def assertIn(self, a, b, msg=None): self.assertTrue(a in b,msg)
+ def assertIn(self, a, b, msg=None): self.assertTrue(a in b, msg)
unittest.TestCase.assertIn = assertIn
+if not hasattr(unittest.TestCase, "assertIsNone"):
+ def assertIsNone(self, obj, msg=None): self.assertEqual(obj, None, msg)
+ unittest.TestCase.assertIsNone = assertIsNone
+
+if not hasattr(unittest, "skip"):
+ def skip(reason="Test skipped"):
+ return lambda f: print(reason)
+ unittest.skip = skip
+
+if not hasattr(unittest, "skipIf"):
+ def skipIf(condition, reason):
+ if condition:
+ return skip(reason)
+ return lambda f: f
+ unittest.skipUnless = skipIf
+if not hasattr(unittest, "skipUnless"):
+ def skipUnless(condition, reason):
+ if not condition:
+ return skip(reason)
+ return lambda f: f
+ unittest.skipUnless = skipUnless
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org