papi: add wrapper to validate crc manifest
[vpp.git] / src / vpp-api / python / vpp_papi / vpp_papi.py
index 5af58a4..0ac86bb 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 #
 # Copyright (c) 2016 Cisco and/or its affiliates.
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -645,10 +645,9 @@ class VPPApiClient(object):
         # Block until we get a reply.
         rl = []
         while (True):
-            msg = self.transport.read()
-            if not msg:
+            r = self.read_blocking(no_type_conversion)
+            if r is None:
                 raise VPPIOError(2, 'VPP API client: read failed')
-            r = self.decode_incoming_msg(msg, no_type_conversion)
             msgname = type(r).__name__
             if context not in r or r.context == 0 or context != r.context:
                 # Message being queued
@@ -665,17 +664,24 @@ class VPPApiClient(object):
 
         self.transport.resume()
 
-        self.logger.debug('Return from {!r}'.format(r))
+        s = 'Return value: {!r}'.format(r)
+        if len(s) > 80:
+            s = s[:80] + "..."
+        self.logger.debug(s)
         return rl
 
     def _call_vpp_async(self, i, msg, **kwargs):
-        """Given a message, send the message and await a reply.
+        """Given a message, send the message and return the context.
 
         msgdef - the message packing definition
         i - the message type index
         context - context number - chosen at random if not
         supplied.
         The remainder of the kwargs are the arguments to the API call.
+
+        The reply message(s) will be delivered later to the registered callback.
+        The returned context will help with assigning which call
+        the reply belongs to.
         """
         if 'context' not in kwargs:
             context = self.get_context()
@@ -691,6 +697,34 @@ class VPPApiClient(object):
         b = msg.pack(kwargs)
 
         self.transport.write(b)
+        return context
+
+    def read_blocking(self, no_type_conversion=False):
+        """Get next received message from transport within timeout, decoded.
+
+        Note that noticifations have context zero
+        and are not put into receive queue (at least for socket transport),
+        use async_thread with registered callback for processing them.
+
+        If no message appears in the queue within timeout, return None.
+
+        Optionally, type conversion can be skipped,
+        as some of conversions are into less precise types.
+
+        When r is the return value of this, the caller can get message name as:
+            msgname = type(r).__name__
+        and context number (type long) as:
+            context = r.context
+
+        :param no_type_conversion: If false, type conversions are applied.
+        :type no_type_conversion: bool
+        :returns: Decoded message, or None if no message (within timeout).
+        :rtype: Whatever VPPType.unpack returns, depends on no_type_conversion.
+        """
+        msg = self.transport.read()
+        if not msg:
+            return None
+        return self.decode_incoming_msg(msg, no_type_conversion)
 
     def register_event_callback(self, callback):
         """Register a callback for async messages.
@@ -725,6 +759,34 @@ class VPPApiClient(object):
             if self.event_callback:
                 self.event_callback(msgname, r)
 
+    def validate_message_table(self, namecrctable):
+        """Take a dictionary of name_crc message names
+        and returns an array of missing messages"""
+
+        missing_table = []
+        for name_crc in namecrctable:
+            i = self.transport.get_msg_index(name_crc)
+            if i <= 0:
+                missing_table.append(name_crc)
+        return missing_table
+
+    def dump_message_table(self):
+        """Return VPPs API message table as name_crc dictionary"""
+        return self.transport.message_table
+
+    def dump_message_table_filtered(self, msglist):
+        """Return VPPs API message table as name_crc dictionary,
+        filtered by message name list."""
+
+        replies = [self.services[n]['reply'] for n in msglist]
+        message_table_filtered = {}
+        for name in msglist + replies:
+            for k,v in self.transport.message_table.items():
+                if k.startswith(name):
+                    message_table_filtered[k] = v
+                    break
+        return message_table_filtered
+
     def __repr__(self):
         return "<VPPApiClient apifiles=%s, testmode=%s, async_thread=%s, " \
                "logger=%s, read_timeout=%s, use_socket=%s, " \