Esempio n. 1
0
class TestGraph(unittest.TestCase):

    def setUp(self):
        rospy.init_node('test_graph')
        self.graph = Graph()

    def test_graph(self):
        flips = None
        while not flips:
            printtest("Waiting for flips")
            self.graph.update()
            flips = self.graph._local_gateway.flip_watchlist
            rospy.rostime.wallsleep(0.2)
        printtest("********************************************************************")
        printtest("* Local Gateway")
        printtest("********************************************************************")
        printtest("%s" % self.graph._local_gateway)
        self.assertEquals("5", str(len(flips)))
        # TODO: this is currently returning the base name, is should be returning the hash name

        self.assertEquals(len([flip for flip in flips if flip.gateway == "remote_gateway" and flip.rule.name == "/add_two_ints" and flip.rule.type == "service"]), 1)
        self.assertEquals(len([flip for flip in flips if flip.gateway == "remote_gateway" and flip.rule.name == "/chatter" and flip.rule.type == "publisher"]), 1)
        self.assertEquals(len([flip for flip in flips if flip.gateway == "remote_gateway" and flip.rule.name == "/chatter" and flip.rule.type == "subscriber"]), 1)
        self.assertEquals(len([flip for flip in flips if flip.gateway == "remote_gateway" and flip.rule.name == "/fibonacci" and flip.rule.type == "action_server"]), 1)
        self.assertEquals(len([flip for flip in flips if flip.gateway == "remote_gateway" and flip.rule.name == "/fibonacci" and flip.rule.type == "action_client"]), 1)
        
        printtest("********************************************************************")
        printtest("* Remote Gateway")
        printtest("********************************************************************")
        printtest("%s" % self.graph._remote_gateways)
        for remote_gateway in self.graph._remote_gateways:
            self.assertEquals("remote_gateway", rocon_gateway_utils.gateway_basename(remote_gateway.name))

    def tearDown(self):
        pass
Esempio n. 2
0
 def setUp(self):
     print(
         "\n********************************************************************"
     )
     print("* Pull Tests Setup")
     print(
         "********************************************************************"
     )
     rospy.init_node('test_pulls')
     self.graph = Graph()
Esempio n. 3
0
class TestGraph(unittest.TestCase):
    def setUp(self):
        rospy.init_node('test_graph')
        self.graph = Graph()

    def test_graph(self):
        flips = None
        while not flips:
            printtest("Waiting for flips")
            self.graph.update()
            flips = self.graph._local_gateway.flip_watchlist
            rospy.sleep(0.2)
        printtest(
            "********************************************************************"
        )
        printtest("* Local Gateway")
        printtest(
            "********************************************************************"
        )
        printtest("%s" % self.graph._local_gateway)
        self.assertEquals("1", str(len(flips)))
        # TODO: this is currently returning the base name, is should be returning the hash name
        self.assertEquals("remote_gateway", flips[0].gateway)
        self.assertEquals("publisher", flips[0].rule.type)
        self.assertEquals("/chatter", flips[0].rule.name)

        printtest(
            "********************************************************************"
        )
        printtest("* Remote Gateway")
        printtest(
            "********************************************************************"
        )
        printtest("%s" % self.graph._remote_gateways)
        for remote_gateway in self.graph._remote_gateways:
            self.assertEquals(
                "remote_gateway",
                rocon_utilities.gateway_basename(remote_gateway.name))

    def tearDown(self):
        pass
Esempio n. 4
0
 def setUp(self):
     rospy.init_node('test_graph')
     self.graph = Graph()
Esempio n. 5
0
 def setUp(self):
     rospy.init_node('test_pullments')
     self.graph = Graph()
Esempio n. 6
0
class TestFlips(unittest.TestCase):
    def setUp(self):
        rospy.init_node('test_pullments')
        self.graph = Graph()

    def test_flip_all(self):
        print(
            "\n********************************************************************"
        )
        print("* Flip All")
        print(
            "********************************************************************"
        )
        try:
            samples.flip_all()
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when flipping all connections [%s]" %
                str(e))
        flipped_interface = self._wait_for_flipped_interface()
        #print("%s" % self.graph._local_gateway)
        self.assertEquals("2", str(len(flipped_interface)))
        for remote_rule in flipped_interface:
            self.assertEquals("/chatter", remote_rule.remote_rule.rule.name)
            # Should probably assert rule.type and rule.node here as well.
        # Revert state
        try:
            samples.flip_all(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unflipping all connections [%s]" %
                str(e))
        self._assert_cleared_flipped_interface()

    def test_flip_tutorials(self):
        print(
            "\n********************************************************************"
        )
        print("* Flip Tutorials")
        print(
            "********************************************************************"
        )
        try:
            samples.flip_tutorials()
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when flipping tutorial connections.")
        flipped_interface = self._wait_for_flipped_interface()
        #print("%s" % self.graph._local_gateway)
        self.assertIn("/chatter", [
            remote_rule.remote_rule.rule.name
            for remote_rule in flipped_interface
        ])
        try:
            samples.flip_tutorials(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unflipping tutorial connections.")
        self._assert_cleared_flipped_interface()

    def test_flip_regex_tutorials(self):
        print(
            "\n********************************************************************"
        )
        print("* Flip Regex Tutorials")
        print(
            "********************************************************************"
        )
        try:
            samples.flip_tutorials(regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when flipping tutorial connections.")
        flipped_interface = self._wait_for_flipped_interface()
        print("%s" % self.graph._local_gateway)
        self.assertIn("/chatter", [
            remote_rule.remote_rule.rule.name
            for remote_rule in flipped_interface
        ])
        try:
            samples.flip_tutorials(cancel=True, regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unflipping tutorial connections.")
        self._assert_cleared_flipped_interface()

    def tearDown(self):
        pass

    ##########################################################################
    # Utility methods
    ##########################################################################

    def _wait_for_flipped_interface(self):
        flipped_interface = None
        while not flipped_interface:
            self.graph.update()
            flipped_interface = self.graph._local_gateway.flipped_connections
            rospy.sleep(0.2)
        return flipped_interface

    def _assert_cleared_flipped_interface(self):
        start_time = rospy.Time.now()
        while True:
            self.graph.update()
            flipped_interface = self.graph._local_gateway.flipped_connections
            if flipped_interface:
                result = "cleared"
                break
            else:
                rospy.sleep(0.2)
            if rospy.Time.now() - start_time > rospy.Duration(1.0):
                result = "timed out waiting for flipped interface to clear"
                break
        self.assertEqual("cleared", result)
Esempio n. 7
0
 def setUp(self):
     rospy.init_node('test_advertisements')
     self.graph = Graph()
Esempio n. 8
0
class TestGraph(unittest.TestCase):

    def setUp(self):
        rospy.init_node('test_advertisements')
        self.graph = Graph()

    def test_advertise_all(self):
        print("\n********************************************************************")
        print("* Advertise All")
        print("********************************************************************")
        try:
            samples.advertise_all()
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when advertising all connections.")
        public_interface = self._wait_for_public_interface()
        #print("%s" % self.graph._local_gateway)
        self.assertEquals("2", str(len(public_interface)))
        for rule in public_interface:
            self.assertEquals("/chatter", rule.name)
            # Should probably assert rule.type and rule.node here as well.
        # Revert state
        try:
            samples.advertise_all(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when unadvertising all connections.")
        self._assert_cleared_public_interface()

    def test_advertise_tutorials(self):
        print("\n********************************************************************")
        print("* Advertise Tutorials")
        print("********************************************************************")
        try:
            samples.advertise_tutorials() 
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when advertising tutorial connections.")
        public_interface = self._wait_for_public_interface()
        #print("%s" % self.graph._local_gateway)
        self.assertIn("/chatter", [rule.name for rule in public_interface])
        try:
            samples.advertise_tutorials(cancel=True) 
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when unadvertising tutorial connections.")
        self._assert_cleared_public_interface()

    def test_advertise_regex_tutorials(self):
        print("\n********************************************************************")
        print("* Advertise Regex Tutorials")
        print("********************************************************************")
        try:
            samples.advertise_tutorials(regex_patterns=True) 
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when advertising tutorial connections.")
        public_interface = self._wait_for_public_interface()
        print("%s" % self.graph._local_gateway)
        self.assertIn("/chatter", [rule.name for rule in public_interface])
        try:
            samples.advertise_tutorials(cancel=True, regex_patterns=True) 
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when unadvertising tutorial connections.")
        self._assert_cleared_public_interface()
        
    def tearDown(self):
        pass

    ##########################################################################
    # Utility methods
    ##########################################################################

    def _wait_for_public_interface(self):
        public_interface = None
        while not public_interface:
            self.graph.update()
            public_interface = self.graph._local_gateway.public_interface
            rospy.rostime.wallsleep(0.2)
        return public_interface

    def _assert_cleared_public_interface(self):
        start_time = rospy.Time.now()
        while True:
            self.graph.update()
            public_interface = self.graph._local_gateway.public_interface
            if public_interface:
                result = "cleared"
                break
            else:
                rospy.rostime.wallsleep(0.2)
            if rospy.Time.now() - start_time > rospy.Duration(2.0):
                result = "timed out waiting for public interface to clear"
                break
        self.assertEqual("cleared", result)
Esempio n. 9
0
    def __init__(self, context):
        super(GatewayGraph, self).__init__(context)
        self.initialised = False
        self.setObjectName('Gateway Graph')
        self._current_dotcode = None

        self._widget = QWidget()

        # factory builds generic dotcode items
        self.dotcode_factory = PydotFactory()
        # self.dotcode_factory = PygraphvizFactory()
        self.dotcode_generator = RosGraphDotcodeGenerator()
        self.dot_to_qt = DotToQtGenerator()
        self._graph = Graph()

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_gateway_graph'), 'ui',
                               'gateway_graph.ui')
        #ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ui', 'gateway_graph.ui')
        loadUi(ui_file, self._widget,
               {'InteractiveGraphicsView': InteractiveGraphicsView})
        self._widget.setObjectName('GatewayGraphUi')
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)

        self._widget.refresh_graph_push_button.setIcon(
            QIcon.fromTheme('view-refresh'))
        self._widget.refresh_graph_push_button.pressed.connect(
            self._update_gateway_graph)

        self._widget.graph_type_combo_box.insertItem(0, self.tr('Gateways'),
                                                     GATEWAY_GATEWAY_GRAPH)
        self._widget.graph_type_combo_box.insertItem(
            1, self.tr('Pulled Connections'), GATEWAY_PULLED_GRAPH)
        self._widget.graph_type_combo_box.insertItem(
            2, self.tr('Flipped Connections'), GATEWAY_FLIPPED_GRAPH)
        self._widget.graph_type_combo_box.setCurrentIndex(0)
        self._widget.graph_type_combo_box.currentIndexChanged.connect(
            self._refresh_rosgraph)

        self.node_completionmodel = NamespaceCompletionModel(
            self._widget.filter_line_edit, False)
        completer = RepeatedWordCompleter(self.node_completionmodel, self)
        completer.setCompletionMode(QCompleter.PopupCompletion)
        completer.setWrapAround(True)
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.filter_line_edit.editingFinished.connect(
            self._refresh_rosgraph)
        self._widget.filter_line_edit.setCompleter(completer)
        self.topic_completionmodel = NamespaceCompletionModel(
            self._widget.topic_filter_line_edit, False)
        topic_completer = RepeatedWordCompleter(self.topic_completionmodel,
                                                self)
        topic_completer.setCompletionMode(QCompleter.PopupCompletion)
        topic_completer.setWrapAround(True)
        topic_completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.topic_filter_line_edit.editingFinished.connect(
            self._refresh_rosgraph)
        self._widget.topic_filter_line_edit.setCompleter(topic_completer)

        self._widget.namespace_cluster_check_box.clicked.connect(
            self._refresh_rosgraph)
        self._widget.watchlist_check_box.clicked.connect(
            self._refresh_rosgraph)
        self._widget.all_advertisements_check_box.clicked.connect(
            self._refresh_rosgraph)

        self._widget.highlight_connections_check_box.toggled.connect(
            self._redraw_graph_view)
        self._widget.auto_fit_graph_check_box.toggled.connect(
            self._redraw_graph_view)
        self._widget.fit_in_view_push_button.setIcon(
            QIcon.fromTheme('zoom-original'))
        self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view)

        self._widget.load_dot_push_button.setIcon(
            QIcon.fromTheme('document-open'))
        self._widget.load_dot_push_button.pressed.connect(self._load_dot)
        self._widget.save_dot_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_dot_push_button.pressed.connect(self._save_dot)
        self._widget.save_as_svg_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_as_svg_push_button.pressed.connect(self._save_svg)
        self._widget.save_as_image_push_button.setIcon(
            QIcon.fromTheme('image'))
        self._widget.save_as_image_push_button.pressed.connect(
            self._save_image)

        self._update_gateway_graph()
        self._deferred_fit_in_view.connect(self._fit_in_view,
                                           Qt.QueuedConnection)
        self._deferred_fit_in_view.emit()
        context.add_widget(self._widget)
Esempio n. 10
0
class GatewayGraph(Plugin):

    _deferred_fit_in_view = Signal()

    def __init__(self, context):
        super(GatewayGraph, self).__init__(context)
        self.initialised = False
        self.setObjectName('Gateway Graph')
        self._current_dotcode = None

        self._widget = QWidget()

        # factory builds generic dotcode items
        self.dotcode_factory = PydotFactory()
        # self.dotcode_factory = PygraphvizFactory()
        self.dotcode_generator = RosGraphDotcodeGenerator()
        self.dot_to_qt = DotToQtGenerator()
        self._graph = Graph()

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_gateway_graph'), 'ui',
                               'gateway_graph.ui')
        #ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ui', 'gateway_graph.ui')
        loadUi(ui_file, self._widget,
               {'InteractiveGraphicsView': InteractiveGraphicsView})
        self._widget.setObjectName('GatewayGraphUi')
        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))

        self._scene = QGraphicsScene()
        self._scene.setBackgroundBrush(Qt.white)
        self._widget.graphics_view.setScene(self._scene)

        self._widget.refresh_graph_push_button.setIcon(
            QIcon.fromTheme('view-refresh'))
        self._widget.refresh_graph_push_button.pressed.connect(
            self._update_gateway_graph)

        self._widget.graph_type_combo_box.insertItem(0, self.tr('Gateways'),
                                                     GATEWAY_GATEWAY_GRAPH)
        self._widget.graph_type_combo_box.insertItem(
            1, self.tr('Pulled Connections'), GATEWAY_PULLED_GRAPH)
        self._widget.graph_type_combo_box.insertItem(
            2, self.tr('Flipped Connections'), GATEWAY_FLIPPED_GRAPH)
        self._widget.graph_type_combo_box.setCurrentIndex(0)
        self._widget.graph_type_combo_box.currentIndexChanged.connect(
            self._refresh_rosgraph)

        self.node_completionmodel = NamespaceCompletionModel(
            self._widget.filter_line_edit, False)
        completer = RepeatedWordCompleter(self.node_completionmodel, self)
        completer.setCompletionMode(QCompleter.PopupCompletion)
        completer.setWrapAround(True)
        completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.filter_line_edit.editingFinished.connect(
            self._refresh_rosgraph)
        self._widget.filter_line_edit.setCompleter(completer)
        self.topic_completionmodel = NamespaceCompletionModel(
            self._widget.topic_filter_line_edit, False)
        topic_completer = RepeatedWordCompleter(self.topic_completionmodel,
                                                self)
        topic_completer.setCompletionMode(QCompleter.PopupCompletion)
        topic_completer.setWrapAround(True)
        topic_completer.setCaseSensitivity(Qt.CaseInsensitive)
        self._widget.topic_filter_line_edit.editingFinished.connect(
            self._refresh_rosgraph)
        self._widget.topic_filter_line_edit.setCompleter(topic_completer)

        self._widget.namespace_cluster_check_box.clicked.connect(
            self._refresh_rosgraph)
        self._widget.watchlist_check_box.clicked.connect(
            self._refresh_rosgraph)
        self._widget.all_advertisements_check_box.clicked.connect(
            self._refresh_rosgraph)

        self._widget.highlight_connections_check_box.toggled.connect(
            self._redraw_graph_view)
        self._widget.auto_fit_graph_check_box.toggled.connect(
            self._redraw_graph_view)
        self._widget.fit_in_view_push_button.setIcon(
            QIcon.fromTheme('zoom-original'))
        self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view)

        self._widget.load_dot_push_button.setIcon(
            QIcon.fromTheme('document-open'))
        self._widget.load_dot_push_button.pressed.connect(self._load_dot)
        self._widget.save_dot_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_dot_push_button.pressed.connect(self._save_dot)
        self._widget.save_as_svg_push_button.setIcon(
            QIcon.fromTheme('document-save-as'))
        self._widget.save_as_svg_push_button.pressed.connect(self._save_svg)
        self._widget.save_as_image_push_button.setIcon(
            QIcon.fromTheme('image'))
        self._widget.save_as_image_push_button.pressed.connect(
            self._save_image)

        self._update_gateway_graph()
        self._deferred_fit_in_view.connect(self._fit_in_view,
                                           Qt.QueuedConnection)
        self._deferred_fit_in_view.emit()
        context.add_widget(self._widget)

    def save_settings(self, plugin_settings, instance_settings):
        instance_settings.set_value(
            'graph_type_combo_box_index',
            self._widget.graph_type_combo_box.currentIndex())
        instance_settings.set_value('filter_line_edit_text',
                                    self._widget.filter_line_edit.text())
        instance_settings.set_value('topic_filter_line_edit_text',
                                    self._widget.topic_filter_line_edit.text())
        instance_settings.set_value(
            'namespace_cluster_check_box_state',
            self._widget.namespace_cluster_check_box.isChecked())
        instance_settings.set_value(
            'watchlist_check_box_state',
            self._widget.watchlist_check_box.isChecked())
        instance_settings.set_value(
            'all_advertisements_check_box_state',
            self._widget.all_advertisements_check_box.isChecked())
        instance_settings.set_value(
            'auto_fit_graph_check_box_state',
            self._widget.auto_fit_graph_check_box.isChecked())
        instance_settings.set_value(
            'highlight_connections_check_box_state',
            self._widget.highlight_connections_check_box.isChecked())

    def restore_settings(self, plugin_settings, instance_settings):
        self._widget.graph_type_combo_box.setCurrentIndex(
            int(instance_settings.value('graph_type_combo_box_index', 0)))
        self._widget.filter_line_edit.setText(
            instance_settings.value('filter_line_edit_text', ''))
        self._widget.topic_filter_line_edit.setText(
            instance_settings.value('topic_filter_line_edit_text', '/'))
        self._widget.namespace_cluster_check_box.setChecked(
            instance_settings.value('namespace_cluster_check_box_state', True)
            in [True, 'true'])
        self._widget.watchlist_check_box.setChecked(
            instance_settings.value('watchlist_check_box_state', True) in
            [True, 'true'])
        self._widget.all_advertisements_check_box.setChecked(
            instance_settings.value('all_advertisements_check_box_state',
                                    False) in [False, 'false'])
        self._widget.auto_fit_graph_check_box.setChecked(
            instance_settings.value('auto_fit_graph_check_box_state', True) in
            [True, 'true'])
        self._widget.highlight_connections_check_box.setChecked(
            instance_settings.value('highlight_connections_check_box_state',
                                    True) in [True, 'true'])
        self.initialised = True
        self._refresh_rosgraph()

    def shutdown_plugin(self):
        pass

    def _update_gateway_graph(self):
        # re-enable controls customizing fetched ROS graph
        self._widget.graph_type_combo_box.setEnabled(True)
        self._widget.filter_line_edit.setEnabled(True)
        self._widget.topic_filter_line_edit.setEnabled(True)
        self._widget.namespace_cluster_check_box.setEnabled(True)
        self._widget.watchlist_check_box.setEnabled(True)
        self._widget.all_advertisements_check_box.setEnabled(True)

        self._graph.update()
        self.node_completionmodel.refresh(self._graph.gateway_nodes)
        self.topic_completionmodel.refresh(self._graph.flipped_nodes)
        self._refresh_rosgraph()

    def _refresh_rosgraph(self):
        if not self.initialised:
            return
        self._update_graph_view(self._generate_dotcode())

    def _generate_dotcode(self):
        ns_filter = self._widget.filter_line_edit.text()
        topic_filter = self._widget.topic_filter_line_edit.text()
        graph_mode = self._widget.graph_type_combo_box.itemData(
            self._widget.graph_type_combo_box.currentIndex())
        orientation = 'LR'
        if self._widget.namespace_cluster_check_box.isChecked():
            namespace_cluster = 1
        else:
            namespace_cluster = 0
        hide_dead_end_topics = self._widget.watchlist_check_box.isChecked()
        show_all_advertisements = self._widget.all_advertisements_check_box.isChecked(
        )

        return self.dotcode_generator.generate_dotcode(
            rosgraphinst=self._graph,
            ns_filter=ns_filter,
            topic_filter=topic_filter,
            graph_mode=graph_mode,
            show_all_advertisements=show_all_advertisements,
            hide_dead_end_topics=hide_dead_end_topics,
            cluster_namespaces_level=namespace_cluster,
            dotcode_factory=self.dotcode_factory,
            orientation=orientation,
        )

    def _update_graph_view(self, dotcode):
        if dotcode == self._current_dotcode:
            return
        self._current_dotcode = dotcode
        self._redraw_graph_view()

    def _generate_tool_tip(self, url):
        if url is not None and ':' in url:
            item_type, item_path = url.split(':', 1)
            if item_type == 'node':
                tool_tip = 'Node:\n  %s' % (item_path)
                service_names = rosservice.get_service_list(node=item_path)
                if service_names:
                    tool_tip += '\nServices:'
                    for service_name in service_names:
                        try:
                            service_type = rosservice.get_service_type(
                                service_name)
                            tool_tip += '\n  %s [%s]' % (service_name,
                                                         service_type)
                        except rosservice.ROSServiceIOException as e:
                            tool_tip += '\n  %s' % (e)
                return tool_tip
            elif item_type == 'topic':
                topic_type, topic_name, _ = rostopic.get_topic_type(item_path)
                return 'Topic:\n  %s\nType:\n  %s' % (topic_name, topic_type)
        return url

    def _redraw_graph_view(self):
        self._scene.clear()

        if self._widget.highlight_connections_check_box.isChecked():
            highlight_level = 3
        else:
            highlight_level = 1

        # layout graph and create qt items
        (nodes, edges) = self.dot_to_qt.dotcode_to_qt_items(
            self._current_dotcode,
            highlight_level=highlight_level,
            same_label_siblings=True)

        # if we wish to make special nodes, do that here (maybe subclass GraphItem, just like NodeItem does)
        for node_item in nodes.itervalues():
            if node_item._label.text() == self._graph.local_gateway_name():
                orange = QColor(232, 132, 3)
                node_item._default_color = orange
                node_item.set_color(orange)
                print "Local gateway: %s" % self._graph.local_gateway_name()
            self._scene.addItem(node_item)
        for edge_items in edges.itervalues():
            for edge_item in edge_items:
                edge_item.add_to_scene(self._scene)

        self._scene.setSceneRect(self._scene.itemsBoundingRect())
        if self._widget.auto_fit_graph_check_box.isChecked():
            self._fit_in_view()

    def _load_dot(self, file_name=None):
        if file_name is None:
            file_name, _ = QFileDialog.getOpenFileName(
                self._widget, self.tr('Open graph from file'), None,
                self.tr('DOT graph (*.dot)'))
            if file_name is None or file_name == '':
                return

        try:
            fh = open(file_name, 'rb')
            dotcode = fh.read()
            fh.close()
        except IOError:
            return

        # disable controls customizing fetched ROS graph
        self._widget.graph_type_combo_box.setEnabled(False)
        self._widget.filter_line_edit.setEnabled(False)
        self._widget.topic_filter_line_edit.setEnabled(False)
        self._widget.namespace_cluster_check_box.setEnabled(False)
        self._widget.watchlist_check_box.setEnabled(False)
        self._widget.all_advertisements_check_box.setEnabled(False)

        self._update_graph_view(dotcode)

    def _fit_in_view(self):
        self._widget.graphics_view.fitInView(self._scene.itemsBoundingRect(),
                                             Qt.KeepAspectRatio)

    def _save_dot(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self._widget, self.tr('Save as DOT'), 'rosgraph.dot',
            self.tr('DOT graph (*.dot)'))
        if file_name is None or file_name == '':
            return

        handle = QFile(file_name)
        if not handle.open(QIODevice.WriteOnly | QIODevice.Text):
            return

        handle.write(self._current_dotcode)
        handle.close()

    def _save_svg(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self._widget, self.tr('Save as SVG'), 'rosgraph.svg',
            self.tr('Scalable Vector Graphic (*.svg)'))
        if file_name is None or file_name == '':
            return

        generator = QSvgGenerator()
        generator.setFileName(file_name)
        generator.setSize((self._scene.sceneRect().size() * 2.0).toSize())

        painter = QPainter(generator)
        painter.setRenderHint(QPainter.Antialiasing)
        self._scene.render(painter)
        painter.end()

    def _save_image(self):
        file_name, _ = QFileDialog.getSaveFileName(
            self._widget, self.tr('Save as image'), 'rosgraph.png',
            self.tr('Image (*.bmp *.jpg *.png *.tiff)'))
        if file_name is None or file_name == '':
            return

        img = QImage((self._scene.sceneRect().size() * 2.0).toSize(),
                     QImage.Format_ARGB32_Premultiplied)
        painter = QPainter(img)
        painter.setRenderHint(QPainter.Antialiasing)
        self._scene.render(painter)
        painter.end()
        img.save(file_name)
Esempio n. 11
0
class TestPulls(unittest.TestCase):
    def setUp(self):
        print(
            "\n********************************************************************"
        )
        print("* Pull Tests Setup")
        print(
            "********************************************************************"
        )
        rospy.init_node('test_pulls')
        self.graph = Graph()

    def test_pull_all(self):
        print(
            "\n********************************************************************"
        )
        print("* Pull All")
        print(
            "********************************************************************"
        )
        try:
            samples.pull_all()
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when advertising all connections.")
        pulled_interface = self._wait_for_pulled_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" %
                      self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(pulled_interface)))

        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/add_two_ints" and
                remote_rule.rule.node.split(',')[0] == "/add_two_ints_server"
                and remote_rule.rule.type == "service"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/chatter"
                and remote_rule.rule.node.split(',')[0] == "/talker"
                and remote_rule.rule.type == "publisher"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/chatter"
                and remote_rule.rule.node.split(',')[0] == "/listener"
                and remote_rule.rule.type == "subscriber"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/fibonacci/server"
                and remote_rule.rule.node.split(',')[0] == "/fibonacci_server"
                and remote_rule.rule.type == "action_server"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/fibonacci/client"
                and remote_rule.rule.node.split(',')[0] == "/fibonacci_client"
                and remote_rule.rule.type == "action_client"
            ]), 1)

        # Revert state
        try:
            samples.pull_all(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unadvertising all connections.")
        self._assert_cleared_pulled_interface()

    def test_pull_tutorials(self):
        print(
            "\n********************************************************************"
        )
        print("* Pull Tutorials")
        print(
            "********************************************************************"
        )
        try:
            samples.pull_tutorials()
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when advertising tutorial connections.")
        pulled_interface = self._wait_for_pulled_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" %
                      self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(pulled_interface)))

        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/add_two_ints" and
                remote_rule.rule.node.split(',')[0] == "/add_two_ints_server"
                and remote_rule.rule.type == "service"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/chatter"
                and remote_rule.rule.node.split(',')[0] == "/talker"
                and remote_rule.rule.type == "publisher"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/chatter"
                and remote_rule.rule.node.split(',')[0] == "/listener"
                and remote_rule.rule.type == "subscriber"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/fibonacci/server"
                and remote_rule.rule.node.split(',')[0] == "/fibonacci_server"
                and remote_rule.rule.type == "action_server"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/fibonacci/client"
                and remote_rule.rule.node.split(',')[0] == "/fibonacci_client"
                and remote_rule.rule.type == "action_client"
            ]), 1)

        try:
            samples.pull_tutorials(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unadvertising tutorial connections."
            )
        self._assert_cleared_pulled_interface()

    def test_pull_regex_tutorials(self):
        print(
            "\n********************************************************************"
        )
        print("* Pull Regex Tutorials")
        print(
            "********************************************************************"
        )
        try:
            samples.pull_tutorials(regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when advertising tutorial connections.")
        pulled_interface = self._wait_for_pulled_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" %
                      self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(pulled_interface)))

        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/add_two_ints" and
                remote_rule.rule.node.split(',')[0] == "/add_two_ints_server"
                and remote_rule.rule.type == "service"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/chatter"
                and remote_rule.rule.node.split(',')[0] == "/talker"
                and remote_rule.rule.type == "publisher"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/chatter"
                and remote_rule.rule.node.split(',')[0] == "/listener"
                and remote_rule.rule.type == "subscriber"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/fibonacci/server"
                and remote_rule.rule.node.split(',')[0] == "/fibonacci_server"
                and remote_rule.rule.type == "action_server"
            ]), 1)
        self.assertEquals(
            len([
                remote_rule for remote_rule in pulled_interface
                if remote_rule.rule.name == "/fibonacci/client"
                and remote_rule.rule.node.split(',')[0] == "/fibonacci_client"
                and remote_rule.rule.type == "action_client"
            ]), 1)

        try:
            samples.pull_tutorials(cancel=True, regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unadvertising tutorial connections."
            )
        self._assert_cleared_pulled_interface()

    def tearDown(self):
        pass

    ##########################################################################
    # Utility methods
    ##########################################################################

    def _wait_for_pulled_interface(self):
        pulled_interface = None
        while not pulled_interface:
            self.graph.update()
            pulled_interface = self.graph._local_gateway.pulled_connections
            rospy.sleep(1.0)
        return pulled_interface

    def _assert_cleared_pulled_interface(self):
        start_time = rospy.Time.now()
        while True:
            self.graph.update()
            pulled_interface = self.graph._local_gateway.pulled_connections
            if not pulled_interface:
                result = "cleared"
                break
            else:
                rospy.sleep(0.2)
            if rospy.Time.now() - start_time > rospy.Duration(2.0):
                result = "timed out waiting for pulled interface to clear"
                break
        self.assertEqual("cleared", result)
Esempio n. 12
0
 def setUp(self):
     self.graph = Graph()
Esempio n. 13
0
class TestFlips(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        # Note this should be called only once by process.
        # We only run one process here, for all 3 tests
        rospy.init_node('test_pullments')

    @classmethod
    def tearDownClass(cls):
        # shutting down process here
        pass

    def setUp(self):
        self.graph = Graph()

    def test_flip_all(self):
        print(console.bold + "\n********************************************************************" + console.reset)
        print(console.bold + "* Flip All" + console.reset)
        print(console.bold + "********************************************************************" + console.reset)
        try:
            samples.flip_all()
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when flipping all connections [%s]" % str(e))
        flipped_interface = self._wait_for_flipped_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" % self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(flipped_interface)))

        self.assertEquals(len([flip for flip in flipped_interface if flip.remote_rule.rule.name == "/add_two_ints" and flip.remote_rule.rule.node.split(',')[0] == "/add_two_ints_server" and flip.remote_rule.rule.type == "service"]), 1)
        self.assertEquals(len([flip for flip in flipped_interface if flip.remote_rule.rule.name == "/chatter" and flip.remote_rule.rule.node.split(',')[0] == "/talker" and flip.remote_rule.rule.type == "publisher"]), 1)
        self.assertEquals(len([flip for flip in flipped_interface if flip.remote_rule.rule.name == "/chatter" and flip.remote_rule.rule.node.split(',')[0] == "/listener" and flip.remote_rule.rule.type == "subscriber"]), 1)
        self.assertEquals(len([flip for flip in flipped_interface if flip.remote_rule.rule.name == "/fibonacci/server" and flip.remote_rule.rule.node.split(',')[0] == "/fibonacci_server" and flip.remote_rule.rule.type == "action_server"]), 1)
        self.assertEquals(len([flip for flip in flipped_interface if flip.remote_rule.rule.name == "/fibonacci/client" and flip.remote_rule.rule.node.split(',')[0] == "/fibonacci_client" and flip.remote_rule.rule.type == "action_client"]), 1)

        result = self._wait_for_accepted_flipped_interface()
        self.assertTrue(result)
        # Revert state
        try:
            samples.flip_all(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when unflipping all connections [%s]" % str(e))
        self._assert_cleared_flipped_interface()

    def test_flip_tutorials(self):
        print(console.bold + "\n********************************************************************" + console.reset)
        print(console.bold + "* Flip Tutorials" + console.reset)
        print(console.bold + "********************************************************************" + console.reset)
        try:
            samples.flip_tutorials()
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when flipping tutorial connections.")
        flipped_interface = self._wait_for_flipped_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" % self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(flipped_interface)))

        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/add_two_ints" and remote_rule.remote_rule.rule.node.split(',')[0] == "/add_two_ints_server" and remote_rule.remote_rule.rule.type == "service"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/chatter" and remote_rule.remote_rule.rule.node.split(',')[0] == "/talker" and remote_rule.remote_rule.rule.type == "publisher"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/chatter" and remote_rule.remote_rule.rule.node.split(',')[0] == "/listener" and remote_rule.remote_rule.rule.type == "subscriber"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/fibonacci/server" and remote_rule.remote_rule.rule.node.split(',')[0] == "/fibonacci_server" and remote_rule.remote_rule.rule.type == "action_server"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/fibonacci/client" and remote_rule.remote_rule.rule.node.split(',')[0] == "/fibonacci_client" and remote_rule.remote_rule.rule.type == "action_client"]), 1)

        result = self._wait_for_accepted_flipped_interface()
        self.assertTrue(result)
        try:
            samples.flip_tutorials(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when unflipping tutorial connections.")
        self._assert_cleared_flipped_interface()

    def test_flip_regex_tutorials(self):
        print(console.bold + "\n********************************************************************" + console.reset)
        print(console.bold + "* Flip Regex Tutorials" + console.reset)
        print(console.bold + "********************************************************************" + console.reset)
        try:
            samples.flip_tutorials(regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when flipping tutorial connections.")
        flipped_interface = self._wait_for_flipped_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" % self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(flipped_interface)))

        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/add_two_ints" and remote_rule.remote_rule.rule.node.split(',')[0] == "/add_two_ints_server" and remote_rule.remote_rule.rule.type == "service"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/chatter" and remote_rule.remote_rule.rule.node.split(',')[0] == "/talker" and remote_rule.remote_rule.rule.type == "publisher"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/chatter" and remote_rule.remote_rule.rule.node.split(',')[0] == "/listener" and remote_rule.remote_rule.rule.type == "subscriber"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/fibonacci/server" and remote_rule.remote_rule.rule.node.split(',')[0] == "/fibonacci_server" and remote_rule.remote_rule.rule.type == "action_server"]), 1)
        self.assertEquals(len([remote_rule for remote_rule in flipped_interface if remote_rule.remote_rule.rule.name == "/fibonacci/client" and remote_rule.remote_rule.rule.node.split(',')[0] == "/fibonacci_client" and remote_rule.remote_rule.rule.type == "action_client"]), 1)

        result = self._wait_for_accepted_flipped_interface()
        self.assertTrue(result)
        try:
            samples.flip_tutorials(cancel=True, regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when unflipping tutorial connections.")
        self._assert_cleared_flipped_interface()

    def tearDown(self):
        pass

    ##########################################################################
    # Utility methods
    ##########################################################################

    def _wait_for_accepted_flipped_interface(self):
        result = False
        start_time = rospy.Time.now()
        while not result and (rospy.Time.now() - start_time) < rospy.Duration(5.0):
            rospy.sleep(0.1)
            self.graph.update()
            accepted = True
            flipped_interface = self.graph._local_gateway.flipped_connections
            if not flipped_interface:
                continue
            for remote_rule in flipped_interface:
                result = True
                if remote_rule.status != 'accepted':
                    result = False
                    break
        return result

    def _wait_for_flipped_interface(self):
        flipped_interface = None
        while not flipped_interface:
            self.graph.update()
            flipped_interface = self.graph._local_gateway.flipped_connections
            rospy.sleep(0.2)
        return flipped_interface

    def _assert_cleared_flipped_interface(self):
        start_time = rospy.Time.now()
        while True:
            self.graph.update()
            flipped_interface = self.graph._local_gateway.flipped_connections
            if not flipped_interface:
                result = "cleared"
                break
            else:
                rospy.sleep(0.2)
            if rospy.Time.now() - start_time > rospy.Duration(2.0):
                result = "timed out waiting for flipped interface to clear"
                break
        self.assertEqual("cleared", result)
 def setUp(self):
     try:
         self.graph = Graph()
     except Exception as exc:
         self.fail()
class TestAdvertisements(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # Note this should be called only once by process.
        # We only run one process here, for all 3 tests
        rospy.init_node('test_advertisements')

    @classmethod
    def tearDownClass(cls):
        # shutting down process here
        pass

    def setUp(self):
        try:
            self.graph = Graph()
        except Exception as exc:
            self.fail()

    def test_advertise_all(self):
        rospy.loginfo(
            console.cyan +
            "********************************************************************"
            + console.reset)
        rospy.loginfo(console.cyan + "* Advertise All" + console.reset)
        rospy.loginfo(
            console.cyan +
            "********************************************************************"
            + console.reset)
        try:
            samples.advertise_all()
        except GatewaySampleRuntimeError as e:
            self.fail("Runtime error caught when advertising all connections.")
        time.sleep(2)
        public_interface = self._wait_for_public_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" %
                      self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(public_interface)))

        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/add_two_ints" and rule.node ==
                "/add_two_ints_server" and rule.type == "service"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface if rule.name == "/chatter"
                and rule.node == "/talker" and rule.type == "publisher"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface if rule.name == "/chatter"
                and rule.node == "/listener" and rule.type == "subscriber"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/fibonacci/server" and rule.node ==
                "/fibonacci_server" and rule.type == "action_server"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/fibonacci/client" and rule.node ==
                "/fibonacci_client" and rule.type == "action_client"
            ]), 1)

        # Revert state
        try:
            samples.advertise_all(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unadvertising all connections.")
        self._assert_cleared_public_interface()

    def test_advertise_tutorials(self):
        rospy.loginfo(
            console.cyan +
            "********************************************************************"
            + console.reset)
        rospy.loginfo(console.cyan + "* Advertise Tutorials" + console.reset)
        rospy.loginfo(
            console.cyan +
            "********************************************************************"
            + console.reset)
        try:
            samples.advertise_tutorials()
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when advertising tutorial connections.")
        time.sleep(2)
        public_interface = self._wait_for_public_interface()
        rospy.loginfo(console.cyan + "  - local gateway graph : \n%s" %
                      self.graph._local_gateway + console.reset)
        self.assertEquals("5", str(len(public_interface)))

        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/add_two_ints" and rule.node ==
                "/add_two_ints_server" and rule.type == "service"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface if rule.name == "/chatter"
                and rule.node == "/talker" and rule.type == "publisher"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface if rule.name == "/chatter"
                and rule.node == "/listener" and rule.type == "subscriber"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/fibonacci/server" and rule.node ==
                "/fibonacci_server" and rule.type == "action_server"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/fibonacci/client" and rule.node ==
                "/fibonacci_client" and rule.type == "action_client"
            ]), 1)

        try:
            samples.advertise_tutorials(cancel=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unadvertising tutorial connections."
            )
        self._assert_cleared_public_interface()

    def test_advertise_regex_tutorials(self):
        print(
            "\n********************************************************************"
        )
        print("* Advertise Regex Tutorials")
        print(
            "********************************************************************"
        )
        try:
            samples.advertise_tutorials(regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when advertising tutorial connections.")
        time.sleep(2)
        public_interface = self._wait_for_public_interface()
        print("%s" % self.graph._local_gateway)
        self.assertEquals("5", str(len(public_interface)))

        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/add_two_ints" and rule.node ==
                "/add_two_ints_server" and rule.type == "service"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface if rule.name == "/chatter"
                and rule.node == "/talker" and rule.type == "publisher"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface if rule.name == "/chatter"
                and rule.node == "/listener" and rule.type == "subscriber"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/fibonacci/server" and rule.node ==
                "/fibonacci_server" and rule.type == "action_server"
            ]), 1)
        self.assertEquals(
            len([
                rule for rule in public_interface
                if rule.name == "/fibonacci/client" and rule.node ==
                "/fibonacci_client" and rule.type == "action_client"
            ]), 1)

        try:
            samples.advertise_tutorials(cancel=True, regex_patterns=True)
        except GatewaySampleRuntimeError as e:
            self.fail(
                "Runtime error caught when unadvertising tutorial connections."
            )
        self._assert_cleared_public_interface()

    def tearDown(self):
        pass

    ##########################################################################
    # Utility methods
    ##########################################################################

    def _wait_for_public_interface(self):
        public_interface = None
        while not public_interface:
            self.graph.update()
            public_interface = self.graph._local_gateway.public_interface
            rospy.rostime.wallsleep(0.2)
        return public_interface

    def _assert_cleared_public_interface(self):
        start_time = rospy.Time.now()
        while True:
            self.graph.update()
            rospy.loginfo(console.cyan + "  - getting public interface" +
                          console.reset)
            public_interface = self.graph._local_gateway.public_interface
            rospy.loginfo(console.cyan + "  - public interface: \n" +
                          console.reset + "%s" % public_interface)
            if not public_interface:
                result = "cleared"
                break
            else:
                rospy.rostime.wallsleep(0.2)
            if rospy.Time.now() - start_time > rospy.Duration(10.0):
                result = "timed out waiting for public interface to clear"
                break
        self.assertEqual("cleared", result)