misc: vpp_papi- add tests, clean up pep8

Type: test

Change-Id: Ic81bd4a9eba3c89a746e7a9b9e471b59cd87fa40
Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
diff --git a/src/vpp-api/python/tox.ini b/src/vpp-api/python/tox.ini
new file mode 100644
index 0000000..9b6c1f2
--- /dev/null
+++ b/src/vpp-api/python/tox.ini
@@ -0,0 +1,40 @@
+[tox]
+envlist = py27,py3{6,7}, pep8
+minversion = 2.3.1
+skipsdist = True
+skip_missing_interpreters = True
+
+[testenv]
+usedevelop = True
+whitelist_externals =
+    find
+deps =
+    stestr
+    parameterized
+commands =
+    find . -type f -name "*.pyc" -delete
+    stestr --test-path {toxinidir}/vpp_papi/tests/ run --slowest {posargs}
+
+[testenv:pep8]
+basepython = python3
+deps =
+    flake8
+commands =
+    flake8  --exclude {toxinidir}/vpp_papi/tests {toxinidir}/vpp_papi {posargs}
+
+[testenv:pypi]
+basepython = python3
+deps =
+    twine
+    wheel
+passenv =
+    TWINE_USERNAME
+    TWINE_PASSWORD
+    TWINE_REPOSITORY
+    TWINE_REPOSITORY_URL
+    TWINE_CERT
+
+commands =
+    python setup.py bdist_wheel
+    twine upload  {toxinidir}/dist/*
+
diff --git a/src/vpp-api/python/vpp_papi/__init__.py b/src/vpp-api/python/vpp_papi/__init__.py
index f9afcf1..957468a 100644
--- a/src/vpp-api/python/vpp_papi/__init__.py
+++ b/src/vpp-api/python/vpp_papi/__init__.py
@@ -1 +1,10 @@
-from .vpp_papi import *
+from .vpp_papi import FuncWrapper, VPP, VppApiDynamicMethodHolder  # noqa: F401
+from .vpp_papi import VppEnum, VppEnumType  # noqa: F401
+from .vpp_papi import VPPIOError, VPPRuntimeError, VPPValueError  # noqa: F401
+from .vpp_papi import VPPApiClient  # noqa: F401
+from . macaddress import MACAddress, mac_pton, mac_ntop  # noqa: F401
+
+# sorted lexicographically
+from .vpp_serializer import BaseTypes  # noqa: F401
+from .vpp_serializer import VPPEnumType, VPPType, VPPTypeAlias  # noqa: F401
+from .vpp_serializer import VPPMessage, VPPUnionType  # noqa: F401
diff --git a/src/vpp-api/python/vpp_papi/tests/test_vpp_format.py b/src/vpp-api/python/vpp_papi/tests/test_vpp_format.py
new file mode 100644
index 0000000..54b4846
--- /dev/null
+++ b/src/vpp-api/python/vpp_papi/tests/test_vpp_format.py
@@ -0,0 +1,130 @@
+#  Copyright (c) 2019. Vinci Consulting Corp. All Rights Reserved.
+#
+#  Licensed 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.
+
+import ipaddress
+import socket
+import unittest
+try:
+    text_type = unicode
+except NameError:
+    text_type = str
+
+from vpp_papi import vpp_format
+
+from parameterized import parameterized
+
+ip4_addr = '1.2.3.4'
+ip4_addrn = b'\x01\x02\x03\x04'
+ip4_prefix_len = 32
+ip4_prefix = '%s/%s' % (ip4_addr, ip4_prefix_len)
+ipv4_network = ipaddress.IPv4Network(text_type(ip4_prefix))
+ip4_addr_format_vl_api_address_t = {'un': {'ip4': b'\x01\x02\x03\x04'},
+                                    'af': 0}
+ip4_addr_format_vl_api_prefix_t = {'prefix':
+                                       {'un': {'ip4': b'\x01\x02\x03\x04'},
+                                        'af': 0},
+                                   'len': ip4_prefix_len}
+ip4_addr_format_vl_api_prefix_packed_t = {'prefix': b'\x01\x02\x03\x04',
+                                          'len': ip4_prefix_len}
+
+ip6_addr = 'dead::'
+ip6_addrn = b'\xde\xad\x00\x00\x00\x00\x00\x00' \
+            b'\x00\x00\x00\x00\x00\x00\x00\x00'
+ip6_prefix_len = 127
+ip6_prefix = '%s/%s' % (ip6_addr, ip6_prefix_len)
+ipv6_network = ipaddress.IPv6Network(text_type(ip6_prefix))
+ip6_addr_format_vl_api_address_t = {'un': {'ip6': b'\xde\xad\x00\x00'
+                                                  b'\x00\x00\x00\x00'
+                                                  b'\x00\x00\x00\x00'
+                                                  b'\x00\x00\x00\x00'},
+                                    'af': 1}
+ip6_addr_format_vl_api_prefix_t = {'prefix':
+                                       {'af': 1,
+                                        'un': {
+                                            'ip6': b'\xde\xad\x00\x00'
+                                                   b'\x00\x00\x00\x00'
+                                                   b'\x00\x00\x00\x00'
+                                                   b'\x00\x00\x00\x00'}},
+                                   'len': ip6_prefix_len}
+ip6_addr_format_vl_api_prefix_packed_t = {'prefix': b'\xde\xad\x00\x00'
+                                                    b'\x00\x00\x00\x00'
+                                                    b'\x00\x00\x00\x00'
+                                                    b'\x00\x00\x00\x00',
+                                          'len': ip6_prefix_len}
+
+
+class TestVppFormat(unittest.TestCase):
+
+    def test_format_vl_api_address_t(self):
+        res = vpp_format.format_vl_api_address_t(ip4_addr)
+        self.assertEqual(res, ip4_addr_format_vl_api_address_t)
+
+        # PY2: raises socket.error
+        # PY3: raises OSError
+        with self.assertRaises((TypeError,
+                                socket.error,
+                                OSError)):
+            res = vpp_format.format_vl_api_address_t(ip4_addrn)
+
+        res = vpp_format.format_vl_api_address_t(ip6_addr)
+        self.assertEqual(res, ip6_addr_format_vl_api_address_t)
+
+        with self.assertRaises(TypeError):
+            es = vpp_format.format_vl_api_address_t(ip6_addrn)
+
+    @parameterized.expand([('ip4 prefix',
+                            ip4_prefix,
+                            ip4_addr_format_vl_api_prefix_t),
+                           ('ip6 prefix',
+                            ip6_prefix,
+                            ip6_addr_format_vl_api_prefix_t),
+                           ('IPv4Network',
+                            ipv4_network,
+                            ip4_addr_format_vl_api_prefix_t),
+                           ('IPv6Network',
+                            ipv6_network,
+                            ip6_addr_format_vl_api_prefix_t),
+                           ])
+    def test_format_vl_api_prefix_t(self, _, arg, expected):
+
+        res = vpp_format.format_vl_api_prefix_t(arg)
+        self.assertEqual(res, expected)
+
+    def test_format_vl_api_ip6_prefix_t(self):
+        res = vpp_format.format_vl_api_ip6_prefix_t(ip6_prefix)
+        self.assertEqual(res, ip6_addr_format_vl_api_prefix_packed_t)
+
+        res = vpp_format.format_vl_api_ip6_prefix_t(ipv6_network)
+        self.assertEqual(res, ip6_addr_format_vl_api_prefix_packed_t)
+
+    def test_format_vl_api_ip4_prefix_t(self):
+        res = vpp_format.format_vl_api_ip4_prefix_t(ip4_prefix)
+        self.assertEqual(res, ip4_addr_format_vl_api_prefix_packed_t)
+
+        res = vpp_format.format_vl_api_ip4_prefix_t(ipv4_network)
+        self.assertEqual(res, ip4_addr_format_vl_api_prefix_packed_t)
+
+
+    def test_format_vl_api_ip6_prefix_t_raises(self):
+        # PY2: raises socket.error
+        # PY3: raises OSError
+        with self.assertRaises((socket.error, OSError)):
+            res = vpp_format.format_vl_api_ip6_prefix_t(ip4_prefix)
+
+    def test_format_vl_api_ip4_prefix_t_raises(self):
+        # PY2: raises socket.error
+        # PY3: raises OSError
+        with self.assertRaises((socket.error, OSError)):
+            res = vpp_format.format_vl_api_ip4_prefix_t(ip6_prefix)
+
diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py
index 7880965..5d35b02 100644
--- a/src/vpp-api/python/vpp_papi/vpp_papi.py
+++ b/src/vpp-api/python/vpp_papi/vpp_papi.py
@@ -21,17 +21,14 @@
 import multiprocessing as mp
 import os
 import logging
-import collections
-import struct
 import functools
 import json
 import threading
 import fnmatch
 import weakref
 import atexit
-from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes
+from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType
 from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias
-from . macaddress import MACAddress, mac_pton, mac_ntop
 
 logger = logging.getLogger(__name__)
 
@@ -40,6 +37,11 @@
 else:
     import queue as queue
 
+__all__ = ('FuncWrapper', 'VPP', 'VppApiDynamicMethodHolder',
+           'VppEnum', 'VppEnumType',
+           'VPPIOError', 'VPPRuntimeError', 'VPPValueError',
+           'VPPApiClient', )
+
 
 def metaclass(metaclass):
     @functools.wraps(metaclass)
diff --git a/src/vpp-api/python/vpp_papi/vpp_serializer.py b/src/vpp-api/python/vpp_papi/vpp_serializer.py
index 2d775d5..fe9a083 100644
--- a/src/vpp-api/python/vpp_papi/vpp_serializer.py
+++ b/src/vpp-api/python/vpp_papi/vpp_serializer.py
@@ -12,25 +12,24 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-import struct
 import collections
-import sys
 import logging
-from . import vpp_format
-import ipaddress
 import socket
+import struct
+import sys
 
 if sys.version_info <= (3, 4):
-    from aenum import IntEnum
+    from aenum import IntEnum  # noqa: F401
 else:
-    from enum import IntEnum
+    from enum import IntEnum  # noqa: F401
 
 if sys.version_info <= (3, 6):
-    from aenum import IntFlag
+    from aenum import IntFlag  # noqa: F401
 else:
-    from enum import IntFlag
 
+    from enum import IntFlag  # noqa: F401
+
+from . import vpp_format  # noqa: E402
 
 #
 # Set log-level in application by doing e.g.:
diff --git a/src/vpp-api/python/vpp_papi/vpp_stats.py b/src/vpp-api/python/vpp_papi/vpp_stats.py
index 590549a..3638892 100644
--- a/src/vpp-api/python/vpp_papi/vpp_stats.py
+++ b/src/vpp-api/python/vpp_papi/vpp_stats.py
@@ -86,7 +86,7 @@
 uint64_t stat_segment_version(void);
 uint64_t stat_segment_version_r(stat_client_main_t *sm);
 void free(void *ptr);
-""")
+""")  # noqa: E501
 
 
 # Utility functions
@@ -130,12 +130,14 @@
         vec.append(if_per_thread)
     return vec
 
+
 def error_vec_list(api, e):
     vec = []
     for thread in range(api.stat_segment_vec_len(e)):
         vec.append(e[thread])
     return vec
 
+
 def name_vec_list(api, e):
     return [ffi.string(e[i]).decode('utf-8') for i in
             range(api.stat_segment_vec_len(e)) if e[i] != ffi.NULL]
@@ -175,7 +177,7 @@
         if not message:
             try:
                 message = self.message % kwargs
-            except Exception as e:
+            except Exception:
                 message = self.message
         else:
             message = message % kwargs
@@ -258,7 +260,7 @@
                                          .format(name))
                 k, v = s.popitem()
                 return v
-            except VPPStatsIOError as e:
+            except VPPStatsIOError:
                 if retries > 10:
                     return None
                 retries += 1
@@ -280,7 +282,7 @@
                 error_names = self.ls(['/err/'])
                 error_counters = self.dump(error_names)
                 break
-            except VPPStatsIOError as e:
+            except VPPStatsIOError:
                 if retries > 10:
                     return None
                 retries += 1
diff --git a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py
index d26a3d4..ee14258 100644
--- a/src/vpp-api/python/vpp_papi/vpp_transport_socket.py
+++ b/src/vpp-api/python/vpp_papi/vpp_transport_socket.py
@@ -188,6 +188,8 @@
         header = self.header.pack(0, len(buf), 0)
         n = self.socket.send(header)
         n = self.socket.send(buf)
+        if n == 0:
+            raise VppTransportSocketIOError(1, 'Not connected')
 
     def _read(self):
         hdr = self.socket.recv(16)