1 /*
2 * Copyright (C) 2020 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 #include "utils/MultiConditionTrigger.h"
17
18 #include <gtest/gtest.h>
19
20 #include <chrono>
21 #include <set>
22 #include <thread>
23 #include <vector>
24
25 #ifdef __ANDROID__
26
27 using namespace std;
28 using std::this_thread::sleep_for;
29
30 namespace android {
31 namespace os {
32 namespace statsd {
33
TEST(MultiConditionTrigger,TestMultipleConditions)34 TEST(MultiConditionTrigger, TestMultipleConditions) {
35 int numConditions = 5;
36 string t1 = "t1", t2 = "t2", t3 = "t3", t4 = "t4", t5 = "t5";
37 set<string> conditionNames = {t1, t2, t3, t4, t5};
38
39 mutex lock;
40 condition_variable cv;
41 bool triggerCalled = false;
42
43 // Mark done as true and notify in the done.
44 MultiConditionTrigger trigger(conditionNames, [&lock, &cv, &triggerCalled] {
45 {
46 lock_guard lg(lock);
47 triggerCalled = true;
48 }
49 cv.notify_all();
50 });
51
52 vector<thread> threads;
53 vector<int> done(numConditions, 0);
54
55 int i = 0;
56 for (const string& conditionName : conditionNames) {
57 threads.emplace_back([&done, &conditionName, &trigger, i] {
58 sleep_for(chrono::milliseconds(3));
59 done[i] = 1;
60 trigger.markComplete(conditionName);
61 });
62 i++;
63 }
64
65 unique_lock<mutex> unique_lk(lock);
66 cv.wait(unique_lk, [&triggerCalled] {
67 return triggerCalled;
68 });
69
70 for (i = 0; i < numConditions; i++) {
71 EXPECT_EQ(done[i], 1);
72 }
73
74 for (i = 0; i < numConditions; i++) {
75 threads[i].join();
76 }
77 }
78
TEST(MultiConditionTrigger,TestNoConditions)79 TEST(MultiConditionTrigger, TestNoConditions) {
80 mutex lock;
81 condition_variable cv;
82 bool triggerCalled = false;
83
84 MultiConditionTrigger trigger({}, [&lock, &cv, &triggerCalled] {
85 {
86 lock_guard lg(lock);
87 triggerCalled = true;
88 }
89 cv.notify_all();
90 });
91
92 unique_lock<mutex> unique_lk(lock);
93 cv.wait(unique_lk, [&triggerCalled] { return triggerCalled; });
94 EXPECT_TRUE(triggerCalled);
95 // Ensure that trigger occurs immediately if no events need to be completed.
96 }
97
TEST(MultiConditionTrigger,TestMarkCompleteCalledBySameCondition)98 TEST(MultiConditionTrigger, TestMarkCompleteCalledBySameCondition) {
99 string t1 = "t1", t2 = "t2";
100 set<string> conditionNames = {t1, t2};
101
102 mutex lock;
103 condition_variable cv;
104 bool triggerCalled = false;
105
106 MultiConditionTrigger trigger(conditionNames, [&lock, &cv, &triggerCalled] {
107 {
108 lock_guard lg(lock);
109 triggerCalled = true;
110 }
111 cv.notify_all();
112 });
113
114 trigger.markComplete(t1);
115 trigger.markComplete(t1);
116
117 // Ensure that the trigger still hasn't fired.
118 {
119 lock_guard lg(lock);
120 EXPECT_FALSE(triggerCalled);
121 }
122
123 trigger.markComplete(t2);
124 unique_lock<mutex> unique_lk(lock);
125 cv.wait(unique_lk, [&triggerCalled] { return triggerCalled; });
126 EXPECT_TRUE(triggerCalled);
127 }
128
TEST(MultiConditionTrigger,TestTriggerOnlyCalledOnce)129 TEST(MultiConditionTrigger, TestTriggerOnlyCalledOnce) {
130 string t1 = "t1";
131 set<string> conditionNames = {t1};
132
133 mutex lock;
134 condition_variable cv;
135 bool triggerCalled = false;
136 int triggerCount = 0;
137
138 MultiConditionTrigger trigger(conditionNames, [&lock, &cv, &triggerCalled, &triggerCount] {
139 {
140 lock_guard lg(lock);
141 triggerCount++;
142 triggerCalled = true;
143 }
144 cv.notify_all();
145 });
146
147 trigger.markComplete(t1);
148
149 // Ensure that the trigger fired.
150 {
151 unique_lock<mutex> unique_lk(lock);
152 cv.wait(unique_lk, [&triggerCalled] { return triggerCalled; });
153 EXPECT_TRUE(triggerCalled);
154 EXPECT_EQ(triggerCount, 1);
155 triggerCalled = false;
156 }
157
158 trigger.markComplete(t1);
159
160 // Ensure that the trigger does not fire again.
161 {
162 unique_lock<mutex> unique_lk(lock);
163 cv.wait_for(unique_lk, chrono::milliseconds(5), [&triggerCalled] { return triggerCalled; });
164 EXPECT_FALSE(triggerCalled);
165 EXPECT_EQ(triggerCount, 1);
166 }
167 }
168
169 } // namespace statsd
170 } // namespace os
171 } // namespace android
172 #else
173 GTEST_LOG_(INFO) << "This test does nothing.\n";
174 #endif
175