health@2.0 VTS test: fix flaky test

An implementation may or may not invoke the callback
immediately when registerCallback is called, causing
a race in the test. Fix the test by waiting for the
invocation, or time-out, whichever comes first.

Test: run test 200 times
Bug: 69005254
Change-Id: I79a416f9ba5c93d7e8f9f2d6e32a0f46410561d7
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index 9b86873..bf8548c 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -68,23 +68,24 @@
 };
 
 class Callback : public IHealthInfoCallback {
-    using Function = std::function<void(const HealthInfo&)>;
-
    public:
-    Callback(const Function& f) : mInternal(f) {}
-    Return<void> healthInfoChanged(const HealthInfo& info) override {
-        std::unique_lock<std::mutex> lock(mMutex);
-        if (mInternal) mInternal(info);
+    Return<void> healthInfoChanged(const HealthInfo&) override {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mInvoked = true;
+        mInvokedNotify.notify_all();
         return Void();
     }
-    void clear() {
+    template <typename R, typename P>
+    bool waitInvoke(std::chrono::duration<R, P> duration) {
         std::unique_lock<std::mutex> lock(mMutex);
-        mInternal = nullptr;
+        bool r = mInvokedNotify.wait_for(lock, duration, [this] { return this->mInvoked; });
+        mInvoked = false;
+        return r;
     }
-
    private:
     std::mutex mMutex;
-    Function mInternal;
+    std::condition_variable mInvokedNotify;
+    bool mInvoked = false;
 };
 
 #define ASSERT_OK(r) ASSERT_TRUE(isOk(r))
@@ -112,71 +113,42 @@
  */
 TEST_F(HealthHidlTest, Callbacks) {
     using namespace std::chrono_literals;
-
-    std::mutex mutex;
-    std::condition_variable cv;
-    bool firstCallbackInvoked = false;
-    bool secondCallbackInvoked = false;
-
-    sp<Callback> firstCallback = new Callback([&](const auto&) {
-        std::unique_lock<std::mutex> lk(mutex);
-        firstCallbackInvoked = true;
-    });
-
-    sp<Callback> secondCallback = new Callback([&](const auto&) {
-        std::unique_lock<std::mutex> lk(mutex);
-        secondCallbackInvoked = true;
-        cv.notify_all();
-    });
+    sp<Callback> firstCallback = new Callback();
+    sp<Callback> secondCallback = new Callback();
 
     ASSERT_ALL_OK(mHealth->registerCallback(firstCallback));
     ASSERT_ALL_OK(mHealth->registerCallback(secondCallback));
 
-    // assert that the first callback is invoked when update is called.
-    {
-        std::unique_lock<std::mutex> lk(mutex);
-        firstCallbackInvoked = false;
-        secondCallbackInvoked = false;
-    }
+    // registerCallback may or may not invoke the callback immediately, so the test needs
+    // to wait for the invocation. If the implementation chooses not to invoke the callback
+    // immediately, just wait for some time.
+    firstCallback->waitInvoke(200ms);
+    secondCallback->waitInvoke(200ms);
 
+    // assert that the first callback is invoked when update is called.
     ASSERT_ALL_OK(mHealth->update());
 
-    {
-        std::unique_lock<std::mutex> lk(mutex);
-        EXPECT_TRUE(cv.wait_for(lk, 1s, [&] {
-            return firstCallbackInvoked && secondCallbackInvoked;
-        })) << "Timeout.";
-        ASSERT_TRUE(firstCallbackInvoked);
-        ASSERT_TRUE(secondCallbackInvoked);
-    }
+    ASSERT_TRUE(firstCallback->waitInvoke(1s));
+    ASSERT_TRUE(secondCallback->waitInvoke(1s));
 
     ASSERT_ALL_OK(mHealth->unregisterCallback(firstCallback));
 
-    // assert that the second callback is still invoked even though the first is unregistered.
-    {
-        std::unique_lock<std::mutex> lk(mutex);
-        firstCallbackInvoked = false;
-        secondCallbackInvoked = false;
-    }
+    // clear any potentially pending callbacks result from wakealarm / kernel events
+    // If there is none, just wait for some time.
+    firstCallback->waitInvoke(200ms);
+    secondCallback->waitInvoke(200ms);
 
+    // assert that the second callback is still invoked even though the first is unregistered.
     ASSERT_ALL_OK(mHealth->update());
 
-    {
-        std::unique_lock<std::mutex> lk(mutex);
-        EXPECT_TRUE(cv.wait_for(lk, 1s, [&] { return secondCallbackInvoked; })) << "Timeout.";
-        ASSERT_FALSE(firstCallbackInvoked);
-        ASSERT_TRUE(secondCallbackInvoked);
-    }
+    ASSERT_FALSE(firstCallback->waitInvoke(200ms));
+    ASSERT_TRUE(secondCallback->waitInvoke(1s));
 
     ASSERT_ALL_OK(mHealth->unregisterCallback(secondCallback));
-
-    // avoid reference to lambda function that goes out of scope.
-    firstCallback->clear();
-    secondCallback->clear();
 }
 
 TEST_F(HealthHidlTest, UnregisterNonExistentCallback) {
-    sp<Callback> callback = new Callback([](const auto&) {});
+    sp<Callback> callback = new Callback();
     auto ret = mHealth->unregisterCallback(callback);
     ASSERT_OK(ret);
     ASSERT_EQ(Result::NOT_FOUND, static_cast<Result>(ret)) << "Actual: " << toString(ret);