Skip to content

Commit

Permalink
Merge pull request #285 from k-okada/fix_rostwitter_instal
Browse files Browse the repository at this point in the history
add rostwitter.test
  • Loading branch information
k-okada committed Sep 20, 2021
2 parents 7fc1c0b + e4a2a5e commit ecc4be5
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 4 deletions.
1 change: 1 addition & 0 deletions .github/workflows/indigo.yml
Expand Up @@ -25,3 +25,4 @@ jobs:
# latest catkin_virtualenv with pip==21.0.1 is incompatible with python 2.x
# https://github.com/jsk-ros-pkg/jsk_3rdparty/pull/237
BEFORE_SCRIPT : "sudo pip install virtualenv==15.1.0"
USE_DEB : false
6 changes: 6 additions & 0 deletions .travis.rosinstall.indigo
@@ -0,0 +1,6 @@
# last kinetic release was 0.2.13,
# rostwitter requries sound_play >= 0.3.7 https://github.com/ros-drivers/audio_common/pull/149
- git:
local-name: audio_common/sound_play
uri: https://github.com/k-okada/audio_common
version: indigo_setup
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -19,7 +19,7 @@ env:
matrix:
- CHECK_PYTHON2_COMPILE=true
- CHECK_PYTHON3_COMPILE=true
- ROS_DISTRO=indigo USE_DEB=true
- ROS_DISTRO=indigo USE_DEB=false
- ROS_DISTRO=kinetic USE_DEB=true
- ROS_DISTRO=kinetic USE_DEB=true DOCKER_IMAGE=i386/ubuntu:16.04 ROSDEP_ADDITIONAL_OPTIONS="-n -q -r --ignore-src --skip-keys=python-google-cloud-texttospeech-pip --skip-keys=python-dialogflow-pip" # Skip installation of grpcio by pip because it causes error
- ROS_DISTRO=melodic USE_DEB=true
Expand Down
25 changes: 23 additions & 2 deletions rostwitter/CMakeLists.txt
Expand Up @@ -25,6 +25,27 @@ catkin_package(
CATKIN_DEPENDS message_runtime
)

install(PROGRAMS scripts/tweet.py
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# on noetic it needs catkin_install_python to support Python3
# but it does not work on indigo for some reason...
if($ENV{ROS_DISTRO} STREQUAL "indigo")
install(DIRECTORY scripts
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
USE_SOURCE_PERMISSIONS
)
else()
file(GLOB SCRIPT_PROGRAMS scripts/*.py)
catkin_install_python(
PROGRAMS ${SCRIPT_PROGRAMS}
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/scripts/
)
endif()

install(DIRECTORY test
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
USE_SOURCE_PERMISSIONS
)

if(CATKIN_ENABLE_TESTING)
find_package(rostest REQUIRED)
add_rostest(test/rostwitter.test)
endif()
3 changes: 3 additions & 0 deletions rostwitter/package.xml
Expand Up @@ -21,13 +21,16 @@
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend>
<exec_depend>sound_play</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-requests-oauthlib</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-requests-oauthlib</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-requests</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-requests</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 2">python-simplejson</exec_depend>
<exec_depend condition="$ROS_PYTHON_VERSION == 3">python3-simplejson</exec_depend>

<test_depend>rostest</test_depend>

<export>

</export>
Expand Down
6 changes: 5 additions & 1 deletion rostwitter/python/rostwitter/twitter.py
Expand Up @@ -3,7 +3,11 @@
import json as simplejson
import requests
from requests_oauthlib import OAuth1
from StringIO import StringIO
# https://stackoverflow.com/questions/11914472/stringio-in-python3
try:
from StringIO import StringIO ## for Python 2
except ImportError:
from io import StringIO ## for Python 3

import rospy

Expand Down
5 changes: 5 additions & 0 deletions rostwitter/test/dummy_account.yaml
@@ -0,0 +1,5 @@
CKEY: xxx
CSECRET: xxx
AKEY: xxx
ASECRET: xxx

19 changes: 19 additions & 0 deletions rostwitter/test/rostwitter.test
@@ -0,0 +1,19 @@
<launch>
<!-- tweet.py requires global account_info param -->
<param name="account_info" value="$(find rostwitter)/test/dummy_account.yaml" />
<node pkg="rostwitter" type="tweet.py" name="tweet" >
</node>
<!-- tweet_image_server.py requires private account_info param -->
<node pkg="rostwitter" type="tweet_image_server.py" name="tweet_image_server" >
<param name="account_info" value="$(find rostwitter)/test/dummy_account.yaml" />
</node>

<!-- copy subscribe test node until https://github.com/ros/ros_comm/pull/2184 merged -->
<test test-name="subscribetest_test" pkg="rostwitter" type="subscribetest" time-limit="20" retry="2">
<rosparam>
topics:
- name: /tweet
- name: /tweet_image_server/tweet/goal
</rosparam>
</test>
</launch>
148 changes: 148 additions & 0 deletions rostwitter/test/subscribetest
@@ -0,0 +1,148 @@
#!/usr/bin/env python
###############################################################################
# Software License Agreement (BSD License)
#
# Copyright (c) 2021, Kei Okada
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###############################################################################

"""
Integration test node that checks if the specified topics are subscribed.
below parameters must be set:
<test name="subscribetest"
test-name="subscribetest"
pkg="rostest" type="subscribetest">
<rosparam>
topics:
- name: a topic name
timeout: timeout for the topic
- name: another topic name
timeout: timeout for the topic
type: std_msgs/String
- name: another topic name
timeout: timeout for the topic
negative: true
</rosparam>
</test>
Author: Kei OKada <kei.okada@gmail.com>
"""

import sys
import time
import unittest

import rospy
import rosservice
import rosgraph

PKG = 'rostest'
NAME = 'subscribetest'


class SubscribeTest(unittest.TestCase):
def __init__(self, *args):
super(self.__class__, self).__init__(*args)
rospy.init_node(NAME)
# scrape rosparam
self.topics = {}
params = rospy.get_param('~topics', [])
for param in params:
if 'name' not in param:
self.fail("'name' field in rosparam is required but not specified.")
topic = {'timeout': 10, 'type': None, 'negative': False,}
topic.update(param)
self.topics[topic['name']] = topic
self.services = {}
# check if there is at least one topic
if not self.topics:
self.fail('No topic or service is specified in rosparam.')

def setUp(self):
# warn on /use_sim_time is true
use_sim_time = rospy.get_param('/use_sim_time', False)
self.t_start = time.time()
while not rospy.is_shutdown() and \
use_sim_time and (rospy.Time.now() == rospy.Time(0)):
rospy.logwarn_throttle(
1, '/use_sim_time is specified and rostime is 0, /clock is published?')
if time.time() - t_start > 10:
self.fail('Timed out (10s) of /clock publication.')
# must use time.sleep because /clock isn't yet published, so rospy.sleep hangs.
time.sleep(0.1)

def test_subscribe_topics(self):
"""Test topics are subscribed"""
def topic_type(t, topic_types):
matches = [t_type for t_name, t_type in topic_types if t_name == t]
if matches:
return matches[0]
return 'unknown type'

if self.topics:
t_start = self.t_start
t_name_set = set(self.topics.keys())
t_timeout_max = max(t['timeout'] for t in self.topics.values())
finished_topics = []
while not rospy.is_shutdown():
t_now = time.time()
t_elapsed = t_now - t_start
if not t_name_set:
break
if t_elapsed > t_timeout_max:
break
master = rosgraph.Master('/rostopic')
topic_types = master.getTopicTypes()

pubs, subs, servs = master.getSystemState()
for t_name, _ in subs:
t_type = topic_type(t_name, topic_types)
if t_name in t_name_set:
t_name_set.remove(t_name)
topic = self.topics[t_name]
assert t_elapsed < topic['timeout'], \
'Topic [%s] is subscribed before timeout [%s] secs' % (topic['name'], topic['timeout'])
assert not topic['negative'], \
'Topic [%s] is not subscribed' % (topic['name'])
if topic['type'] is not None:
assert t_type == topic['type'], \
'Topic type of [%s] is [%s]' % (topic['name'], topic['type'])
time.sleep(0.05)

for t_name in t_name_set:
topic = self.topics[t_name]
assert topic['negative'], \
'Topic [%s] is not subscribed' % (topic['name'])


if __name__ == '__main__':
import rostest
rostest.run(PKG, NAME, SubscribeTest, sys.argv)

0 comments on commit ecc4be5

Please sign in to comment.