/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "test_utils.h" using std::chrono::milliseconds; using std::chrono::steady_clock; using std::chrono::time_point; using namespace android; using namespace std::chrono_literals; using namespace testing; // ------------------------------------------------------------------------------------------------- // Delay allowed for the scheduler to process callbacks during this test. static const auto TEST_TIMEOUT = 100ms; class VibratorCallbackSchedulerTest : public Test { public: void SetUp() override { mScheduler = std::make_unique(); } protected: std::mutex mMutex; std::unique_ptr mScheduler = nullptr; vibrator::TestCounter mCallbackCounter; std::vector mExpiredCallbacks GUARDED_BY(mMutex); std::function createCallback(int32_t id) { return [this, id]() { { std::lock_guard lock(mMutex); mExpiredCallbacks.push_back(id); } mCallbackCounter.increment(); }; } std::vector getExpiredCallbacks() { std::lock_guard lock(mMutex); return std::vector(mExpiredCallbacks); } int32_t waitForCallbacks(int32_t callbackCount, milliseconds timeout) { mCallbackCounter.tryWaitUntilCountIsAtLeast(callbackCount, timeout); return mCallbackCounter.get(); } }; // ------------------------------------------------------------------------------------------------- TEST_F(VibratorCallbackSchedulerTest, TestScheduleRunsOnlyAfterDelay) { auto callbackDuration = 50ms; time_point startTime = steady_clock::now(); mScheduler->schedule(createCallback(1), callbackDuration); ASSERT_THAT(waitForCallbacks(1, callbackDuration + TEST_TIMEOUT), Eq(1)); time_point callbackTime = steady_clock::now(); // Callback took at least the required duration to trigger. ASSERT_THAT(callbackTime, Ge(startTime + callbackDuration)); } TEST_F(VibratorCallbackSchedulerTest, TestScheduleMultipleCallbacksRunsInDelayOrder) { // Schedule first callbacks long enough that all 3 will be scheduled together and run in order. mScheduler->schedule(createCallback(1), 50ms + 2 * TEST_TIMEOUT); mScheduler->schedule(createCallback(2), 50ms + TEST_TIMEOUT); mScheduler->schedule(createCallback(3), 50ms); // Callbacks triggered in the expected order based on the requested durations. ASSERT_THAT(waitForCallbacks(3, 50ms + 3 * TEST_TIMEOUT), Eq(3)); ASSERT_THAT(getExpiredCallbacks(), ElementsAre(3, 2, 1)); } TEST_F(VibratorCallbackSchedulerTest, TestDestructorDropsPendingCallbacksAndKillsThread) { // Schedule callback long enough that scheduler will be destroyed while it's still scheduled. mScheduler->schedule(createCallback(1), 100ms); mScheduler.reset(nullptr); // Should timeout waiting for callback to run. ASSERT_THAT(waitForCallbacks(1, 100ms + TEST_TIMEOUT), Eq(0)); ASSERT_THAT(getExpiredCallbacks(), IsEmpty()); }