Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0cb2e73 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Fix flaky recurrent timer test." into main

parents 8328cbb3 bdba2b57
Loading
Loading
Loading
Loading
+39 −23
Original line number Diff line number Diff line
@@ -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);