nat: tweak rfc7857 tcp connection tracking
[vpp.git] / test / remote_test.py
index f5b3c62..19bad89 100644 (file)
@@ -1,33 +1,28 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 import inspect
 import os
 
 import inspect
 import os
+import reprlib
 import unittest
 from framework import VppTestCase
 from multiprocessing import Process, Pipe
 from pickle import dumps
 import unittest
 from framework import VppTestCase
 from multiprocessing import Process, Pipe
 from pickle import dumps
-import six
-from six import moves
 import sys
 import sys
-if sys.version_info <= (3, 4):
-    from aenum import IntEnum
-else:
-    from enum import IntEnum
 
 
-if sys.version_info <= (3, 6):
-    from aenum import IntFlag
-else:
-    from enum import IntFlag
+from enum import IntEnum, IntFlag
 
 
 
 
-class SerializableClassCopy(object):
+class SerializableClassCopy:
     """
     Empty class used as a basis for a serializable copy of another class.
     """
     pass
 
     """
     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.
     """
     """
     Wrapper around attribute of a remotely executed class.
     """
@@ -51,7 +46,8 @@ class RemoteClassAttr(object):
     def __getattr__(self, attr):
         if attr[0] == '_':
             if not (attr.startswith('__') and attr.endswith('__')):
     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
 
         self._path.append(attr)
         return self
 
@@ -62,34 +58,44 @@ class RemoteClassAttr(object):
                 return
         self._path.append(attr)
         self._remote._remote_exec(RemoteClass.SETATTR, self.path_to_str(),
                 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(),
 
     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.
 
 
 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:
     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
     """
 
     GET = 0       # Get attribute remotely
@@ -113,7 +119,7 @@ class RemoteClass(Process):
         self._pipe = Pipe()  # pipe for input/output arguments
 
     def __repr__(self):
         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))
 
     def __str__(self):
         return str(RemoteClassAttr(self, None))
@@ -126,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)
             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):
         return RemoteClassAttr(self, attr)
 
     def __setattr__(self, attr, val):
@@ -136,7 +142,7 @@ class RemoteClass(Process):
                 return
         setattr(RemoteClassAttr(self, None), attr, val)
 
                 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.
         """
         """
         Execute given operation on a given, possibly nested, member remotely.
         """
@@ -144,23 +150,20 @@ class RemoteClass(Process):
         mutable_args = list(args)
         for i, val in enumerate(mutable_args):
             if isinstance(val, RemoteClass) or \
         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)
                 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 \
             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))
                 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
         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:
             if args and isinstance(args[0], (long, int)):
                 timeout += args[0]
             elif 'timeout' in kwargs:
@@ -207,7 +210,7 @@ class RemoteClass(Process):
     def _get_local_repr(self, path):
         try:
             obj = self._get_local_object(path)
     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
 
         except AttributeError:
             return None
 
@@ -251,13 +254,18 @@ class RemoteClass(Process):
 
         # copy at least serializable attributes and properties
         for name, member in inspect.getmembers(obj):
 
         # 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):
                 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
 
             setattr(copy, name, member)
         return copy
 
@@ -304,7 +312,7 @@ class RemoteClass(Process):
 
     def quit_remote(self):
         """ Quit remote execution """
 
     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 """
 
     def get_remote_value(self):
         """ Get value of a remotely held object """
@@ -356,32 +364,32 @@ class RemoteClass(Process):
 class RemoteVppTestCase(VppTestCase):
     """ Re-use VppTestCase to create remote VPP segment
 
 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):
     """
 
     def __init__(self):
@@ -408,6 +416,10 @@ class RemoteVppTestCase(VppTestCase):
         super(RemoteVppTestCase, cls).setUpClass()
         os.environ = orig_env
 
         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 """
     @unittest.skip("Empty test")
     def emptyTest(self):
         """ Do nothing """