1/*
2 * Copyright (C) 2017 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 <broadcastradio-utils/WorkerThread.h>
18#include <gtest/gtest.h>
19
20namespace {
21
22using namespace std::chrono_literals;
23
24using android::WorkerThread;
25
26using std::atomic;
27using std::chrono::time_point;
28using std::chrono::steady_clock;
29using std::is_sorted;
30using std::lock_guard;
31using std::mutex;
32using std::this_thread::sleep_for;
33using std::vector;
34
35#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \
36    ASSERT_LE((val1) - (tolerance), (val2));            \
37    ASSERT_GE((val1) + (tolerance), (val2));
38
39TEST(WorkerThreadTest, oneTask) {
40    atomic<bool> executed(false);
41    atomic<time_point<steady_clock>> stop;
42    WorkerThread thread;
43
44    auto start = steady_clock::now();
45    thread.schedule(
46        [&]() {
47            stop = steady_clock::now();
48            executed = true;
49        },
50        100ms);
51
52    sleep_for(150ms);
53
54    ASSERT_TRUE(executed);
55    auto delta = stop.load() - start;
56    ASSERT_EQ_WITH_TOLERANCE(delta, 100ms, 50ms);
57}
58
59TEST(WorkerThreadTest, cancelSecond) {
60    atomic<bool> executed1(false);
61    atomic<bool> executed2(false);
62    WorkerThread thread;
63
64    thread.schedule([&]() { executed2 = true; }, 100ms);
65    thread.schedule([&]() { executed1 = true; }, 25ms);
66
67    sleep_for(50ms);
68    thread.cancelAll();
69    sleep_for(100ms);
70
71    ASSERT_TRUE(executed1);
72    ASSERT_FALSE(executed2);
73}
74
75TEST(WorkerThreadTest, executeInOrder) {
76    mutex mut;
77    vector<int> order;
78    WorkerThread thread;
79
80    thread.schedule(
81        [&]() {
82            lock_guard<mutex> lk(mut);
83            order.push_back(0);
84        },
85        50ms);
86
87    thread.schedule(
88        [&]() {
89            lock_guard<mutex> lk(mut);
90            order.push_back(4);
91        },
92        400ms);
93
94    thread.schedule(
95        [&]() {
96            lock_guard<mutex> lk(mut);
97            order.push_back(1);
98        },
99        100ms);
100
101    thread.schedule(
102        [&]() {
103            lock_guard<mutex> lk(mut);
104            order.push_back(3);
105        },
106        300ms);
107
108    thread.schedule(
109        [&]() {
110            lock_guard<mutex> lk(mut);
111            order.push_back(2);
112        },
113        200ms);
114
115    sleep_for(500ms);
116
117    ASSERT_EQ(5u, order.size());
118    ASSERT_TRUE(is_sorted(order.begin(), order.end()));
119}
120
121TEST(WorkerThreadTest, dontExecuteAfterDestruction) {
122    atomic<bool> executed1(false);
123    atomic<bool> executed2(false);
124    {
125        WorkerThread thread;
126
127        thread.schedule([&]() { executed2 = true; }, 100ms);
128        thread.schedule([&]() { executed1 = true; }, 25ms);
129
130        sleep_for(50ms);
131    }
132    sleep_for(100ms);
133
134    ASSERT_TRUE(executed1);
135    ASSERT_FALSE(executed2);
136}
137
138}  // anonymous namespace
139