You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2013/02/13 21:58:31 UTC

svn commit: r1445920 - in /qpid/proton/trunk: proton-c/bindings/python/ tests/interop/ tests/python/ tests/python/proton_tests/

Author: aconway
Date: Wed Feb 13 20:58:30 2013
New Revision: 1445920

URL: http://svn.apache.org/r1445920
Log:
PROTON-215: Add tests to verify AMQP type support for python bindings.

The test consists of
- a generator program that generates AMQP fragments for all AMQP types
- a checked-in set of generated AMQP fragments
- a set of python unit tests to decode, verify and re-encode the fragments.

The generator only needs to be run when the test data changes. The generated
files are checked in. This allows unit test in different languages to
access the test data without depending on python.

Additional unit tests will be added for each proton language binding.

Added:
    qpid/proton/trunk/tests/interop/
    qpid/proton/trunk/tests/interop/arrays.amqp
    qpid/proton/trunk/tests/interop/described.amqp
    qpid/proton/trunk/tests/interop/described_array.amqp
    qpid/proton/trunk/tests/interop/lists.amqp
    qpid/proton/trunk/tests/interop/maps.amqp
    qpid/proton/trunk/tests/interop/null.amqp
    qpid/proton/trunk/tests/interop/primitives.amqp
    qpid/proton/trunk/tests/interop/strings.amqp
    qpid/proton/trunk/tests/python/interop-generate   (with props)
    qpid/proton/trunk/tests/python/proton_tests/interop.py   (with props)
Modified:
    qpid/proton/trunk/proton-c/bindings/python/proton.py
    qpid/proton/trunk/tests/python/proton_tests/__init__.py

Modified: qpid/proton/trunk/proton-c/bindings/python/proton.py
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/bindings/python/proton.py?rev=1445920&r1=1445919&r2=1445920&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/bindings/python/proton.py (original)
+++ qpid/proton/trunk/proton-c/bindings/python/proton.py Wed Feb 13 20:58:30 2013
@@ -936,6 +936,37 @@ class Data:
   LIST = PN_LIST; "A list value."
   MAP = PN_MAP; "A map value."
 
+  type_names = {
+    NULL: "null",
+    BOOL: "bool",
+    BYTE: "byte",
+    UBYTE: "ubyte",
+    SHORT: "short",
+    USHORT: "ushort",
+    INT: "int",
+    UINT: "uint",
+    CHAR: "char",
+    LONG: "long",
+    ULONG: "ulong",
+    TIMESTAMP: "timestamp",
+    FLOAT: "float",
+    DOUBLE: "double",
+    DECIMAL32: "decimal32",
+    DECIMAL64: "decimal64",
+    DECIMAL128: "decimal128",
+    UUID: "uuid",
+    BINARY: "binary",
+    STRING: "string",
+    SYMBOL: "symbol",
+    DESCRIBED: "described",
+    ARRAY: "array",
+    LIST: "list",
+    MAP: "map"
+    }
+
+  @classmethod
+  def type_name(type): return Data.type_names[type]
+
   def __init__(self, capacity=16):
     if type(capacity) in (int, long):
       self._data = pn_data(capacity)
@@ -964,7 +995,9 @@ class Data:
 
   def rewind(self):
     """
-    Clears current node and sets the parent to the root node.
+    Clears current node and sets the parent to the root node.  Clearing the
+    current node sets it _before_ the first node, calling next() will advance to
+    the first node.
     """
     pn_data_rewind(self._data)
 
@@ -995,6 +1028,8 @@ class Data:
   def enter(self):
     """
     Sets the parent node to the current node and clears the current node.
+    Clearing the current node sets it _before_ the first child,
+    call next() advances to the first child.
     """
     return pn_data_enter(self._data)
 
@@ -1592,7 +1627,14 @@ class Data:
       self.exit()
 
   def get_py_array(self):
+    """
+    If the current node is an array, return an Array object
+    representing the array and its contents. Otherwise return None.
+    This is a convenience wrapper around get_array, enter, etc.
+    """
+
     count, described, type = self.get_array()
+    if type is None: return None
     if self.enter():
       try:
         if described:
@@ -1666,6 +1708,7 @@ class Data:
     MAP: get_dict
     }
 
+
   def put_object(self, obj):
     putter = self.put_mappings[obj.__class__]
     putter(self, obj)
@@ -1679,7 +1722,6 @@ class Data:
     else:
       return UnmappedType(str(type))
 
-
 class ConnectionException(ProtonException):
   pass
 
@@ -2558,7 +2600,6 @@ class Driver(object):
   def pending_connector(self):
     return wrap_connector(pn_driver_connector(self._driver))
 
-
 __all__ = [
            "LANGUAGE",
            "PN_SESSION_WINDOW",

Added: qpid/proton/trunk/tests/interop/arrays.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/arrays.amqp?rev=1445920&view=auto
==============================================================================
Files qpid/proton/trunk/tests/interop/arrays.amqp (added) and qpid/proton/trunk/tests/interop/arrays.amqp Wed Feb 13 20:58:30 2013 differ

Added: qpid/proton/trunk/tests/interop/described.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/described.amqp?rev=1445920&view=auto
==============================================================================
Files qpid/proton/trunk/tests/interop/described.amqp (added) and qpid/proton/trunk/tests/interop/described.amqp Wed Feb 13 20:58:30 2013 differ

Added: qpid/proton/trunk/tests/interop/described_array.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/described_array.amqp?rev=1445920&view=auto
==============================================================================
Files qpid/proton/trunk/tests/interop/described_array.amqp (added) and qpid/proton/trunk/tests/interop/described_array.amqp Wed Feb 13 20:58:30 2013 differ

Added: qpid/proton/trunk/tests/interop/lists.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/lists.amqp?rev=1445920&view=auto
==============================================================================
Files qpid/proton/trunk/tests/interop/lists.amqp (added) and qpid/proton/trunk/tests/interop/lists.amqp Wed Feb 13 20:58:30 2013 differ

Added: qpid/proton/trunk/tests/interop/maps.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/maps.amqp?rev=1445920&view=auto
==============================================================================
Files qpid/proton/trunk/tests/interop/maps.amqp (added) and qpid/proton/trunk/tests/interop/maps.amqp Wed Feb 13 20:58:30 2013 differ

Added: qpid/proton/trunk/tests/interop/null.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/null.amqp?rev=1445920&view=auto
==============================================================================
--- qpid/proton/trunk/tests/interop/null.amqp (added)
+++ qpid/proton/trunk/tests/interop/null.amqp Wed Feb 13 20:58:30 2013
@@ -0,0 +1 @@
+@
\ No newline at end of file

Added: qpid/proton/trunk/tests/interop/primitives.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/primitives.amqp?rev=1445920&view=auto
==============================================================================
Files qpid/proton/trunk/tests/interop/primitives.amqp (added) and qpid/proton/trunk/tests/interop/primitives.amqp Wed Feb 13 20:58:30 2013 differ

Added: qpid/proton/trunk/tests/interop/strings.amqp
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/interop/strings.amqp?rev=1445920&view=auto
==============================================================================
Files qpid/proton/trunk/tests/interop/strings.amqp (added) and qpid/proton/trunk/tests/interop/strings.amqp Wed Feb 13 20:58:30 2013 differ

Added: qpid/proton/trunk/tests/python/interop-generate
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/interop-generate?rev=1445920&view=auto
==============================================================================
--- qpid/proton/trunk/tests/python/interop-generate (added)
+++ qpid/proton/trunk/tests/python/interop-generate Wed Feb 13 20:58:30 2013
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Generate encoded  AMQP fragments for interop testing.
+
+import logging, optparse, os, struct, sys, time, traceback, types, cgi
+from proton import *
+
+def main(argv):
+
+    def write(data, filename):
+        f = open(filename+".amqp", 'w')
+        f.write(data.encode())
+        f.close()
+
+    # null
+    d = Data()
+    d.put_null()
+    write(d, "null")
+
+    # primitive types
+    d = Data()
+    d.put_bool(True)
+    d.put_bool(False)
+    d.put_ubyte(42)
+    d.put_ushort(42)
+    d.put_short(-42)
+    d.put_uint(12345)
+    d.put_int(-12345)
+    d.put_ulong(12345)
+    d.put_long(-12345)
+    d.put_float(0.125)
+    d.put_double(0.125)
+    write(d, "primitives")
+
+    # string types
+    d = Data()
+    d.put_binary("abc\0defg")
+    d.put_string("abcdefg")
+    d.put_symbol("abcdefg")
+    d.put_binary("")
+    d.put_string("")
+    d.put_symbol("")
+    write(d, "strings")
+
+    # described types
+    d = Data()
+    d.put_described()
+    d.enter()
+    d.put_symbol("foo-descriptor")
+    d.put_string("foo-value")
+    d.exit()
+
+    d.put_described()
+    d.enter()
+    d.put_int(12)
+    d.put_int(13)
+    d.exit()
+
+    write(d, "described")
+
+    # described array
+    d = Data()
+    d.put_array(True, Data.INT)
+    d.enter()
+    d.put_symbol("int-array")
+    for i in xrange(0,10): d.put_int(i)
+    d.exit()
+    write(d, "described_array")
+
+
+    # Arrays
+
+    # Integer array
+    d = Data()
+    d.put_array(False, Data.INT)
+    d.enter()
+    for i in xrange(0,100): d.put_int(i)
+    d.exit()
+
+    # String array
+    d.put_array(False, Data.STRING)
+    d.enter()
+    for i in ["a", "b", "c"]: d.put_string(i)
+    d.exit()
+
+    # empty array
+    d.put_array(False, Data.INT)
+
+    write(d, "arrays")
+
+    # List - mixed types
+    d = Data()
+    d.put_list()
+    d.enter()
+    d.put_int(32)
+    d.put_string("foo")
+    d.put_bool(True)
+    d.exit()
+
+    d.put_list()                # Empty list
+    write(d, "lists")
+
+    # Maps
+    d = Data()
+    d.put_map()
+    d.enter()
+    for k,v in {"one":1, "two":2, "three":3}.items():
+        d.put_string(k)
+        d.put_int(v)
+    d.exit()
+
+    d.put_map()
+    d.enter()
+    for k,v in {1:"one", 2:"two", 3:"three"}.items():
+        d.put_int(k)
+        d.put_string(v)
+    d.exit()
+
+    d.put_map()                 # Empty map
+    write(d, "maps")
+
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv))

Propchange: qpid/proton/trunk/tests/python/interop-generate
------------------------------------------------------------------------------
    svn:executable = *

Modified: qpid/proton/trunk/tests/python/proton_tests/__init__.py
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/__init__.py?rev=1445920&r1=1445919&r2=1445920&view=diff
==============================================================================
--- qpid/proton/trunk/tests/python/proton_tests/__init__.py (original)
+++ qpid/proton/trunk/tests/python/proton_tests/__init__.py Wed Feb 13 20:58:30 2013
@@ -24,4 +24,4 @@ import proton_tests.messenger
 import proton_tests.sasl
 import proton_tests.transport
 import proton_tests.ssl
-
+import proton_tests.interop

Added: qpid/proton/trunk/tests/python/proton_tests/interop.py
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/interop.py?rev=1445920&view=auto
==============================================================================
--- qpid/proton/trunk/tests/python/proton_tests/interop.py (added)
+++ qpid/proton/trunk/tests/python/proton_tests/interop.py Wed Feb 13 20:58:30 2013
@@ -0,0 +1,117 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from proton import *
+import os, common
+
+class InteropTest(common.Test):
+
+    def setup(self):
+        self.data = Data()
+
+    def teardown(self):
+        self.data = None
+
+    def decode(self, name):
+        home = os.getenv("PROTON_HOME") or os.getcwd()
+        filename = os.path.join(home, "tests", "interop", name+".amqp")
+        f = open(filename)
+        encoded = f.read()
+        f.close()
+        buffer = encoded
+        while buffer:
+            n = self.data.decode(buffer)
+            buffer = buffer[n:]
+        self.data.rewind()
+        # Test the round-trip re-encoding gives the same result.
+        assert encoded == self.data.encode()
+
+    def assert_next(self, type, value):
+        next_type = self.data.next()
+        assert next_type == type, "Type mismatch: %s != %s"%(
+            Data.type_names[next_type], Data.type_names[type])
+        getter = Data.get_mappings[type]
+        next_value = getter(self.data)
+        assert next_value == value, "Value mismatch: %s != %s"%(next_value, value)
+
+    def test_primitives(self):
+        self.decode("primitives")
+        self.assert_next(Data.BOOL, True)
+        self.assert_next(Data.BOOL, False)
+        self.assert_next(Data.UBYTE, 42)
+        self.assert_next(Data.USHORT, 42)
+        self.assert_next(Data.SHORT, -42)
+        self.assert_next(Data.UINT, 12345)
+        self.assert_next(Data.INT, -12345)
+        self.assert_next(Data.ULONG, 12345)
+        self.assert_next(Data.LONG, -12345)
+        self.assert_next(Data.FLOAT, 0.125)
+        self.assert_next(Data.DOUBLE, 0.125)
+        assert self.data.next() is None
+
+    def test_strings(self):
+        self.decode("strings")
+        self.assert_next(Data.BINARY, "abc\0defg")
+        self.assert_next(Data.STRING, "abcdefg")
+        self.assert_next(Data.SYMBOL, "abcdefg")
+        self.assert_next(Data.BINARY, "")
+        self.assert_next(Data.STRING, "")
+        self.assert_next(Data.SYMBOL, "")
+        assert self.data.next() is None
+
+    def test_described(self):
+        self.decode("described")
+        assert self.data.next() == Data.DESCRIBED
+        self.data.enter()
+        self.assert_next(Data.SYMBOL, "foo-descriptor")
+        self.assert_next(Data.STRING, "foo-value")
+        self.data.exit()
+
+        assert self.data.next() == Data.DESCRIBED
+        self.data.enter()
+        self.assert_next(Data.INT, 12)
+        self.assert_next(Data.INT, 13)
+        self.data.exit()
+
+        assert self.data.next() is None
+
+    def test_described_array(self):
+        raise common.Skipped()  # PROTON-240: Incorrect encoding of described arrays.
+        self.decode("described_array")
+        self.assert_next(Data.ARRAY, Array("int-array", Data.INT, *range(0,10)))
+
+    def test_arrays(self):
+        self.decode("arrays")
+        self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT, *range(0,100)))
+        self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.STRING, *["a", "b", "c"]))
+        self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT))
+        assert self.data.next() is None
+
+    def test_lists(self):
+        self.decode("lists")
+        self.assert_next(Data.LIST, [32, "foo", True])
+        self.assert_next(Data.LIST, [])
+        assert self.data.next() is None
+
+    def test_maps(self):
+        self.decode("maps")
+        self.assert_next(Data.MAP, {"one":1, "two":2, "three":3 })
+        self.assert_next(Data.MAP, {1:"one", 2:"two", 3:"three"})
+        self.assert_next(Data.MAP, {})
+        assert self.data.next() is None

Propchange: qpid/proton/trunk/tests/python/proton_tests/interop.py
------------------------------------------------------------------------------
    svn:eol-style = native



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org