async_test.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 Pilz GmbH & Co. KG
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ASYNC_TEST_H
18 #define ASYNC_TEST_H
19 
20 #include <algorithm>
21 #include <chrono>
22 #include <condition_variable>
23 #include <mutex>
24 #include <string>
25 
26 #include <gmock/gmock.h>
27 
28 #include <ros/ros.h>
29 
30 namespace testing
31 {
75 class AsyncTest
76 {
77 public:
86  void triggerClearEvent(const std::string& event);
87 
97  bool barricade(const std::string& clear_event, const int timeout_ms = -1);
98 
108  bool barricade(std::initializer_list<std::string> clear_events, const int timeout_ms = -1);
109 
110 protected:
111  std::mutex m_;
112  std::condition_variable cv_;
113  std::set<std::string> clear_events_{};
114  std::set<std::string> waitlist_{};
115 };
116 
117 // for better readability in tests
118 #define BARRIER(...) EXPECT_TRUE(barricade(__VA_ARGS__))
119 #define BARRIER_FATAL(...) ASSERT_TRUE(barricade(__VA_ARGS__))
120 
121 #define ACTION_OPEN_BARRIER(str) \
122  ::testing::InvokeWithoutArgs([this](void) { \
123  this->triggerClearEvent(str); \
124  return true; \
125  })
126 #define ACTION_OPEN_BARRIER_VOID(str) ::testing::InvokeWithoutArgs([this](void) { this->triggerClearEvent(str); })
127 
128 inline void AsyncTest::triggerClearEvent(const std::string& event)
129 {
130  std::lock_guard<std::mutex> lk(m_);
131 
132  if (clear_events_.empty())
133  {
134  ROS_DEBUG_NAMED("Test", "Clearing Barricade[%s]", event.c_str());
135  waitlist_.insert(event);
136  }
137  else if (clear_events_.erase(event) < 1)
138  {
139  ROS_WARN_STREAM("Triggered event " << event << " despite not waiting for it.");
140  }
141  cv_.notify_one();
142 }
143 
144 inline bool AsyncTest::barricade(const std::string& clear_event, const int timeout_ms)
145 {
146  return barricade({ clear_event }, timeout_ms);
147 }
148 
149 inline bool AsyncTest::barricade(std::initializer_list<std::string> clear_events, const int timeout_ms)
150 {
151  std::unique_lock<std::mutex> lk(m_);
152 
153  std::stringstream events_stringstream;
154  for (const auto& event : clear_events)
155  {
156  events_stringstream << event << ", ";
157  }
158  ROS_DEBUG_NAMED("Test", "Adding Barricade[%s]", events_stringstream.str().c_str());
159 
160  std::copy_if(clear_events.begin(),
161  clear_events.end(),
162  std::inserter(clear_events_, clear_events_.end()),
163  [this](std::string event) { return this->waitlist_.count(event) == 0; });
164  waitlist_.clear();
165 
166  auto end_time_point = std::chrono::system_clock::now() + std::chrono::milliseconds(timeout_ms);
167 
168  while (!clear_events_.empty())
169  {
170  if (timeout_ms < 0)
171  {
172  cv_.wait(lk);
173  }
174  else
175  {
176  std::cv_status status = cv_.wait_for(lk, end_time_point - std::chrono::system_clock::now());
177  if (status == std::cv_status::timeout)
178  {
179  return clear_events_.empty();
180  }
181  }
182  }
183  return true;
184 }
185 
186 } // namespace testing
187 
188 #endif // ASYNC_TEST_H
bool barricade(const std::string &clear_event, const int timeout_ms=-1)
Will block until the event given by clear_event is triggered or a timeout is reached. Unblocks immediately, if the event was on the waitlist.
Definition: async_test.h:144
std::condition_variable cv_
Definition: async_test.h:112
#define ROS_DEBUG_NAMED(name,...)
std::set< std::string > clear_events_
Definition: async_test.h:113
#define ROS_WARN_STREAM(args)
void triggerClearEvent(const std::string &event)
Triggeres a clear event. If a call to barricade is currently pending it will unblock as soon as all c...
Definition: async_test.h:128
Test class that allows the handling of asynchronous test objects.
Definition: async_test.h:75
std::set< std::string > waitlist_
Definition: async_test.h:114


pilz_testutils
Author(s):
autogenerated on Mon Feb 28 2022 23:13:41