Merge "Fix flaky recurrent timer test." into main

This commit is contained in:
Treehugger Robot 2023-07-07 20:32:25 +00:00 committed by Gerrit Code Review
commit d0cb2e73b2

View file

@ -18,6 +18,7 @@
#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
#include <condition_variable>
#include <chrono>
#include <memory>
@ -28,6 +29,8 @@ namespace hardware {
namespace automotive {
namespace vehicle {
using ::android::base::ScopedLockAssertion;
class RecurrentTimerTest : public testing::Test {
public:
std::shared_ptr<RecurrentTimer::Callback> getCallback(size_t token) {
@ -35,6 +38,15 @@ class RecurrentTimerTest : public testing::Test {
std::scoped_lock<std::mutex> lockGuard(mLock);
mCallbacks.push_back(token);
mCond.notify_all();
});
}
bool waitForCalledCallbacks(size_t count, size_t timeoutInMs) {
std::unique_lock<std::mutex> uniqueLock(mLock);
return mCond.wait_for(uniqueLock, std::chrono::milliseconds(timeoutInMs), [this, count] {
ScopedLockAssertion lockAssertion(mLock);
return mCallbacks.size() >= count;
});
}
@ -54,6 +66,7 @@ class RecurrentTimerTest : public testing::Test {
}
private:
std::condition_variable mCond;
std::mutex mLock;
std::vector<size_t> mCallbacks GUARDED_BY(mLock);
};
@ -66,12 +79,11 @@ TEST_F(RecurrentTimerTest, testRegisterCallback) {
auto action = getCallback(0);
timer.registerTimerCallback(interval, action);
std::this_thread::sleep_for(std::chrono::seconds(1));
// Should only takes 1s, use 5s as timeout to be safe.
ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
<< "Not enough callbacks called before timeout";
timer.unregisterTimerCallback(action);
// Theoretically trigger 10 times, but check for at least 9 times to be stable.
ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
}
TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
@ -92,10 +104,11 @@ TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
timer.registerTimerCallback(interval, action);
std::this_thread::sleep_for(std::chrono::seconds(1));
// Should only takes 1s, use 5s as timeout to be safe.
ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
<< "Not enough callbacks called before timeout";
// Theoretically trigger 10 times, but check for at least 9 times to be stable.
ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
timer.unregisterTimerCallback(action);
}
TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
@ -114,7 +127,9 @@ TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
ASSERT_TRUE(getCalledCallbacks().empty());
// Should be 0, but in rare cases there might be 1 events in the queue while the timer is
// being destroyed.
ASSERT_LE(getCalledCallbacks().size(), 1u);
}
TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
@ -132,7 +147,11 @@ TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
auto action3 = getCallback(3);
timer.registerTimerCallback(interval3, action3);
std::this_thread::sleep_for(std::chrono::seconds(1));
// In 1s, we should generate 10 + 20 + 33 = 63 events.
// Here we are waiting for more events to make sure we receive enough events for each actions.
// Use 5s as timeout to be safe.
ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 70u, /* timeoutInMs= */ 5000))
<< "Not enough callbacks called before timeout";
timer.unregisterTimerCallback(action1);
timer.unregisterTimerCallback(action2);
@ -152,20 +171,18 @@ TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
action3Count++;
}
}
// Theoretically trigger 10 times, but check for at least 9 times to be stable.
ASSERT_GE(action1Count, static_cast<size_t>(9));
// Theoretically trigger 20 times, but check for at least 15 times to be stable.
ASSERT_GE(action2Count, static_cast<size_t>(15));
// Theoretically trigger 33 times, but check for at least 25 times to be stable.
ASSERT_GE(action3Count, static_cast<size_t>(25));
ASSERT_GE(action1Count, static_cast<size_t>(10));
ASSERT_GE(action2Count, static_cast<size_t>(20));
ASSERT_GE(action3Count, static_cast<size_t>(33));
}
TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
RecurrentTimer timer;
// 0.02s
int64_t interval1 = 20000000;
// 0.01s
int64_t interval2 = 10000000;
// 0.2s
int64_t interval1 = 200'000'000;
// 0.1s
int64_t interval2 = 100'000'000;
auto action = getCallback(0);
for (int i = 0; i < 10; i++) {
@ -175,10 +192,9 @@ TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
clearCalledCallbacks();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// Theoretically trigger 10 times, but check for at least 9 times to be stable.
ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
// Should only takes 1s, use 5s as timeout to be safe.
ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
<< "Not enough callbacks called before timeout";
timer.unregisterTimerCallback(action);