dpdk: add qat gen4-b device support
[vpp.git] / test / remote_test.py
index bc6d707..19bad89 100644 (file)
@@ -1,26 +1,28 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import inspect
 import os
+import reprlib
 import unittest
+from framework import VppTestCase
 from multiprocessing import Process, Pipe
 from pickle import dumps
+import sys
 
-import six
-from six import moves
-
-from framework import VppTestCase
-from enum import Enum
+from enum import IntEnum, IntFlag
 
 
-class SerializableClassCopy(object):
+class SerializableClassCopy:
     """
     Empty class used as a basis for a serializable copy of another class.
     """
     pass
 
+    def __repr__(self):
+        return '<SerializableClassCopy dict=%s>' % self.__dict__
+
 
-class RemoteClassAttr(object):
+class RemoteClassAttr:
     """
     Wrapper around attribute of a remotely executed class.
     """
@@ -44,7 +46,8 @@ class RemoteClassAttr(object):
     def __getattr__(self, attr):
         if attr[0] == '_':
             if not (attr.startswith('__') and attr.endswith('__')):
-                raise AttributeError
+                raise AttributeError('tried to get private attribute: %s ',
+                                     attr)
         self._path.append(attr)
         return self
 
@@ -55,34 +58,44 @@ class RemoteClassAttr(object):
                 return
         self._path.append(attr)
         self._remote._remote_exec(RemoteClass.SETATTR, self.path_to_str(),
-                                  True, value=val)
+                                  value=val)
 
     def __call__(self, *args, **kwargs):
         return self._remote._remote_exec(RemoteClass.CALL, self.path_to_str(),
-                                         True, *args, **kwargs)
+                                         *args, **kwargs)
 
 
 class RemoteClass(Process):
     """
     This class can wrap around and adapt the interface of another class,
     and then delegate its execution to a newly forked child process.
+
     Usage:
-        # Create a remotely executed instance of MyClass
-        object = RemoteClass(MyClass, arg1='foo', arg2='bar')
-        object.start_remote()
-        # Access the object normally as if it was an instance of your class.
-        object.my_attribute = 20
-        print object.my_attribute
-        print object.my_method(object.my_attribute)
-        object.my_attribute.nested_attribute = 'test'
-        # If you need the value of a remote attribute, use .get_remote_value
-        method. This method is automatically called when needed in the context
-        of a remotely executed class. E.g.:
-        if (object.my_attribute.get_remote_value() > 20):
-            object.my_attribute2 = object.my_attribute
-        # Destroy the instance
-        object.quit_remote()
-        object.terminate()
+
+        #. Create a remotely executed instance of MyClass. ::
+
+            object = RemoteClass(MyClass, arg1='foo', arg2='bar')
+            object.start_remote()
+
+        #. Access the object normally as if it was an instance of your
+           class. ::
+
+            object.my_attribute = 20
+            print object.my_attribute
+            print object.my_method(object.my_attribute)
+            object.my_attribute.nested_attribute = 'test'
+
+        #. If you need the value of a remote attribute, use .get_remote_value
+           method. This method is automatically called when needed in the
+           context of a remotely executed class. E.g. ::
+
+            if (object.my_attribute.get_remote_value() > 20):
+                object.my_attribute2 = object.my_attribute
+
+        #. Destroy the instance. ::
+
+            object.quit_remote()
+            object.terminate()
     """
 
     GET = 0       # Get attribute remotely
@@ -106,7 +119,7 @@ class RemoteClass(Process):
         self._pipe = Pipe()  # pipe for input/output arguments
 
     def __repr__(self):
-        return moves.reprlib.repr(RemoteClassAttr(self, None))
+        return reprlib.repr(RemoteClassAttr(self, None))
 
     def __str__(self):
         return str(RemoteClassAttr(self, None))
@@ -119,7 +132,7 @@ class RemoteClass(Process):
             if not (attr.startswith('__') and attr.endswith('__')):
                 if hasattr(super(RemoteClass, self), '__getattr__'):
                     return super(RemoteClass, self).__getattr__(attr)
-                raise AttributeError
+                raise AttributeError('missing: %s', attr)
         return RemoteClassAttr(self, attr)
 
     def __setattr__(self, attr, val):
@@ -129,7 +142,7 @@ class RemoteClass(Process):
                 return
         setattr(RemoteClassAttr(self, None), attr, val)
 
-    def _remote_exec(self, op, path=None, ret=True, *args, **kwargs):
+    def _remote_exec(self, op, path=None, *args, **kwargs):
         """
         Execute given operation on a given, possibly nested, member remotely.
         """
@@ -137,23 +150,20 @@ class RemoteClass(Process):
         mutable_args = list(args)
         for i, val in enumerate(mutable_args):
             if isinstance(val, RemoteClass) or \
-               isinstance(val, RemoteClassAttr):
+                    isinstance(val, RemoteClassAttr):
                 mutable_args[i] = val.get_remote_value()
         args = tuple(mutable_args)
-        for key, val in six.iteritems(kwargs):
+        for key, val in kwargs.items():
             if isinstance(val, RemoteClass) or \
-               isinstance(val, RemoteClassAttr):
+                    isinstance(val, RemoteClassAttr):
                 kwargs[key] = val.get_remote_value()
         # send request
         args = self._make_serializable(args)
         kwargs = self._make_serializable(kwargs)
         self._pipe[RemoteClass.PIPE_PARENT].send((op, path, args, kwargs))
-        if not ret:
-            # no return value expected
-            return None
         timeout = self._timeout
         # adjust timeout specifically for the .sleep method
-        if path.split('.')[-1] == 'sleep':
+        if path is not None and path.split('.')[-1] == 'sleep':
             if args and isinstance(args[0], (long, int)):
                 timeout += args[0]
             elif 'timeout' in kwargs:
@@ -200,7 +210,7 @@ class RemoteClass(Process):
     def _get_local_repr(self, path):
         try:
             obj = self._get_local_object(path)
-            return moves.reprlib.repr(obj)
+            return reprlib.repr(obj)
         except AttributeError:
             return None
 
@@ -244,13 +254,18 @@ class RemoteClass(Process):
 
         # copy at least serializable attributes and properties
         for name, member in inspect.getmembers(obj):
-            if name[0] == '_':  # skip private members
+            # skip private members and non-writable dunder methods.
+            if name[0] == '_':
+                if name in ['__weakref__']:
+                    continue
+                if name in ['__dict__']:
+                    continue
                 if not (name.startswith('__') and name.endswith('__')):
                     continue
             if callable(member) and not isinstance(member, property):
                 continue
             if not self._serializable(member):
-                continue
+                member = self._make_serializable(member)
             setattr(copy, name, member)
         return copy
 
@@ -266,7 +281,7 @@ class RemoteClass(Process):
             if type(obj) is tuple:
                 rv = tuple(rv)
             return rv
-        elif (isinstance(obj, Enum)):
+        elif (isinstance(obj, IntEnum) or isinstance(obj, IntFlag)):
             return obj.value
         else:
             return self._make_obj_serializable(obj)
@@ -297,7 +312,7 @@ class RemoteClass(Process):
 
     def quit_remote(self):
         """ Quit remote execution """
-        self._remote_exec(RemoteClass.QUIT, None, False)
+        self._remote_exec(RemoteClass.QUIT, None)
 
     def get_remote_value(self):
         """ Get value of a remotely held object """
@@ -349,32 +364,32 @@ class RemoteClass(Process):
 class RemoteVppTestCase(VppTestCase):
     """ Re-use VppTestCase to create remote VPP segment
 
-        In your test case:
+        In your test case::
 
-        @classmethod
-        def setUpClass(cls):
-            # fork new process before clinet connects to VPP
-            cls.remote_test = RemoteClass(RemoteVppTestCase)
+            @classmethod
+            def setUpClass(cls):
+                # fork new process before client connects to VPP
+                cls.remote_test = RemoteClass(RemoteVppTestCase)
 
-            # start remote process
-            cls.remote_test.start_remote()
+                # start remote process
+                cls.remote_test.start_remote()
 
-            # set up your test case
-            super(MyTestCase, cls).setUpClass()
+                # set up your test case
+                super(MyTestCase, cls).setUpClass()
 
-            # set up remote test
-            cls.remote_test.setUpClass(cls.tempdir)
+                # set up remote test
+                cls.remote_test.setUpClass(cls.tempdir)
 
-        @classmethod
-        def tearDownClass(cls):
-            # tear down remote test
-            cls.remote_test.tearDownClass()
+            @classmethod
+            def tearDownClass(cls):
+                # tear down remote test
+                cls.remote_test.tearDownClass()
 
-            # stop remote process
-            cls.remote_test.quit_remote()
+                # stop remote process
+                cls.remote_test.quit_remote()
 
-            # tear down your test case
-            super(MyTestCase, cls).tearDownClass()
+                # tear down your test case
+                super(MyTestCase, cls).tearDownClass()
     """
 
     def __init__(self):
@@ -401,6 +416,10 @@ class RemoteVppTestCase(VppTestCase):
         super(RemoteVppTestCase, cls).setUpClass()
         os.environ = orig_env
 
+    @classmethod
+    def tearDownClass(cls):
+        super(RemoteVppTestCase, cls).tearDownClass()
+
     @unittest.skip("Empty test")
     def emptyTest(self):
         """ Do nothing """