[CalendarServer-changes] [11419] CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/ python

source_changes at macosforge.org source_changes at macosforge.org
Wed Jun 26 01:15:51 PDT 2013


Revision: 11419
          http://trac.calendarserver.org//changeset/11419
Author:   glyph at apple.com
Date:     2013-06-26 01:15:51 -0700 (Wed, 26 Jun 2013)
Log Message:
-----------
Lots of cleanup.

Modified Paths:
--------------
    CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/launchd.py
    CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/test/test_launchd.py

Modified: CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/launchd.py
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/launchd.py	2013-06-26 08:15:25 UTC (rev 11418)
+++ CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/launchd.py	2013-06-26 08:15:51 UTC (rev 11419)
@@ -21,8 +21,6 @@
 
 from __future__ import print_function
 
-import sys
-
 from cffi import FFI
 
 ffi = FFI()
@@ -79,10 +77,6 @@
 #include <launch.h>
 """)
 
-class NullPointerException(Exception):
-    """
-    Python doesn't have one of these.
-    """
 
 
 class LaunchArray(object):
@@ -165,6 +159,11 @@
 
 
 def _launchify(launchvalue):
+    """
+    Convert a ctypes value wrapping a C{_launch_data} structure into the
+    relevant Python object (integer, bytes, L{LaunchDictionary},
+    L{LaunchArray}).
+    """
     if launchvalue == ffi.NULL:
         return None
     dtype = lib.launch_data_get_type(launchvalue)
@@ -201,32 +200,53 @@
     """
     Perform a launchd checkin, returning a Pythonic wrapped data structure
     representing the retrieved check-in plist.
+
+    @return: a C{dict}-like object.
     """
+    return _launchify(
+        lib.launch_msg(
+            _managed(lib.launch_data_new_string(lib.LAUNCH_KEY_CHECKIN))
+        )
+    )
 
+
+
+def _managed(obj):
+    """
+    Automatically free an object that was allocated with a launch_data_*
+    function, or raise L{MemoryError} if it's C{NULL}.
+    """
+    if obj == ffi.NULL:
+        raise MemoryError()
+    else:
+        return ffi.gc(obj, lib.launch_data_free)
+
+
+
+class _Strings(object):
+    """
+    Expose constants as Python-readable values rather than wrapped ctypes
+    pointers.
+    """
+    def __getattribute__(self, name):
+        value = getattr(lib, name)
+        if isinstance(value, int):
+            return value
+        if ffi.typeof(value) != ffi.typeof("char *"):
+            raise AttributeError("no such constant", name)
+        return ffi.string(value)
+
+constants = _Strings()
+
+
+
 def getLaunchDSocketFDs():
     result = {}
-    req = lib.launch_data_new_string(lib.LAUNCH_KEY_CHECKIN)
-    if req == ffi.NULL:
-        # Good luck reproducing this case.
-        raise NullPointerException()
-    response = lib.launch_msg(req)
-    if response == ffi.NULL:
-        raise NullPointerException()
-    if lib.launch_data_get_type(response) == lib.LAUNCH_DATA_ERRNO:
-        raise NullPointerException()
-    response = LaunchDictionary(response)
+    response = {}
     label = response[lib.LAUNCH_JOBKEY_LABEL]
     skts = response[lib.LAUNCH_JOBKEY_SOCKETS]
     result['label'] = label
     result['sockets'] = list(skts['TestSocket'])
     return result
 
-if __name__ == '__main__':
-    # Unit tests :-(
-    import traceback
-    try:
-        print(getLaunchDSocketFDs())
-    except:
-        traceback.print_exc()
-        sys.stdout.flush()
-        sys.stderr.flush()
+

Modified: CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/test/test_launchd.py
===================================================================
--- CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/test/test_launchd.py	2013-06-26 08:15:25 UTC (rev 11418)
+++ CalendarServer/branches/users/glyph/launchd-wrapper-bis/twext/python/test/test_launchd.py	2013-06-26 08:15:51 UTC (rev 11419)
@@ -22,15 +22,21 @@
 
 if __name__ == '__main__':
     import time
+    from pprint import pformat
     sys.stdout.write("HELLO WORLD\n")
     sys.stderr.write("ERROR WORLD\n")
+    sys.stdout.write(pformat(dict(os.environ)))
     sys.stdout.flush()
     sys.stderr.flush()
     time.sleep(1)
+    import socket
+    skt = socket.socket()
+    skt.connect(("127.0.0.1", int(os.environ["TESTING_PORT"])))
     sys.exit(0)
 
 
-from twext.python.launchd import lib, ffi, LaunchDictionary, LaunchArray
+from twext.python.launchd import (lib, ffi, LaunchDictionary, LaunchArray,
+                                  _managed, constants)
 
 from twisted.trial.unittest import TestCase
 from twisted.python.filepath import FilePath
@@ -44,9 +50,8 @@
         """
         Assemble a test dictionary.
         """
-        self.testDict = ffi.gc(
-            lib.launch_data_alloc(lib.LAUNCH_DATA_DICTIONARY),
-            lib.launch_data_free
+        self.testDict = _managed(
+            lib.launch_data_alloc(lib.LAUNCH_DATA_DICTIONARY)
         )
         key1 = ffi.new("char[]", "alpha")
         val1 = lib.launch_data_new_string("alpha-value")
@@ -162,6 +167,24 @@
 
 
 
+class SimpleStringConstants(TestCase):
+    """
+    Tests for bytestring-constants wrapping.
+    """
+
+    def test_constant(self):
+        """
+        C{launchd.constants.LAUNCH_*} will return a bytes object corresponding
+        to a constant.
+        """
+        self.assertEqual(constants.LAUNCH_JOBKEY_SOCKETS,
+                         b"Sockets")
+        self.assertRaises(AttributeError, getattr, constants,
+                          "launch_data_alloc")
+        self.assertEquals(constants.LAUNCH_DATA_ARRAY, 2)
+
+
+
 class CheckInTests(TestCase):
     """
     Integration tests making sure that actual checkin with launchd results in
@@ -171,10 +194,25 @@
     def setUp(self):
         fp = FilePath(self.mktemp())
         fp.makedirs()
+        from twisted.internet.protocol import Protocol, Factory
+        from twisted.internet import reactor, defer
+        d = defer.Deferred()
+        class JustLetMeMoveOn(Protocol):
+            def connectionMade(self):
+                d.callback(None)
+                self.transport.abortConnection()
+        f = Factory()
+        f.protocol = JustLetMeMoveOn
+        port = reactor.listenTCP(0, f, interface="127.0.0.1")
+        @self.addCleanup
+        def goodbyePort():
+            return port.stopListening()
+        env = dict(os.environ)
+        env["TESTING_PORT"] = repr(port.getHost().port)
         plist = {
             "Label": "org.calendarserver.UNIT-TESTS." + repr(os.getpid()),
             "ProgramArguments": [sys.executable, "-m", __name__],
-            "EnvironmentVariables": dict(os.environ),
+            "EnvironmentVariables": env,
             "KeepAlive": False,
             "StandardOutPath": fp.child("stdout.txt").path,
             "StandardErrorPath": fp.child("stderr.txt").path,
@@ -183,11 +221,13 @@
         self.job = fp.child("job.plist")
         self.job.setContent(plistlib.writePlistToString(plist))
         os.spawnlp(os.P_WAIT, "launchctl", "launchctl", "load", self.job.path)
+        return d
 
 
-    def test_something(self):
+    def test_test(self):
         """
-        Test something.
+        Since this test framework is somewhat finicky, let's just make sure
+        that a test can complete.
         """
 
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130626/77bd8dbd/attachment-0001.html>


More information about the calendarserver-changes mailing list