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 using canopen_chain_node::GetObject;
40 using namespace prbt_support;
41 using namespace testing;
42 
43 static const std::string GET_OBJECT_TOPIC_NAME{ "get_object" };
44 static const std::string JOINT_STATES_TOPIC_NAME{ "joint_states" };
45 static constexpr unsigned int JOINT_STATES_TOPIC_QUEUE_SIZE{ 1 };
46 
52 class SystemInfoTests : public testing::Test, public testing::AsyncTest
53 {
54 public:
55  void SetUp() override;
56  void TearDown() override;
57 
58  void publishJointState();
59 
60 protected:
61  MOCK_METHOD2(executeGetObject, bool(GetObject::Request&, GetObject::Response&));
62 
63  void advertiseGetObjectService();
64 
65 protected:
66  // Needed so that service callback are proecessed. Otherwise test in which
67  // service are calls will hang.
68  ros::AsyncSpinner spinner_{ 2 };
69 
70  const std::vector<std::string> joint_names_{ "joint1", "joint2" };
72  std::thread publisher_thread_;
73  std::atomic_bool terminate_{ false };
74 };
75 
77 {
78  ros::NodeHandle driver_nh{ "/prbt/driver/" };
79  get_obj_service_ = driver_nh.advertiseService(GET_OBJECT_TOPIC_NAME, &SystemInfoTests::executeGetObject, this);
80 }
81 
83 {
84  spinner_.start();
85 
86  // Set joint names on parameter server
87  ros::NodeHandle driver_nh{ "/prbt/driver/" };
88  for (unsigned int i = 0; i < joint_names_.size(); ++i)
89  {
90  driver_nh.setParam("nodes/" + joint_names_.at(i) + "/id", static_cast<int>(i));
91  }
92 
93  publisher_thread_ = std::thread(&SystemInfoTests::publishJointState, this);
94  advertiseGetObjectService();
95 }
96 
98 {
99  if (publisher_thread_.joinable())
100  {
101  terminate_ = true;
102  publisher_thread_.join();
103  }
104 }
105 
107 {
108  ros::NodeHandle global_nh{ "/" };
109  ros::Publisher joint_state_pub =
110  global_nh.advertise<sensor_msgs::JointState>(JOINT_STATES_TOPIC_NAME, JOINT_STATES_TOPIC_QUEUE_SIZE);
111 
112  while (!terminate_ && ros::ok())
113  {
114  joint_state_pub.publish(sensor_msgs::JointState());
115  ros::Duration(0.5).sleep();
116  }
117 }
118 
122 TEST_F(SystemInfoTests, TestExceptions)
123 {
124  const std::string exp_msg{ "Test-Msg" };
125  std::shared_ptr<SystemInfoException> ex{ new SystemInfoException(exp_msg) };
126  EXPECT_TRUE(std::string(ex->what()) == exp_msg);
127 }
128 
133 TEST_F(SystemInfoTests, testNodeNamesMissing)
134 {
135  ros::NodeHandle nh{ "~" };
136  nh.deleteParam("/prbt/driver/nodes");
137  EXPECT_THROW(SystemInfo{ nh }, SystemInfoException);
138 }
139 
144 TEST_F(SystemInfoTests, testCANUpAndRunning)
145 {
146  // Make sure that no JointStates are published
147  terminate_ = true;
148  publisher_thread_.join();
149 
150  // Variable stating if the constructor is finished or not.
151  std::atomic_bool ctor_called{ false };
152  // Start thread which allows us to asynchronously call the constructor
153  std::thread async_ctor_call_thread = std::thread([this, &ctor_called]() {
154  ros::NodeHandle nh{ "~" };
155  SystemInfo info(nh);
156  ctor_called = true;
157  this->triggerClearEvent("ctor_called");
158  });
159 
160  // Wait a while and then check if constructor is still waiting for the topic.
162  ASSERT_FALSE(ctor_called) << "Ctor already finished although \"/joint_states\" topic not published yet";
163 
164  // Activate publishing of "/joint_states"
165  terminate_ = false;
166  publisher_thread_ = std::thread(&SystemInfoTests::publishJointState, this);
167  pilz_utils::waitForMessage<sensor_msgs::JointState>("/joint_states");
168  // Wait till constructor is finished
169  BARRIER("ctor_called");
170 
171  if (async_ctor_call_thread.joinable())
172  {
173  async_ctor_call_thread.join();
174  }
175 }
176 
181 TEST_F(SystemInfoTests, testCANServiceUpAndRunning)
182 {
183  // Make sure that no ros_canopen service "get_object" is advertised.
184  get_obj_service_.shutdown();
185 
186  // Variable stating if the constructor is finished or not.
187  std::atomic_bool ctor_called{ false };
188  // Start thread which allows us to asynchronously call the constructor
189  std::thread async_ctor_call_thread = std::thread([this, &ctor_called]() {
190  ros::NodeHandle nh{ "~" };
191  SystemInfo info(nh);
192  ctor_called = true;
193  this->triggerClearEvent("ctor_called");
194  });
195 
196  // Wait a while and then check if constructor is still waiting for the topic.
198  ASSERT_FALSE(ctor_called) << "Ctor already finished although \"get_object\" service not advertised yet";
199 
200  advertiseGetObjectService();
201  pilz_utils::waitForService("/prbt/driver/get_object");
202  // Wait till constructor is finished
203  BARRIER("ctor_called");
204 
205  if (async_ctor_call_thread.joinable())
206  {
207  async_ctor_call_thread.join();
208  }
209 }
210 
215 TEST_F(SystemInfoTests, testServiceResponseFalse)
216 {
217  EXPECT_CALL(*this, executeGetObject(_, _))
218  .Times(1)
219  .WillRepeatedly(testing::Invoke([](GetObject::Request&, GetObject::Response& res) {
220  res.success = false;
221  return true;
222  }));
223 
224  ros::NodeHandle nh{ "~" };
225  SystemInfo info{ nh };
226  EXPECT_THROW(info.getFirmwareVersions(), SystemInfoException);
227 }
228 
232 TEST_F(SystemInfoTests, testServiceFail)
233 {
234  EXPECT_CALL(*this, executeGetObject(_, _))
235  .Times(1)
236  .WillRepeatedly(testing::Invoke([](GetObject::Request&, GetObject::Response&) { return false; }));
237 
238  ros::NodeHandle nh{ "~" };
239  SystemInfo info{ nh };
240  EXPECT_THROW(info.getFirmwareVersions(), SystemInfoException);
241 }
242 
247 TEST_F(SystemInfoTests, testGetFirmwareVersions)
248 {
249  ASSERT_EQ(2u, joint_names_.size()) << "Number of joints in test set-up have changed => Change expected version "
250  "container in test accordingly.";
251 
252  const FirmwareCont exp_versions{ { joint_names_.at(0), "100 Build:11158 Date:2018-06-07 16:49:55" },
253  { joint_names_.at(1), "101 Build:11158 Date:2018-06-07 16:49:55" } };
254 
255  EXPECT_CALL(*this, executeGetObject(_, _))
256  .Times(2)
257  .WillRepeatedly(testing::Invoke([exp_versions](GetObject::Request& req, GetObject::Response& res) {
258  res.value = exp_versions.at(req.node);
259  res.success = true;
260  return true;
261  }));
262 
263  // Check that returned versions from service are correct
264  ros::NodeHandle nh{ "~" };
265  SystemInfo info{ nh };
266  FirmwareCont actual_version_cont{ info.getFirmwareVersions() };
267  for (const auto& joint : joint_names_)
268  {
269  EXPECT_TRUE(actual_version_cont.find(joint) != actual_version_cont.cend()) << "No version for joint found";
270  EXPECT_EQ(exp_versions.at(joint), actual_version_cont.at(joint)) << "Expected and actual firmware version do not "
271  "match";
272  }
273 }
274 
279 TEST_F(SystemInfoTests, testGetFirmwareVersionsResizeTo40Chars)
280 {
281  ASSERT_EQ(2u, joint_names_.size()) << "Number of joints in test set-up have changed => Change expected version "
282  "container in test accordingly.";
283 
284  const FirmwareCont exp_versions{ { joint_names_.at(0), "100 Build:11158 Date:2018-06-07 16:49:55" },
285  { joint_names_.at(1), "101 Build:11158 Date:2018-06-07 16:49:55" } };
286 
287  EXPECT_CALL(*this, executeGetObject(_, _))
288  .Times(2)
289  .WillRepeatedly(testing::Invoke([exp_versions](GetObject::Request& req, GetObject::Response& res) {
290  res.value = exp_versions.at(req.node) + "AdditionalStuffWhichNeedsToBeRemoved";
291  res.success = true;
292  return true;
293  }));
294 
295  // Check that returned versions from service are correct
296  ros::NodeHandle nh{ "~" };
297  SystemInfo info{ nh };
298  FirmwareCont actual_version_cont{ info.getFirmwareVersions() };
299  for (const auto& joint : joint_names_)
300  {
301  EXPECT_TRUE(actual_version_cont.find(joint) != actual_version_cont.cend()) << "No version for joint found";
302  EXPECT_EQ(exp_versions.at(joint), actual_version_cont.at(joint)) << "Expected and actual firmware version do not "
303  "match";
304  }
305 }
306 
307 } // namespace system_info_tests
308 
309 int main(int argc, char* argv[])
310 {
311  ros::init(argc, argv, "system_info_test");
312  ros::NodeHandle nh;
313 
314  testing::InitGoogleTest(&argc, argv);
315  return RUN_ALL_TESTS();
316 }
static const std::string JOINT_STATES_TOPIC_NAME
std::map< std::string, std::string > FirmwareCont
Definition: system_info.h:33
Exception thrown by the SystemInfo class in case of an error.
int main(int argc, char *argv[])
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
static constexpr double DEFAULT_RETRY_TIMEOUT
#define EXPECT_EQ(a, b)
void publish(const boost::shared_ptr< M > &message) const
Collection of tests checking the functionality of the SystemInfo class.
FirmwareCont getFirmwareVersions()
Definition: system_info.cpp:74
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.
bool sleep() const
static const std::string GET_OBJECT_TOPIC_NAME
Provides easy access to system information which are of importance when analyzing bugs...
Definition: system_info.h:39
#define EXPECT_TRUE(args)


prbt_support
Author(s):
autogenerated on Mon Feb 28 2022 23:14:45