summaryrefslogtreecommitdiff
path: root/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2021-08-14 06:30:57 +0000
committerXin Li <delphij@google.com>2021-08-14 06:30:57 +0000
commite287df40b90fe64c226f90c66353a33e8ef40063 (patch)
tree7c602d9041f18c2a25c6d12ab5b77203e2eeb9f2 /biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
parentff81122b948c9169a2c9024f21bd7339acf952f6 (diff)
parentb0fefa2d97288c4087897bd84c4c521f239fd508 (diff)
Merge sc-dev-plus-aosp-without-vendor@7634622
Merged-In: Ifa71accba7ecf2ab15980227a4413831cfceb187 Change-Id: I7fb44c6c578a51c8ad36649d20a46233fd9609ca
Diffstat (limited to 'biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp')
-rw-r--r--biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp b/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
new file mode 100644
index 0000000000..b2417bd242
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2021 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 <algorithm>
+#include <chrono>
+#include <future>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include "WorkerThread.h"
+
+namespace {
+
+using aidl::android::hardware::biometrics::fingerprint::Callable;
+using aidl::android::hardware::biometrics::fingerprint::WorkerThread;
+using namespace std::chrono_literals;
+
+TEST(WorkerThreadTest, ScheduleReturnsTrueWhenQueueHasSpace) {
+ WorkerThread worker(1 /*maxQueueSize*/);
+ for (int i = 0; i < 100; ++i) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise)]() mutable {
+ // Notify that the task has started.
+ promise.set_value();
+ })));
+
+ future.wait();
+ }
+}
+
+TEST(WorkerThreadTest, ScheduleReturnsFalseWhenQueueIsFull) {
+ WorkerThread worker(2 /*maxQueueSize*/);
+
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ // Schedule a long-running task.
+ ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise)]() mutable {
+ // Notify that the task has started.
+ promise.set_value();
+ // Block for a "very long" time.
+ std::this_thread::sleep_for(1s);
+ })));
+
+ // Make sure the long-running task began executing.
+ future.wait();
+
+ // The first task is already being worked on, which means the queue must be empty.
+ // Fill the worker's queue to the maximum.
+ ASSERT_TRUE(worker.schedule(Callable::from([] {})));
+ ASSERT_TRUE(worker.schedule(Callable::from([] {})));
+
+ EXPECT_FALSE(worker.schedule(Callable::from([] {})));
+}
+
+TEST(WorkerThreadTest, TasksExecuteInOrder) {
+ constexpr int NUM_TASKS = 10000;
+ WorkerThread worker(NUM_TASKS);
+
+ std::mutex mut;
+ std::condition_variable cv;
+ bool finished = false;
+ std::vector<int> results;
+
+ for (int i = 0; i < NUM_TASKS; ++i) {
+ worker.schedule(Callable::from([&mut, &results, i] {
+ // Delay tasks differently to provoke races.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(100 - i % 100));
+ auto lock = std::lock_guard(mut);
+ results.push_back(i);
+ }));
+ }
+
+ // Schedule a special task to signal when all of the tasks are finished.
+ worker.schedule(Callable::from([&mut, &cv, &finished] {
+ auto lock = std::lock_guard(mut);
+ finished = true;
+ cv.notify_one();
+ }));
+
+ auto lock = std::unique_lock(mut);
+ cv.wait(lock, [&finished] { return finished; });
+ ASSERT_EQ(results.size(), NUM_TASKS);
+ EXPECT_TRUE(std::is_sorted(results.begin(), results.end()));
+}
+
+TEST(WorkerThreadTest, ExecutionStopsAfterWorkerIsDestroyed) {
+ std::promise<void> promise1;
+ std::promise<void> promise2;
+ auto future1 = promise1.get_future();
+ auto future2 = promise2.get_future();
+ std::atomic<bool> value;
+
+ // Local scope for the worker to test its destructor when it goes out of scope.
+ {
+ WorkerThread worker(2 /*maxQueueSize*/);
+
+ ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise1)]() mutable {
+ promise.set_value();
+ std::this_thread::sleep_for(200ms);
+ })));
+
+ // The first task should start executing.
+ future1.wait();
+
+ // The second task should schedule successfully.
+ ASSERT_TRUE(
+ worker.schedule(Callable::from([promise = std::move(promise2), &value]() mutable {
+ // The worker should destruct before it gets a chance to execute this.
+ value = true;
+ promise.set_value();
+ })));
+ }
+
+ // The second task should never execute.
+ future2.wait();
+ // The future is expected to be ready but contain an exception.
+ // Cannot use ASSERT_THROW because exceptions are disabled in this codebase.
+ // ASSERT_THROW(future2.get(), std::future_error);
+ EXPECT_FALSE(value);
+}
+
+} // namespace