blob: 5bb9e7e886565549108843d6bc4917f7861a9df4 [file] [log] [blame]
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -08001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
18#include <chrono>
19#include <future>
20#include <thread>
21
22#include <gtest/gtest.h>
23
Joshua McCloskeyc8c0bad2022-05-10 05:17:44 +000024#include "thread/WorkerThread.h"
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080025
26namespace {
27
Joshua McCloskeyc8c0bad2022-05-10 05:17:44 +000028using namespace aidl::android::hardware::biometrics;
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080029using namespace std::chrono_literals;
30
31TEST(WorkerThreadTest, ScheduleReturnsTrueWhenQueueHasSpace) {
32 WorkerThread worker(1 /*maxQueueSize*/);
33 for (int i = 0; i < 100; ++i) {
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +000034 std::promise<void> promise;
35 auto future = promise.get_future();
36
37 ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise)]() mutable {
38 // Notify that the task has started.
39 promise.set_value();
40 })));
41
Ilya Matyukhin77160fa2021-05-10 10:07:34 -070042 future.wait();
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080043 }
44}
45
46TEST(WorkerThreadTest, ScheduleReturnsFalseWhenQueueIsFull) {
47 WorkerThread worker(2 /*maxQueueSize*/);
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080048
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +000049 std::promise<void> promise;
50 auto future = promise.get_future();
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080051
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +000052 // Schedule a long-running task.
53 ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise)]() mutable {
54 // Notify that the task has started.
55 promise.set_value();
56 // Block for a "very long" time.
Ilya Matyukhin77160fa2021-05-10 10:07:34 -070057 std::this_thread::sleep_for(1s);
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +000058 })));
59
60 // Make sure the long-running task began executing.
Ilya Matyukhin77160fa2021-05-10 10:07:34 -070061 future.wait();
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +000062
63 // The first task is already being worked on, which means the queue must be empty.
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080064 // Fill the worker's queue to the maximum.
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +000065 ASSERT_TRUE(worker.schedule(Callable::from([] {})));
66 ASSERT_TRUE(worker.schedule(Callable::from([] {})));
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080067
Ilya Matyukhin4f5d6802021-02-22 13:10:55 -080068 EXPECT_FALSE(worker.schedule(Callable::from([] {})));
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080069}
70
71TEST(WorkerThreadTest, TasksExecuteInOrder) {
72 constexpr int NUM_TASKS = 10000;
Tim Murray712f48c2022-04-19 17:36:33 -070073 WorkerThread worker(NUM_TASKS + 1);
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080074
Ilya Matyukhin916410f2021-06-09 17:52:35 -070075 std::mutex mut;
76 std::condition_variable cv;
77 bool finished = false;
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080078 std::vector<int> results;
Ilya Matyukhin916410f2021-06-09 17:52:35 -070079
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080080 for (int i = 0; i < NUM_TASKS; ++i) {
Ilya Matyukhin916410f2021-06-09 17:52:35 -070081 worker.schedule(Callable::from([&mut, &results, i] {
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080082 // Delay tasks differently to provoke races.
83 std::this_thread::sleep_for(std::chrono::nanoseconds(100 - i % 100));
Ilya Matyukhin916410f2021-06-09 17:52:35 -070084 auto lock = std::lock_guard(mut);
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080085 results.push_back(i);
Ilya Matyukhin4f5d6802021-02-22 13:10:55 -080086 }));
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080087 }
88
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080089 // Schedule a special task to signal when all of the tasks are finished.
Ilya Matyukhin916410f2021-06-09 17:52:35 -070090 worker.schedule(Callable::from([&mut, &cv, &finished] {
91 auto lock = std::lock_guard(mut);
92 finished = true;
93 cv.notify_one();
94 }));
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080095
Ilya Matyukhin916410f2021-06-09 17:52:35 -070096 auto lock = std::unique_lock(mut);
97 cv.wait(lock, [&finished] { return finished; });
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -080098 ASSERT_EQ(results.size(), NUM_TASKS);
99 EXPECT_TRUE(std::is_sorted(results.begin(), results.end()));
100}
101
102TEST(WorkerThreadTest, ExecutionStopsAfterWorkerIsDestroyed) {
103 std::promise<void> promise1;
104 std::promise<void> promise2;
105 auto future1 = promise1.get_future();
106 auto future2 = promise2.get_future();
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +0000107 std::atomic<bool> value;
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -0800108
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +0000109 // Local scope for the worker to test its destructor when it goes out of scope.
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -0800110 {
111 WorkerThread worker(2 /*maxQueueSize*/);
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -0800112
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +0000113 ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise1)]() mutable {
114 promise.set_value();
115 std::this_thread::sleep_for(200ms);
116 })));
117
118 // The first task should start executing.
Ilya Matyukhin77160fa2021-05-10 10:07:34 -0700119 future1.wait();
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +0000120
121 // The second task should schedule successfully.
122 ASSERT_TRUE(
123 worker.schedule(Callable::from([promise = std::move(promise2), &value]() mutable {
124 // The worker should destruct before it gets a chance to execute this.
125 value = true;
126 promise.set_value();
127 })));
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -0800128 }
129
130 // The second task should never execute.
Ilya Matyukhin77160fa2021-05-10 10:07:34 -0700131 future2.wait();
Ilya Matyukhin1d998ec2021-03-22 22:05:27 +0000132 // The future is expected to be ready but contain an exception.
133 // Cannot use ASSERT_THROW because exceptions are disabled in this codebase.
134 // ASSERT_THROW(future2.get(), std::future_error);
135 EXPECT_FALSE(value);
Ilya Matyukhin1f3c8522021-02-12 12:56:02 -0800136}
137
138} // namespace