fixing support for group desc stats

Change-Id: I3d0d9c22e05e58b13b0fdc92fbc672590bb3dd18
diff --git a/ofagent/converter.py b/ofagent/converter.py
index 2a221b7..6855c56 100644
--- a/ofagent/converter.py
+++ b/ofagent/converter.py
@@ -117,35 +117,40 @@
         loxi_match_fields.append(make_loxi_field(oxm_field))
     return of13.match_v3(oxm_list=loxi_match_fields)
 
+
+def make_loxi_action(a):
+    if type(a) is not dict:
+        a = pb2dict(a)
+
+    typ = a.get('type', 0)
+
+    if typ == pb2.OFPAT_OUTPUT:
+        output_kws = a['output']
+        return of13.action.output(**output_kws)
+
+    elif typ == pb2.OFPAT_POP_VLAN:
+        return of13.action.pop_vlan()
+
+    elif typ == pb2.OFPAT_PUSH_VLAN:
+        push_vlan_kws = a['push']
+        return of13.action.push_vlan(**push_vlan_kws)
+
+    elif typ == pb2.OFPAT_SET_FIELD:
+        loxi_field = make_loxi_field(a['set_field']['field'])
+        return of13.action.set_field(loxi_field)
+
+    elif typ == pb2.OFPAT_GROUP:
+        group_kws = a['group']
+        return of13.action.group(**group_kws)
+
+    else:
+        raise NotImplementedError(
+            'Action decoder for action OFPAT_* %d' % typ)
+
+
 def ofp_flow_stats_to_loxi_flow_stats(pb):
     kw = pb2dict(pb)
 
-    def make_loxi_action(a):
-        type = a.get('type', 0)
-
-        if type == pb2.OFPAT_OUTPUT:
-            output_kws = a['output']
-            return of13.action.output(**output_kws)
-
-        elif type == pb2.OFPAT_POP_VLAN:
-            return of13.action.pop_vlan()
-
-        elif type == pb2.OFPAT_PUSH_VLAN:
-            push_vlan_kws = a['push']
-            return of13.action.push_vlan(**push_vlan_kws)
-
-        elif type == pb2.OFPAT_SET_FIELD:
-            loxi_field = make_loxi_field(a['set_field']['field'])
-            return of13.action.set_field(loxi_field)
-
-        elif type == pb2.OFPAT_GROUP:
-            group_kws = a['group']
-            return of13.action.group(**group_kws)
-
-        else:
-            raise NotImplementedError(
-                'Action decoder for action OFPAT_* %d' % type)
-
     def make_loxi_instruction(inst):
         type = inst['type']
         if type == pb2.OFPIT_APPLY_ACTIONS:
@@ -176,16 +181,22 @@
     )
     return packet_in
 
+def ofp_group_desc_to_loxi_group_desc(pb):
+    return of13.group_desc_stats_entry(
+        group_type=pb.type,
+        group_id=pb.group_id,
+        buckets=[to_loxi(bucket) for bucket in pb.buckets])
 
-def ofp_group_entry_to_loxi_group_entry(pb):
+
+def ofp_group_stats_to_loxi_group_stats(pb):
     return of13.group_stats_entry(
-        group_id=pb.stats.group_id,
-        ref_count=pb.stats.ref_count,
-        packet_count=pb.stats.packet_count,
-        byte_count=pb.stats.byte_count,
-        duration_sec=pb.stats.duration_sec,
-        duration_nsec=pb.stats.duration_nsec,
-        bucket_stats=[to_loxi(bstat) for bstat in pb.stats.bucket_stats])
+        group_id=pb.group_id,
+        ref_count=pb.ref_count,
+        packet_count=pb.packet_count,
+        byte_count=pb.byte_count,
+        duration_sec=pb.duration_sec,
+        duration_nsec=pb.duration_nsec,
+        bucket_stats=[to_loxi(bstat) for bstat in pb.bucket_stats])
 
 
 def ofp_bucket_counter_to_loxy_bucket_counter(pb):
@@ -194,13 +205,25 @@
         byte_count=pb.byte_count)
 
 
+def ofp_bucket_to_loxi_bucket(pb):
+    return of13.bucket(
+        weight=pb.weight,
+        watch_port=pb.watch_port,
+        watch_group=pb.watch_group,
+        actions=[to_loxi(action) for action in pb.actions]
+    )
+
+
 to_loxi_converters = {
     'ofp_port': ofp_port_to_loxi_port_desc,
     'ofp_port_status': ofp_port_status_to_loxi_port_status,
     'ofp_flow_stats': ofp_flow_stats_to_loxi_flow_stats,
     'ofp_packet_in': ofp_packet_in_to_loxi_packet_in,
-    'ofp_group_entry': ofp_group_entry_to_loxi_group_entry,
-    'ofp_bucket_counter': ofp_bucket_counter_to_loxy_bucket_counter
+    'ofp_group_stats': ofp_group_stats_to_loxi_group_stats,
+    'ofp_group_desc': ofp_group_desc_to_loxi_group_desc,
+    'ofp_bucket_counter': ofp_bucket_counter_to_loxy_bucket_counter,
+    'ofp_bucket': ofp_bucket_to_loxi_bucket,
+    'ofp_action': make_loxi_action
 }
 
 
diff --git a/ofagent/of_protocol_handler.py b/ofagent/of_protocol_handler.py
index d0b71e3..586055d 100644
--- a/ofagent/of_protocol_handler.py
+++ b/ofagent/of_protocol_handler.py
@@ -179,12 +179,13 @@
     def handle_group_stats_request(self, req):
         group_stats = yield self.rpc.list_groups(self.device_id)
         self.cxn.send(ofp.message.group_stats_reply(
-            xid=req.xid, entries=[to_loxi(g) for g  in group_stats]))
+            xid=req.xid, entries=[to_loxi(g.stats) for g  in group_stats]))
 
+    @inlineCallbacks
     def handle_group_descriptor_request(self, req):
-        group_list = []  # TODO
+        group_stats = yield self.rpc.list_groups(self.device_id)
         self.cxn.send(ofp.message.group_desc_stats_reply(
-            xid=req.xid, entries=group_list))
+            xid=req.xid, entries=[to_loxi(g.desc) for g  in group_stats]))
 
     def handle_group_features_request(self, req):
         raise NotImplementedError()
diff --git a/tests/utests/ofagent/test_converter.py b/tests/utests/ofagent/test_converter.py
index e84108a..b4d0e85 100644
--- a/tests/utests/ofagent/test_converter.py
+++ b/tests/utests/ofagent/test_converter.py
@@ -128,6 +128,8 @@
             (3, 0xe4010103, (2,)),
             (4, 0xe4010104, (1, 2)),
         )
+
+        group_stats = []
         for group_id, mcast_addr, ports in mcast_setup:
             # self.lda.update_group_table(mk_multicast_group_mod(
             #     group_id=group_id,
@@ -149,6 +151,16 @@
                     group(group_id)
                 ]
             ))
+            group_stats.append(group_entry_from_group_mod(
+                mk_multicast_group_mod(
+                 group_id=group_id,
+                 buckets=[
+                     ofp.ofp_bucket(actions=[
+                         pop_vlan(),
+                         output(port)
+                     ]) for port in ports
+                 ])))
+
 
         # Unicast channels for each subscriber
         # Downstream flow 1 for both
@@ -194,13 +206,22 @@
                 ]
             ))
 
-        return flow_stats
+        return (flow_stats, group_stats)
 
     def test_flow_spec_pb_to_loxi_conversion(self):
-        flow_stats = self.gen_pb_flow_stats()
+        flow_stats, _ = self.gen_pb_flow_stats()
         for flow_stat in flow_stats:
             loxi_flow_stats = to_loxi(flow_stat)
 
+    def test_group_stat_spec_pb_to_loxi_conversion(self):
+        _, group_stats = self.gen_pb_flow_stats()
+        for group_stat in group_stats:
+            loxi_group_stat = to_loxi(group_stat.stats)
+
+    def test_group_desc_spec_pb_to_loxi_conversion(self):
+        _, group_stats = self.gen_pb_flow_stats()
+        for group_stat in group_stats:
+            loxi_group_desc = to_loxi(group_stat.desc)
 
 if __name__ == '__main__':
     main()