aboutsummaryrefslogtreecommitdiffstats
path: root/docs
AgeCommit message (Expand)AuthorFilesLines
2021-11-06tests docs: fix jsonschema dependencyDave Wallace1-2/+16
2021-11-02tests: update python packagesDave Wallace1-4/+1
2021-10-13docs: C & C++ apis examplesNathan Skrzypczak6-0/+346
2021-10-13docs: better docs, mv doxygen to sphinxNathan Skrzypczak361-12794/+25242
2021-09-28api: API trace improvementsFilip Tehlar3-66/+66
2021-08-17docs: fix missing dependency on pip-tools for docs-venvDave Wallace1-0/+2
2021-08-13tests docs: upgrade python packagesDave Wallace4-55/+8
2021-07-02ipsec: ADD/update IPSec documentationNeale Ranns1-0/+1
2021-06-11docs: cleanup, remove stale materialDave Barach77-2355/+15
2021-05-14vlib: pass node runtime to vlib_buffer_enqueue_to_thread()Damjan Marion1-1/+1
2021-05-01vlib: refactor trajectory trace debug featureBenoît Ganne1-4/+1
2021-04-21docs: document "make test-help"Dave Barach3-66/+208
2021-03-16docs: ikev2 usecasesFilip Tehlar6-2/+537
2021-03-04docs: Update macos doc to clang-formatNathan Skrzypczak1-15/+13
2021-02-12docs: fixing VPP tutorialArthur de Kerhor3-6/+6
2021-01-28build: do not _FORTIFY_SOURCE in debug modeMohammed Hawari1-3/+3
2021-01-27Change unformat_init_string API in doc to match codehemant_mnkcg1-1/+2
2021-01-22docs: vpp stateless traffic generatorDave Barach2-0/+106
2021-01-20build: add the missing leading underscore to FORTIFY_SOURCENeale Ranns1-8/+8
2021-01-14docs: Update FIB documentationNeale Ranns22-183/+1392
2020-12-21docs: update list of pluginsPaul Vinciguerra4-13/+80
2020-12-18docs: fix missing quotes in ubuntu install instructionsPaul Vinciguerra1-5/+5
2020-12-16docs: revise home gateway use-case documentationDave Barach3-286/+498
2020-12-07docs: Fix CentOS 8 buildJon Loeliger1-1/+7
2020-11-26docs: fix bihash doc bugsDave Barach1-19/+19
2020-11-24buffers: add page-size configNathan Skrzypczak1-0/+14
2020-11-16docs: fix memory troubleshooting docBenoît Ganne2-0/+4
2020-11-10vpp: use vpp heap for libcBenoît Ganne1-0/+84
2020-10-16misc: deprecate VOMDamjan Marion1-1/+1
2020-09-25docs: fix typo in bihash clib_bihash_search() documentationJon Loeliger1-2/+2
2020-09-21build: remove opensuse build infraDave Wallace5-75/+3
2020-09-16docs: improve plugin developer's guideDave Barach1-5/+55
2020-09-09docs: Improve new plugin doc & add govpp API docNathan Skrzypczak4-28/+142
2020-09-09docs: Update and improve indent installNathan Skrzypczak1-13/+28
2020-09-05docs: Improve & link cnat docNathan Skrzypczak2-0/+2
2020-08-13docs: correct fib tunnel diagram referenceChristian Hopps1-1/+1
2020-07-28docs: Update the VPP tutorialJohn DeNisco2-12/+21
2020-07-06docs: Reflect the fact that the DPDK is now a pluginJohn DeNisco2-10/+27
2020-06-23vlib: debug CLI macro expander, part deuxDave Barach1-0/+48
2020-06-16vlib: address sanitizer support for stack switch, enable clangDamjan Marion1-5/+5
2020-06-03docs: improve handoff queue writeupDave Barach1-0/+196
2020-05-29docs: Minor fixes in publish_docs.sh and sanitizer.rstJohn DeNisco2-0/+2
2020-05-20docs: asan: update doc to match current statusBenoît Ganne1-5/+5
2020-05-07misc: deprecate elftoolDamjan Marion1-1/+1
2020-05-06vppinfra: add timer wheel section to Sphinx docsDave Barach1-0/+117
2020-05-02vlib: add nosyslog unix optionRuslan Babayev1-0/+12
2020-04-28docs: add missing spelling dictionaryPaul Vinciguerra1-0/+774
2020-04-22misc: asan: disable leak sanitizer by defaultBenoît Ganne1-5/+3
2020-04-09docs: Fix the Use Cases IndexJohn DeNisco1-15/+15
2020-04-02docs: Fix venv under python3Paul Vinciguerra5-19/+32
# Get string representation of a remote object QUIT = 5 # Quit remote execution PIPE_PARENT = 0 # Parent end of the pipe PIPE_CHILD = 1 # Child end of the pipe DEFAULT_TIMEOUT = 2 # default timeout for an operation to execute def __init__(self, cls, *args, **kwargs): super(RemoteClass, self).__init__() self._cls = cls self._args = args self._kwargs = kwargs self._timeout = RemoteClass.DEFAULT_TIMEOUT self._pipe = Pipe() # pipe for input/output arguments def __repr__(self): return repr(RemoteClassAttr(self, None)) def __str__(self): return str(RemoteClassAttr(self, None)) def __call__(self, *args, **kwargs): return self.RemoteClassAttr(self, None)() def __getattr__(self, attr): if attr[0] == '_' or not self.is_alive(): if hasattr(super(RemoteClass, self), '__getattr__'): return super(RemoteClass, self).__getattr__(attr) raise AttributeError return RemoteClassAttr(self, attr) def __setattr__(self, attr, val): if attr[0] == '_' or not self.is_alive(): super(RemoteClass, self).__setattr__(attr, val) return setattr(RemoteClassAttr(self, None), attr, val) def _remote_exec(self, op, path=None, ret=True, *args, **kwargs): """ Execute given operation on a given, possibly nested, member remotely. """ # automatically resolve remote objects in the arguments mutable_args = list(args) for i, val in enumerate(mutable_args): if isinstance(val, RemoteClass) or \ isinstance(val, RemoteClassAttr): mutable_args[i] = val.get_remote_value() args = tuple(mutable_args) for key, val in kwargs.iteritems(): if isinstance(val, RemoteClass) or \ 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 args and isinstance(args[0], (long, int)): timeout += args[0] elif 'timeout' in kwargs: timeout += kwargs['timeout'] if not self._pipe[RemoteClass.PIPE_PARENT].poll(timeout): return None try: rv = self._pipe[RemoteClass.PIPE_PARENT].recv() rv = self._deserialize(rv) return rv except EOFError: return None def _get_local_object(self, path): """ Follow the path to obtain a reference on the addressed nested attribute """ obj = self._instance for attr in path: obj = getattr(obj, attr) return obj def _get_local_value(self, path): try: return self._get_local_object(path) except AttributeError: return None def _call_local_method(self, path, *args, **kwargs): try: method = self._get_local_object(path) return method(*args, **kwargs) except AttributeError: return None def _set_local_attr(self, path, value): try: obj = self._get_local_object(path[:-1]) setattr(obj, path[-1], value) except AttributeError: pass return None def _get_local_repr(self, path): try: obj = self._get_local_object(path) return repr(obj) except AttributeError: return None def _get_local_str(self, path): try: obj = self._get_local_object(path) return str(obj) except AttributeError: return None def _serializable(self, obj): """ Test if the given object is serializable """ try: dumps(obj) return True except: return False def _make_obj_serializable(self, obj): """ Make a serializable copy of an object. Members which are difficult/impossible to serialize are stripped. """ if self._serializable(obj): return obj # already serializable copy = SerializableClassCopy() # copy at least serializable attributes and properties for name, member in inspect.getmembers(obj): if name[0] == '_': # skip private members continue if callable(member) and not isinstance(member, property): continue if not self._serializable(member): continue setattr(copy, name, member) return copy def _make_serializable(self, obj): """ Make a serializable copy of an object or a list/tuple of objects. Members which are difficult/impossible to serialize are stripped. """ if (type(obj) is list) or (type(obj) is tuple): rv = [] for item in obj: rv.append(self._make_serializable(item)) if type(obj) is tuple: rv = tuple(rv) return rv else: return self._make_obj_serializable(obj) def _deserialize_obj(self, obj): return obj def _deserialize(self, obj): if (type(obj) is list) or (type(obj) is tuple): rv = [] for item in obj: rv.append(self._deserialize(item)) if type(obj) is tuple: rv = tuple(rv) return rv else: return self._deserialize_obj(obj) def start_remote(self): """ Start remote execution """ self.start() def quit_remote(self): """ Quit remote execution """ self._remote_exec(RemoteClass.QUIT, None, False) def get_remote_value(self): """ Get value of a remotely held object """ return RemoteClassAttr(self, None).get_remote_value() def set_request_timeout(self, timeout): """ Change request timeout """ self._timeout = timeout def run(self): """ Create instance of the wrapped class and execute operations on it as requested by the parent process. """ self._instance = self._cls(*self._args, **self._kwargs) while True: try: rv = None # get request from the parent process (op, path, args, kwargs) = self._pipe[RemoteClass.PIPE_CHILD].recv() args = self._deserialize(args) kwargs = self._deserialize(kwargs) path = path.split('.') if path else [] if op == RemoteClass.GET: rv = self._get_local_value(path) elif op == RemoteClass.CALL: rv = self._call_local_method(path, *args, **kwargs) elif op == RemoteClass.SETATTR and 'value' in kwargs: self._set_local_attr(path, kwargs['value']) elif op == RemoteClass.REPR: rv = self._get_local_repr(path) elif op == RemoteClass.STR: rv = self._get_local_str(path) elif op == RemoteClass.QUIT: break else: continue # send return value if not self._serializable(rv): rv = self._make_serializable(rv) self._pipe[RemoteClass.PIPE_CHILD].send(rv) except EOFError: break self._instance = None # destroy the instance @unittest.skip("Remote Vpp Test Case Class") class RemoteVppTestCase(VppTestCase): """ Re-use VppTestCase to create remote VPP segment In your test case: @classmethod def setUpClass(cls): # fork new process before clinet connects to VPP cls.remote_test = RemoteClass(RemoteVppTestCase) # start remote process cls.remote_test.start_remote() # set up your test case super(MyTestCase, cls).setUpClass() # set up remote test cls.remote_test.setUpClass(cls.tempdir) @classmethod def tearDownClass(cls): # tear down remote test cls.remote_test.tearDownClass() # stop remote process cls.remote_test.quit_remote() # tear down your test case super(MyTestCase, cls).tearDownClass() """ def __init__(self): super(RemoteVppTestCase, self).__init__("emptyTest") def __del__(self): if hasattr(self, "vpp"): cls.vpp.poll() if cls.vpp.returncode is None: cls.vpp.terminate() cls.vpp.communicate() @classmethod def setUpClass(cls, tempdir): # disable features unsupported in remote VPP orig_env = dict(os.environ) if 'STEP' in os.environ: del os.environ['STEP'] if 'DEBUG' in os.environ: del os.environ['DEBUG'] cls.tempdir_prefix = os.path.basename(tempdir) + "/" super(RemoteVppTestCase, cls).setUpClass() os.environ = orig_env @unittest.skip("Empty test") def emptyTest(self): """ Do nothing """ pass def setTestFunctionInfo(self, name, doc): """ Store the name and documentation string of currently executed test in the main VPP for logging purposes. """ self._testMethodName = name self._testMethodDoc = doc