diagnostic_updater_test.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2008, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Willow Garage nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 #include <gtest/gtest.h>
39 #ifndef _WIN32
40 #include <unistd.h>
41 #endif
42 
43 using namespace diagnostic_updater;
44 
45 class TestClass
46 {
47 public:
48  void unwrapped(diagnostic_msgs::DiagnosticStatus &s)
49  {
50  }
51 
53  {
54  }
55 };
56 
57 TEST(DiagnosticUpdater, testDiagnosticUpdater)
58 {
59  class classFunction : public DiagnosticTask
60  {
61  public:
62  classFunction() : DiagnosticTask("classFunction")
63  {}
64 
65  void run(DiagnosticStatusWrapper &s)
66  {
67  s.summary(0, "Test is running");
68  s.addf("Value", "%f", 5);
69  s.add("String", "Toto");
70  s.add("Floating", 5.55);
71  s.add("Integer", 5);
72  s.addf("Formatted %s %i", "Hello", 5);
73  s.add("Bool", true);
74  }
75  };
76 
77  TestClass c;
78  ros::NodeHandle nh;
79 
81 
82  updater.add("wrapped", &c, &TestClass::wrapped);
83 
84  classFunction cf;
85  updater.add(cf);
86 }
87 
88 TEST(DiagnosticUpdater, testDiagnosticStatusWrapperKeyValuePairs)
89 {
91 
92  const char *message = "dummy";
93  int level = 1;
94  stat.summary(level, message);
95  EXPECT_STREQ(message, stat.message.c_str()) << "DiagnosticStatusWrapper::summary failed to set message";
96  EXPECT_EQ(level, stat.level) << "DiagnosticStatusWrapper::summary failed to set level";
97 
98  stat.addf("toto", "%.1f", 5.0);
99  stat.add("baba", 5);
100  stat.addf("foo", "%05i", 27);
101 
102  stat.add("bool", true);
103  stat.add("bool2", false);
104 
105  EXPECT_STREQ("5.0", stat.values[0].value.c_str()) << "Bad value, adding a value with addf";
106  EXPECT_STREQ("5", stat.values[1].value.c_str()) << "Bad value, adding a string with add";
107  EXPECT_STREQ("00027", stat.values[2].value.c_str()) << "Bad value, adding a string with addf";
108  EXPECT_STREQ("toto", stat.values[0].key.c_str()) << "Bad label, adding a value with add";
109  EXPECT_STREQ("baba", stat.values[1].key.c_str()) << "Bad label, adding a string with add";
110  EXPECT_STREQ("foo", stat.values[2].key.c_str()) << "Bad label, adding a string with addf";
111 
112  EXPECT_STREQ("bool", stat.values[3].key.c_str()) << "Bad label, adding a true bool key with add";
113  EXPECT_STREQ("True", stat.values[3].value.c_str()) << "Bad label, adding a true bool with add";
114 
115  EXPECT_STREQ("bool2", stat.values[4].key.c_str()) << "Bad label, adding a false bool key with add";
116  EXPECT_STREQ("False", stat.values[4].value.c_str()) << "Bad label, adding a false bool with add";
117 }
118 
119 TEST(DiagnosticUpdater, testDiagnosticStatusWrapperMergeSummary)
120 {
122 
125  EXPECT_EQ(diagnostic_msgs::DiagnosticStatus::OK, stat.level) << "Bad level, merging levels (OK,OK)";
126  EXPECT_STREQ("Old", stat.message.c_str()) << "Bad summary, merging levels (OK,OK)";
127 
130  EXPECT_EQ(diagnostic_msgs::DiagnosticStatus::WARN, stat.level) << "Bad level, merging levels (OK,WARN)";
131  EXPECT_STREQ("New", stat.message.c_str()) << "Bad summary, merging levels (OK,WARN)";
132 
135  EXPECT_EQ(diagnostic_msgs::DiagnosticStatus::WARN, stat.level) << "Bad level, merging levels (WARN,WARN)";
136  EXPECT_STREQ("Old; New", stat.message.c_str()) << "Bad summary, merging levels (WARN,WARN)";
137 
140  EXPECT_EQ(diagnostic_msgs::DiagnosticStatus::ERROR, stat.level) << "Bad level, merging levels (WARN,ERROR)";
141  EXPECT_STREQ("Old; New", stat.message.c_str()) << "Bad summary, merging levels (WARN,ERROR)";
142 }
143 
144 TEST(DiagnosticUpdater, testFrequencyStatus)
145 {
146  double minFreq = 10;
147  double maxFreq = 20;
148 
149  ros::Time::init();
150  ros::Time time(0, 0);
151  ros::Time::setNow(time);
152 
153  FrequencyStatus fs(FrequencyStatusParam(&minFreq, &maxFreq, 0.5, 2));
154 
155  const int MS_TO_NS = 1000000;
156 
157  DiagnosticStatusWrapper stat[5];
158  fs.tick();
159  time += ros::Duration(0, 20 * MS_TO_NS); ros::Time::setNow(time);
160  fs.run(stat[0]); // Should be too fast, 20 ms for 1 tick, lower limit should be 33ms.
161  time += ros::Duration(0, 50 * MS_TO_NS); ros::Time::setNow(time);
162  fs.tick();
163  fs.run(stat[1]); // Should be good, 70 ms for 2 ticks, lower limit should be 66 ms.
164  time += ros::Duration(0, 300 * MS_TO_NS); ros::Time::setNow(time);
165  fs.tick();
166  fs.run(stat[2]); // Should be good, 350 ms for 2 ticks, upper limit should be 400 ms.
167  time += ros::Duration(0, 150 * MS_TO_NS); ros::Time::setNow(time);
168  fs.tick();
169  fs.run(stat[3]); // Should be too slow, 450 ms for 2 ticks, upper limit should be 400 ms.
170  fs.clear();
171  fs.run(stat[4]); // Should be good, just cleared it.
172 
173  using diagnostic_msgs::DiagnosticStatus;
174 
175  EXPECT_EQ(DiagnosticStatus::WARN, stat[0].level) << "max frequency exceeded but not reported";
176  EXPECT_EQ(DiagnosticStatus::OK, stat[1].level) << "within max frequency but reported error";
177  EXPECT_EQ(DiagnosticStatus::OK, stat[2].level) << "within min frequency but reported error";
178  EXPECT_EQ(DiagnosticStatus::WARN, stat[3].level) << "min frequency exceeded but not reported";
179  EXPECT_EQ(DiagnosticStatus::ERROR, stat[4].level) << "freshly cleared should fail";
180  EXPECT_STREQ("", stat[0].name.c_str()) << "Name should not be set by FrequencyStatus";
181  EXPECT_STREQ("Frequency Status", fs.getName().c_str()) << "Name should be \"Frequency Status\"";
182 }
183 
184 TEST(DiagnosticUpdater, testSlowFrequencyStatus)
185 {
186  // We have a slow topic (~0.5 Hz) and call the run() method once a second. This ensures that if the window size
187  // is large enough (longer than 1/min_frequency * duration_between_run_calls), the diagnostics correctly reports
188  // the frequency status even in time windows where no ticks happened.
189 
190  double minFreq = 0.25;
191  double maxFreq = 0.75;
192 
193  ros::Time::init();
194  ros::Time time(0, 0);
195  ros::Time::setNow(time);
196 
197  FrequencyStatus fs(FrequencyStatusParam(&minFreq, &maxFreq, 0.0, 5));
198 
199  DiagnosticStatusWrapper stat[8];
200  fs.tick();
201  time += ros::Duration(1, 0); ros::Time::setNow(time);
202  fs.run(stat[0]); // too high, 1 event in 1 sec window
203  time += ros::Duration(1, 0); ros::Time::setNow(time);
204  fs.run(stat[1]); // ok, 1 event in 2 sec window
205  fs.tick();
206  time += ros::Duration(1, 0); ros::Time::setNow(time);
207  fs.run(stat[2]); // ok, 2 events in 3 sec window
208  time += ros::Duration(1, 0); ros::Time::setNow(time);
209  fs.run(stat[3]); // ok, 2 events in 4 sec window
210  time += ros::Duration(1, 0); ros::Time::setNow(time);
211  fs.run(stat[4]); // ok, 2 events in 5 sec window
212  time += ros::Duration(1, 0); ros::Time::setNow(time);
213  fs.run(stat[5]); // too low, 1 event in 5 sec window (first tick went out of window)
214  time += ros::Duration(1, 0); ros::Time::setNow(time);
215  fs.run(stat[6]); // too low, 1 event in 5 sec window (first tick went out of window)
216  time += ros::Duration(1, 0); ros::Time::setNow(time);
217  fs.run(stat[7]); // no events (second tick went out of window)
218  time += ros::Duration(1, 0); ros::Time::setNow(time);
219 
220  using diagnostic_msgs::DiagnosticStatus;
221 
222  EXPECT_EQ(DiagnosticStatus::WARN, stat[0].level) << "max frequency exceeded but not reported";
223  EXPECT_EQ(DiagnosticStatus::OK, stat[1].level) << "within frequency limits but reported error";
224  EXPECT_EQ(DiagnosticStatus::OK, stat[2].level) << "within frequency limits but reported error";
225  EXPECT_EQ(DiagnosticStatus::OK, stat[3].level) << "within frequency limits but reported error";
226  EXPECT_EQ(DiagnosticStatus::OK, stat[4].level) << "within frequency limits but reported error";
227  EXPECT_EQ(DiagnosticStatus::WARN, stat[5].level) << "min frequency exceeded but not reported";
228  EXPECT_EQ(DiagnosticStatus::WARN, stat[6].level) << "min frequency exceeded but not reported";
229  EXPECT_EQ(DiagnosticStatus::ERROR, stat[7].level) << "no events should fail";
230 }
231 
232 TEST(DiagnosticUpdater, testTimeStampStatus)
233 {
234  ros::Time::init();
235  ros::Time time(1, 0);
236  ros::Time::setNow(time);
237 
239 
240  DiagnosticStatusWrapper stat[5];
241  ts.run(stat[0]);
242  ts.tick(time.toSec() + 2);
243  ts.run(stat[1]);
244  ts.tick(time);
245  ts.run(stat[2]);
246  ts.tick(time.toSec() - 4);
247  ts.run(stat[3]);
248  ts.tick(time.toSec() - 6);
249  ts.run(stat[4]);
250 
251  using diagnostic_msgs::DiagnosticStatus;
252 
253  EXPECT_EQ(DiagnosticStatus::WARN, stat[0].level) << "no data should return a warning";
254  EXPECT_EQ(DiagnosticStatus::ERROR, stat[1].level) << "too far future not reported";
255  EXPECT_EQ(DiagnosticStatus::OK, stat[2].level) << "now not accepted";
256  EXPECT_EQ(DiagnosticStatus::OK, stat[3].level) << "4 seconds ago not accepted";
257  EXPECT_EQ(DiagnosticStatus::ERROR, stat[4].level) << "too far past not reported";
258  EXPECT_STREQ("", stat[0].name.c_str()) << "Name should not be set by TimeStapmStatus";
259  EXPECT_STREQ("Timestamp Status", ts.getName().c_str()) << "Name should be \"Timestamp Status\"";
260 }
261 
262 TEST(DiagnosticUpdater, testSlowTimeStampStatus)
263 {
264  // We have a slow topic (< 1 Hz) and call the run() method once a second. If we set the no_data_is_problem parameter
265  // to false, updates without data should not generate a warning but should be treated as ok.
266 
267  ros::Time::init();
268  ros::Time time(1, 0);
269  ros::Time::setNow(time);
270 
272 
273  DiagnosticStatusWrapper stat[11];
274  ts.run(stat[0]); // no events
275  ts.tick(time.toSec() + 2);
276  ts.run(stat[1]);
277  ts.run(stat[2]);
278  ts.tick(time.toSec() - 4);
279  ts.run(stat[3]);
280  ts.run(stat[4]);
281  ts.run(stat[5]);
282  ts.run(stat[6]);
283  ts.tick(time.toSec() - 6);
284  ts.run(stat[7]);
285  ts.run(stat[8]);
286  ts.run(stat[9]);
287  ts.run(stat[10]);
288 
289  using diagnostic_msgs::DiagnosticStatus;
290 
291  EXPECT_EQ(DiagnosticStatus::OK, stat[0].level) << "no data should be ok";
292  EXPECT_EQ(DiagnosticStatus::ERROR, stat[1].level) << "too far future not reported";
293  EXPECT_EQ(DiagnosticStatus::OK, stat[2].level) << "no data should be ok";
294  EXPECT_EQ(DiagnosticStatus::OK, stat[3].level) << "4 seconds ago not accepted";
295  EXPECT_EQ(DiagnosticStatus::OK, stat[4].level) << "no data should be ok";
296  EXPECT_EQ(DiagnosticStatus::OK, stat[5].level) << "no data should be ok";
297  EXPECT_EQ(DiagnosticStatus::OK, stat[6].level) << "no data should be ok";
298  EXPECT_EQ(DiagnosticStatus::ERROR, stat[7].level) << "too far past not reported";
299  EXPECT_EQ(DiagnosticStatus::OK, stat[8].level) << "no data should be ok";
300  EXPECT_EQ(DiagnosticStatus::OK, stat[9].level) << "no data should be ok";
301  EXPECT_EQ(DiagnosticStatus::OK, stat[10].level) << "no data should be ok";
302 }
303 
304 int main(int argc, char **argv){
305  ros::init(argc, argv, "test_node");
306  testing::InitGoogleTest(&argc, argv);
307  return RUN_ALL_TESTS();
308 }
static TimeStampStatusParam DefaultTimeStampStatusParam
Default TimeStampStatusParam. This is like calling the constructor with no arguments.
void unwrapped(diagnostic_msgs::DiagnosticStatus &s)
virtual void run(diagnostic_updater::DiagnosticStatusWrapper &stat)
Fills out this Task&#39;s DiagnosticStatusWrapper.
void summary(unsigned char lvl, const std::string s)
Fills out the level and message fields of the DiagnosticStatus.
A structure that holds the constructor parameters for the FrequencyStatus class.
XmlRpcServer s
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void add(const std::string &name, TaskFunction f)
Add a DiagnosticTask embodied by a name and function to the DiagnosticTaskVector. ...
Author: Blaise Gassend.
int main(int argc, char **argv)
A structure that holds the constructor parameters for the TimeStampStatus class.
virtual void run(diagnostic_updater::DiagnosticStatusWrapper &stat)
Fills out this Task&#39;s DiagnosticStatusWrapper.
static void setNow(const Time &new_now)
void addf(const std::string &key, const char *format,...)
Add a key-value pair using a format string.
Manages a list of diagnostic tasks, and calls them in a rate-limited manner.
A diagnostic task that monitors the frequency of an event.
void wrapped(DiagnosticStatusWrapper &s)
void tick()
Signals that an event has occurred.
static void init()
Diagnostic task to monitor the interval between events.
void clear()
Resets the statistics.
void mergeSummary(unsigned char lvl, const std::string s)
Merges a level and message with the existing ones.
const std::string & getName()
Returns the name of the DiagnosticTask.
TEST(DiagnosticUpdater, testDiagnosticUpdater)
DiagnosticTask is an abstract base class for collecting diagnostic data.
void add(const std::string &key, const T &val)
Add a key-value pair.
void tick(double stamp)
Signals an event. Timestamp stored as a double.
Wrapper for the diagnostic_msgs::DiagnosticStatus message that makes it easier to update...


diagnostic_updater
Author(s): Kevin Watts, Brice Rebsamen , Jeremy Leibs, Blaise Gassend
autogenerated on Mon Feb 28 2022 22:18:16