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 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 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 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 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