unittest_system_info.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Pilz GmbH & Co. KG
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13 
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <string>
19 #include <vector>
20 #include <thread>
21 #include <atomic>
22 #include <memory>
23 
24 #include <gtest/gtest.h>
25 #include <gmock/gmock.h>
26 
27 #include <ros/ros.h>
28 #include <canopen_chain_node/GetObject.h>
29 #include <sensor_msgs/JointState.h>
30 
33 #include <pilz_testutils/async_test.h>
36 
38 {
39 
40 using canopen_chain_node::GetObject;
41 using namespace prbt_hardware_support;
42 using namespace testing;
43 
44 static const std::string GET_OBJECT_TOPIC_NAME{"get_object"};
45 static const std::string JOINT_STATES_TOPIC_NAME{"joint_states"};
46 static constexpr unsigned int JOINT_STATES_TOPIC_QUEUE_SIZE{1};
47 
53 class SystemInfoTests : public testing::Test, public testing::AsyncTest
54 {
55 public:
56  virtual void SetUp() override;
57  virtual void TearDown() override;
58 
59  void publishJointState();
60 
61 protected:
62  MOCK_METHOD2(executeGetObject, bool(GetObject::Request&, GetObject::Response&));
63 
64  void advertiseGetObjectService();
65 
66 protected:
67  // Needed so that service callback are proecessed. Otherwise test in which
68  // service are calls will hang.
69  ros::AsyncSpinner spinner_ {2};
70 
71  const std::vector<std::string> joint_names_ {"joint1", "joint2"};
73  std::thread publisher_thread_;
74  std::atomic_bool terminate_ {false};
75 
76 };
77 
79 {
80  ros::NodeHandle driver_nh {"/prbt/driver/"};
81  get_obj_service_ = driver_nh.advertiseService(GET_OBJECT_TOPIC_NAME,
82  &SystemInfoTests::executeGetObject,
83  this);
84 }
85 
87 {
88  spinner_.start();
89 
90  // Set joint names on parameter server
91  ros::NodeHandle driver_nh {"/prbt/driver/"};
92  for(unsigned int i = 0; i < joint_names_.size(); ++i)
93  {
94  driver_nh.setParam("nodes/" + joint_names_.at(i) + "/id", static_cast<int>(i));
95  }
96 
97  publisher_thread_ = std::thread(&SystemInfoTests::publishJointState, this);
98  advertiseGetObjectService();
99 }
100 
102 {
103  if (publisher_thread_.joinable())
104  {
105  terminate_ = true;
106  publisher_thread_.join();
107  }
108 }
109 
111 {
112  ros::NodeHandle global_nh {"/"};
113  ros::Publisher joint_state_pub = global_nh.advertise<sensor_msgs::JointState>(
116 
117  while(!terminate_ && ros::ok())
118  {
119  joint_state_pub.publish(sensor_msgs::JointState());
120  ros::Duration(0.5).sleep();
121  }
122 }
123 
127 TEST_F(SystemInfoTests, TestExceptions)
128 {
129  const std::string exp_msg {"Test-Msg"};
130  std::shared_ptr<SystemInfoException> ex {new SystemInfoException(exp_msg)};
131  EXPECT_TRUE(std::string(ex->what()) == exp_msg);
132 }
133 
138 TEST_F(SystemInfoTests, testNodeNamesMissing)
139 {
140  ros::NodeHandle nh{"~"};
141  nh.deleteParam("/prbt/driver/nodes");
142  EXPECT_THROW(SystemInfo{nh}, SystemInfoException);
143 }
144 
149 TEST_F(SystemInfoTests, testCANUpAndRunning)
150 {
151  // Make sure that no JointStates are published
152  terminate_ = true;
153  publisher_thread_.join();
154 
155  // Variable stating if the constructor is finished or not.
156  std::atomic_bool ctor_called {false};
157  // Start thread which allows us to asynchronously call the constructor
158  std::thread async_ctor_call_thread = std::thread([this, &ctor_called] () {
159  ros::NodeHandle nh{"~"};
160  SystemInfo info(nh);
161  ctor_called = true;
162  this->triggerClearEvent("ctor_called");
163  });
164 
165  // Wait a while and then check if constructor is still waiting for the topic.
167  ASSERT_FALSE(ctor_called) << "Ctor already finished although \"/joint_states\" topic not published yet";
168 
169  // Activate publishing of "/joint_states"
170  terminate_ = false;
171  publisher_thread_ = std::thread(&SystemInfoTests::publishJointState, this);
172  pilz_utils::waitForMessage<sensor_msgs::JointState>("/joint_states");
173  // Wait till constructor is finished
174  BARRIER("ctor_called");
175 
176  if (async_ctor_call_thread.joinable())
177  {
178  async_ctor_call_thread.join();
179  }
180 }
181 
186 TEST_F(SystemInfoTests, testCANServiceUpAndRunning)
187 {
188  // Make sure that no ros_canopen service "get_object" is advertised.
189  get_obj_service_.shutdown();
190 
191  // Variable stating if the constructor is finished or not.
192  std::atomic_bool ctor_called {false};
193  // Start thread which allows us to asynchronously call the constructor
194  std::thread async_ctor_call_thread = std::thread([this, &ctor_called] () {
195  ros::NodeHandle nh{"~"};
196  SystemInfo info(nh);
197  ctor_called = true;
198  this->triggerClearEvent("ctor_called");
199  });
200 
201  // Wait a while and then check if constructor is still waiting for the topic.
203  ASSERT_FALSE(ctor_called) << "Ctor already finished although \"get_object\" service not advertised yet";
204 
205  advertiseGetObjectService();
206  pilz_utils::waitForService("/prbt/driver/get_object");
207  // Wait till constructor is finished
208  BARRIER("ctor_called");
209 
210  if (async_ctor_call_thread.joinable())
211  {
212  async_ctor_call_thread.join();
213  }
214 }
215 
220 TEST_F(SystemInfoTests, testServiceResponseFalse)
221 {
222  EXPECT_CALL(*this, executeGetObject(_,_))
223  .Times(1)
224  .WillRepeatedly(testing::Invoke(
225  [](GetObject::Request&, GetObject::Response& res){
226  res.success = false;
227  return true;
228  }
229  ));
230 
231  ros::NodeHandle nh{"~"};
232  SystemInfo info {nh};
233  EXPECT_THROW(info.getFirmwareVersions(), SystemInfoException);
234 }
235 
239 TEST_F(SystemInfoTests, testServiceFail)
240 {
241  EXPECT_CALL(*this, executeGetObject(_,_))
242  .Times(1)
243  .WillRepeatedly(testing::Invoke(
244  [](GetObject::Request&, GetObject::Response&){
245  return false;
246  }
247  ));
248 
249  ros::NodeHandle nh{"~"};
250  SystemInfo info {nh};
251  EXPECT_THROW(info.getFirmwareVersions(), SystemInfoException);
252 }
253 
258 TEST_F(SystemInfoTests, testGetFirmwareVersions)
259 {
260  ASSERT_EQ(2u, joint_names_.size()) << "Number of joints in test set-up have changed => Change expected version container in test accordingly.";
261 
262  const FirmwareCont exp_versions { {joint_names_.at(0), "100 Build:11158 Date:2018-06-07 16:49:55"},
263  {joint_names_.at(1), "101 Build:11158 Date:2018-06-07 16:49:55"}};
264 
265  EXPECT_CALL(*this, executeGetObject(_,_))
266  .Times(2)
267  .WillRepeatedly(testing::Invoke(
268  [exp_versions](GetObject::Request& req, GetObject::Response& res){
269  res.value = exp_versions.at(req.node);
270  res.success = true;
271  return true;
272  }
273  ));
274 
275  // Check that returned versions from service are correct
276  ros::NodeHandle nh{"~"};
277  SystemInfo info {nh};
278  FirmwareCont actual_version_cont {info.getFirmwareVersions()};
279  for(const auto& joint : joint_names_)
280  {
281  EXPECT_TRUE(actual_version_cont.find(joint) != actual_version_cont.cend()) << "No version for joint found";
282  EXPECT_EQ(exp_versions.at(joint), actual_version_cont.at(joint)) << "Expected and actual firmware version do not match";
283  }
284 }
285 
290 TEST_F(SystemInfoTests, testGetFirmwareVersionsResizeTo40Chars)
291 {
292  ASSERT_EQ(2u, joint_names_.size()) << "Number of joints in test set-up have changed => Change expected version container in test accordingly.";
293 
294  const FirmwareCont exp_versions { {joint_names_.at(0), "100 Build:11158 Date:2018-06-07 16:49:55"},
295  {joint_names_.at(1), "101 Build:11158 Date:2018-06-07 16:49:55"}};
296 
297  EXPECT_CALL(*this, executeGetObject(_,_))
298  .Times(2)
299  .WillRepeatedly(testing::Invoke(
300  [exp_versions](GetObject::Request& req, GetObject::Response& res){
301  res.value = exp_versions.at(req.node) + "AdditionalStuffWhichNeedsToBeRemoved";
302  res.success = true;
303  return true;
304  }
305  ));
306 
307  // Check that returned versions from service are correct
308  ros::NodeHandle nh{"~"};
309  SystemInfo info {nh};
310  FirmwareCont actual_version_cont {info.getFirmwareVersions()};
311  for(const auto& joint : joint_names_)
312  {
313  EXPECT_TRUE(actual_version_cont.find(joint) != actual_version_cont.cend()) << "No version for joint found";
314  EXPECT_EQ(exp_versions.at(joint), actual_version_cont.at(joint)) << "Expected and actual firmware version do not match";
315  }
316 }
317 
318 
319 } // namespace system_info_tests
320 
321 
322 int main(int argc, char *argv[])
323 {
324  ros::init(argc, argv, "system_info_test");
325  ros::NodeHandle nh;
326 
327  testing::InitGoogleTest(&argc, argv);
328  return RUN_ALL_TESTS();
329 }
static const std::string JOINT_STATES_TOPIC_NAME
void publish(const boost::shared_ptr< M > &message) const
int main(int argc, char *argv[])
bool sleep() const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
static constexpr unsigned int JOINT_STATES_TOPIC_QUEUE_SIZE
Provides easy access to system information which are of importance when analyzing bugs...
Definition: system_info.h:40
static constexpr double DEFAULT_RETRY_TIMEOUT
Collection of tests checking the functionality of the SystemInfo class.
static void waitForService(const std::string service_name, const double retry_timeout=DEFAULT_RETRY_TIMEOUT, const double msg_output_period=DEFAULT_MSG_OUTPUT_PERIOD)
ROSCPP_DECL bool ok()
TEST_F(SystemInfoTests, TestExceptions)
Tests that exception stores and returns correct error message.
Exception thrown by the SystemInfo class in case of an error.
static const std::string GET_OBJECT_TOPIC_NAME
std::map< std::string, std::string > FirmwareCont
Definition: system_info.h:34


prbt_hardware_support
Author(s):
autogenerated on Tue Feb 2 2021 03:50:17