summaryrefslogtreecommitdiff
path: root/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp')
-rw-r--r--biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp105
1 files changed, 105 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..ba901ad5ca
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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::WorkerThread;
+using namespace std::chrono_literals;
+
+TEST(WorkerThreadTest, ScheduleReturnsTrueWhenQueueHasSpace) {
+ WorkerThread worker(1 /*maxQueueSize*/);
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_TRUE(worker.schedule([] {}));
+ // Allow enough time for the previous task to be processed.
+ std::this_thread::sleep_for(2ms);
+ }
+}
+
+TEST(WorkerThreadTest, ScheduleReturnsFalseWhenQueueIsFull) {
+ WorkerThread worker(2 /*maxQueueSize*/);
+ // Add a long-running task.
+ worker.schedule([] { std::this_thread::sleep_for(1s); });
+
+ // Allow enough time for the worker to start working on the previous task.
+ std::this_thread::sleep_for(2ms);
+
+ // Fill the worker's queue to the maximum.
+ worker.schedule([] {});
+ worker.schedule([] {});
+
+ EXPECT_FALSE(worker.schedule([] {}));
+}
+
+TEST(WorkerThreadTest, TasksExecuteInOrder) {
+ constexpr int NUM_TASKS = 10000;
+ WorkerThread worker(NUM_TASKS);
+
+ std::vector<int> results;
+ for (int i = 0; i < NUM_TASKS; ++i) {
+ worker.schedule([&results, i] {
+ // Delay tasks differently to provoke races.
+ std::this_thread::sleep_for(std::chrono::nanoseconds(100 - i % 100));
+ // Unguarded write to results to provoke races.
+ results.push_back(i);
+ });
+ }
+
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ // Schedule a special task to signal when all of the tasks are finished.
+ worker.schedule([&promise] { promise.set_value(); });
+ auto status = future.wait_for(1s);
+ ASSERT_EQ(status, std::future_status::ready);
+
+ 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();
+
+ {
+ WorkerThread worker(2 /*maxQueueSize*/);
+ worker.schedule([&promise1] {
+ promise1.set_value();
+ std::this_thread::sleep_for(200ms);
+ });
+ worker.schedule([&promise2] { promise2.set_value(); });
+
+ // Make sure the first task is executing.
+ auto status1 = future1.wait_for(1s);
+ ASSERT_EQ(status1, std::future_status::ready);
+ }
+
+ // The second task should never execute.
+ auto status2 = future2.wait_for(1s);
+ EXPECT_EQ(status2, std::future_status::timeout);
+}
+
+} // namespace