1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker *
4*84e33947SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker *
8*84e33947SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker *
10*84e33947SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker */
16*84e33947SAndroid Build Coastguard Worker
17*84e33947SAndroid Build Coastguard Worker #include "chre/util/system/transaction_manager.h"
18*84e33947SAndroid Build Coastguard Worker
19*84e33947SAndroid Build Coastguard Worker #include <algorithm>
20*84e33947SAndroid Build Coastguard Worker #include <map>
21*84e33947SAndroid Build Coastguard Worker
22*84e33947SAndroid Build Coastguard Worker #include "chre/core/event_loop_common.h"
23*84e33947SAndroid Build Coastguard Worker #include "chre/core/timer_pool.h"
24*84e33947SAndroid Build Coastguard Worker #include "chre/platform/linux/system_time.h"
25*84e33947SAndroid Build Coastguard Worker
26*84e33947SAndroid Build Coastguard Worker #include "gmock/gmock.h"
27*84e33947SAndroid Build Coastguard Worker #include "gtest/gtest.h"
28*84e33947SAndroid Build Coastguard Worker
29*84e33947SAndroid Build Coastguard Worker using chre::platform_linux::SystemTimeOverride;
30*84e33947SAndroid Build Coastguard Worker using testing::_;
31*84e33947SAndroid Build Coastguard Worker using testing::Return;
32*84e33947SAndroid Build Coastguard Worker
33*84e33947SAndroid Build Coastguard Worker namespace chre {
34*84e33947SAndroid Build Coastguard Worker namespace {
35*84e33947SAndroid Build Coastguard Worker
36*84e33947SAndroid Build Coastguard Worker constexpr size_t kMaxTransactions = 32;
37*84e33947SAndroid Build Coastguard Worker constexpr Nanoseconds kTimeout = Milliseconds(10);
38*84e33947SAndroid Build Coastguard Worker constexpr uint16_t kMaxAttempts = 3;
39*84e33947SAndroid Build Coastguard Worker
40*84e33947SAndroid Build Coastguard Worker } // anonymous namespace
41*84e33947SAndroid Build Coastguard Worker
42*84e33947SAndroid Build Coastguard Worker class MockTimerPool {
43*84e33947SAndroid Build Coastguard Worker public:
44*84e33947SAndroid Build Coastguard Worker MOCK_METHOD(TimerHandle, setSystemTimer,
45*84e33947SAndroid Build Coastguard Worker (Nanoseconds, SystemEventCallbackFunction, SystemCallbackType,
46*84e33947SAndroid Build Coastguard Worker void *));
47*84e33947SAndroid Build Coastguard Worker MOCK_METHOD(bool, cancelSystemTimer, (TimerHandle));
48*84e33947SAndroid Build Coastguard Worker };
49*84e33947SAndroid Build Coastguard Worker
50*84e33947SAndroid Build Coastguard Worker class FakeTimerPool {
51*84e33947SAndroid Build Coastguard Worker public:
setSystemTimer(Nanoseconds duration,SystemEventCallbackFunction * callback,SystemCallbackType,void * data)52*84e33947SAndroid Build Coastguard Worker TimerHandle setSystemTimer(Nanoseconds duration,
53*84e33947SAndroid Build Coastguard Worker SystemEventCallbackFunction *callback,
54*84e33947SAndroid Build Coastguard Worker SystemCallbackType /*callbackType*/, void *data) {
55*84e33947SAndroid Build Coastguard Worker Timer timer = {
56*84e33947SAndroid Build Coastguard Worker .expiry = SystemTime::getMonotonicTime() + duration,
57*84e33947SAndroid Build Coastguard Worker .callback = callback,
58*84e33947SAndroid Build Coastguard Worker .data = data,
59*84e33947SAndroid Build Coastguard Worker };
60*84e33947SAndroid Build Coastguard Worker TimerHandle handle = mNextHandle++;
61*84e33947SAndroid Build Coastguard Worker mTimers[handle] = timer;
62*84e33947SAndroid Build Coastguard Worker return handle;
63*84e33947SAndroid Build Coastguard Worker }
cancelSystemTimer(TimerHandle handle)64*84e33947SAndroid Build Coastguard Worker bool cancelSystemTimer(TimerHandle handle) {
65*84e33947SAndroid Build Coastguard Worker return mTimers.erase(handle) == 1;
66*84e33947SAndroid Build Coastguard Worker }
67*84e33947SAndroid Build Coastguard Worker
68*84e33947SAndroid Build Coastguard Worker //! Advance the time to the next expiring timer and invoke its callback
69*84e33947SAndroid Build Coastguard Worker //! @return false if no timers exist
invokeNextTimer(SystemTimeOverride & time,Nanoseconds additionalDelay=Nanoseconds (0))70*84e33947SAndroid Build Coastguard Worker bool invokeNextTimer(SystemTimeOverride &time,
71*84e33947SAndroid Build Coastguard Worker Nanoseconds additionalDelay = Nanoseconds(0)) {
72*84e33947SAndroid Build Coastguard Worker auto it = std::min_element(mTimers.begin(), mTimers.end(),
73*84e33947SAndroid Build Coastguard Worker [](const auto &a, const auto &b) {
74*84e33947SAndroid Build Coastguard Worker return a.second.expiry < b.second.expiry;
75*84e33947SAndroid Build Coastguard Worker });
76*84e33947SAndroid Build Coastguard Worker if (it == mTimers.end()) {
77*84e33947SAndroid Build Coastguard Worker return false;
78*84e33947SAndroid Build Coastguard Worker }
79*84e33947SAndroid Build Coastguard Worker Timer timer = it->second;
80*84e33947SAndroid Build Coastguard Worker mTimers.erase(it);
81*84e33947SAndroid Build Coastguard Worker time.update(timer.expiry + additionalDelay);
82*84e33947SAndroid Build Coastguard Worker timer.callback(/*type=*/0, timer.data, /*extraData=*/nullptr);
83*84e33947SAndroid Build Coastguard Worker return true;
84*84e33947SAndroid Build Coastguard Worker }
85*84e33947SAndroid Build Coastguard Worker
86*84e33947SAndroid Build Coastguard Worker struct Timer {
87*84e33947SAndroid Build Coastguard Worker Nanoseconds expiry;
88*84e33947SAndroid Build Coastguard Worker SystemEventCallbackFunction *callback;
89*84e33947SAndroid Build Coastguard Worker void *data;
90*84e33947SAndroid Build Coastguard Worker };
91*84e33947SAndroid Build Coastguard Worker
92*84e33947SAndroid Build Coastguard Worker TimerHandle mNextHandle = 1;
93*84e33947SAndroid Build Coastguard Worker std::map<TimerHandle, Timer> mTimers;
94*84e33947SAndroid Build Coastguard Worker };
95*84e33947SAndroid Build Coastguard Worker
96*84e33947SAndroid Build Coastguard Worker class MockTransactionManagerCallback : public TransactionManagerCallback {
97*84e33947SAndroid Build Coastguard Worker public:
98*84e33947SAndroid Build Coastguard Worker MOCK_METHOD(void, onTransactionAttempt, (uint32_t, uint16_t), (override));
99*84e33947SAndroid Build Coastguard Worker MOCK_METHOD(void, onTransactionFailure, (uint32_t, uint16_t), (override));
100*84e33947SAndroid Build Coastguard Worker };
101*84e33947SAndroid Build Coastguard Worker
102*84e33947SAndroid Build Coastguard Worker class FakeTransactionManagerCallback : public TransactionManagerCallback {
103*84e33947SAndroid Build Coastguard Worker public:
onTransactionAttempt(uint32_t transactionId,uint16_t)104*84e33947SAndroid Build Coastguard Worker void onTransactionAttempt(uint32_t transactionId,
105*84e33947SAndroid Build Coastguard Worker uint16_t /*groupId*/) override {
106*84e33947SAndroid Build Coastguard Worker mTries.push_back(transactionId);
107*84e33947SAndroid Build Coastguard Worker }
onTransactionFailure(uint32_t transactionId,uint16_t)108*84e33947SAndroid Build Coastguard Worker void onTransactionFailure(uint32_t transactionId,
109*84e33947SAndroid Build Coastguard Worker uint16_t /*groupId*/) override {
110*84e33947SAndroid Build Coastguard Worker mFailures.push_back(transactionId);
111*84e33947SAndroid Build Coastguard Worker }
112*84e33947SAndroid Build Coastguard Worker
113*84e33947SAndroid Build Coastguard Worker std::vector<uint32_t> mTries;
114*84e33947SAndroid Build Coastguard Worker std::vector<uint32_t> mFailures;
115*84e33947SAndroid Build Coastguard Worker };
116*84e33947SAndroid Build Coastguard Worker
117*84e33947SAndroid Build Coastguard Worker using TxnMgr = TransactionManager<kMaxTransactions, MockTimerPool>;
118*84e33947SAndroid Build Coastguard Worker using TxnMgrF = TransactionManager<kMaxTransactions, FakeTimerPool>;
119*84e33947SAndroid Build Coastguard Worker
120*84e33947SAndroid Build Coastguard Worker class TransactionManagerTest : public testing::Test {
121*84e33947SAndroid Build Coastguard Worker public:
122*84e33947SAndroid Build Coastguard Worker protected:
defaultTxnMgr()123*84e33947SAndroid Build Coastguard Worker TxnMgr defaultTxnMgr() {
124*84e33947SAndroid Build Coastguard Worker return TxnMgr(mFakeCb, mTimerPool, kTimeout, kMaxAttempts);
125*84e33947SAndroid Build Coastguard Worker }
126*84e33947SAndroid Build Coastguard Worker
defaultTxnMgrF()127*84e33947SAndroid Build Coastguard Worker TxnMgrF defaultTxnMgrF() {
128*84e33947SAndroid Build Coastguard Worker return TxnMgrF(mFakeCb, mFakeTimerPool, kTimeout, kMaxAttempts);
129*84e33947SAndroid Build Coastguard Worker }
130*84e33947SAndroid Build Coastguard Worker
131*84e33947SAndroid Build Coastguard Worker static constexpr uint32_t kTimerId = 1;
132*84e33947SAndroid Build Coastguard Worker
133*84e33947SAndroid Build Coastguard Worker MockTimerPool mTimerPool;
134*84e33947SAndroid Build Coastguard Worker FakeTimerPool mFakeTimerPool;
135*84e33947SAndroid Build Coastguard Worker FakeTransactionManagerCallback mFakeCb;
136*84e33947SAndroid Build Coastguard Worker MockTransactionManagerCallback mMockCb;
137*84e33947SAndroid Build Coastguard Worker SystemTimeOverride mTime = SystemTimeOverride(0);
138*84e33947SAndroid Build Coastguard Worker };
139*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,StartSingleTransaction)140*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, StartSingleTransaction) {
141*84e33947SAndroid Build Coastguard Worker TxnMgr tm = defaultTxnMgr();
142*84e33947SAndroid Build Coastguard Worker
143*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mTimerPool, setSystemTimer(kTimeout, _, _, _))
144*84e33947SAndroid Build Coastguard Worker .Times(1)
145*84e33947SAndroid Build Coastguard Worker .WillOnce(Return(kTimerId));
146*84e33947SAndroid Build Coastguard Worker
147*84e33947SAndroid Build Coastguard Worker uint32_t id;
148*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id));
149*84e33947SAndroid Build Coastguard Worker
150*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), 1);
151*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[0], id);
152*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures.size(), 0);
153*84e33947SAndroid Build Coastguard Worker }
154*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,RemoveSingleTransaction)155*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, RemoveSingleTransaction) {
156*84e33947SAndroid Build Coastguard Worker TxnMgr tm = defaultTxnMgr();
157*84e33947SAndroid Build Coastguard Worker
158*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mTimerPool, setSystemTimer(_, _, _, _))
159*84e33947SAndroid Build Coastguard Worker .Times(1)
160*84e33947SAndroid Build Coastguard Worker .WillOnce(Return(kTimerId));
161*84e33947SAndroid Build Coastguard Worker
162*84e33947SAndroid Build Coastguard Worker uint32_t id;
163*84e33947SAndroid Build Coastguard Worker ASSERT_TRUE(tm.add(/*groupId=*/0, &id));
164*84e33947SAndroid Build Coastguard Worker
165*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mTimerPool, cancelSystemTimer(kTimerId))
166*84e33947SAndroid Build Coastguard Worker .Times(1)
167*84e33947SAndroid Build Coastguard Worker .WillOnce(Return(true));
168*84e33947SAndroid Build Coastguard Worker
169*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.remove(id));
170*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries.size(), 1);
171*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures.size(), 0);
172*84e33947SAndroid Build Coastguard Worker }
173*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,SingleTransactionSuccessOnRetry)174*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, SingleTransactionSuccessOnRetry) {
175*84e33947SAndroid Build Coastguard Worker TxnMgrF tm = defaultTxnMgrF();
176*84e33947SAndroid Build Coastguard Worker
177*84e33947SAndroid Build Coastguard Worker uint32_t id;
178*84e33947SAndroid Build Coastguard Worker ASSERT_TRUE(tm.add(0, &id));
179*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(mFakeTimerPool.invokeNextTimer(mTime));
180*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries.size(), 2);
181*84e33947SAndroid Build Coastguard Worker
182*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.remove(id));
183*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), 2);
184*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[0], id);
185*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[1], id);
186*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures.size(), 0);
187*84e33947SAndroid Build Coastguard Worker EXPECT_FALSE(mFakeTimerPool.invokeNextTimer(mTime));
188*84e33947SAndroid Build Coastguard Worker }
189*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,SingleTransactionTimeout)190*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, SingleTransactionTimeout) {
191*84e33947SAndroid Build Coastguard Worker TxnMgrF tm = defaultTxnMgrF();
192*84e33947SAndroid Build Coastguard Worker
193*84e33947SAndroid Build Coastguard Worker uint32_t id;
194*84e33947SAndroid Build Coastguard Worker ASSERT_TRUE(tm.add(0, &id));
195*84e33947SAndroid Build Coastguard Worker size_t count = 0;
196*84e33947SAndroid Build Coastguard Worker while (mFakeTimerPool.invokeNextTimer(mTime) && count++ < kMaxAttempts * 2);
197*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(count, kMaxAttempts);
198*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(std::count(mFakeCb.mTries.begin(), mFakeCb.mTries.end(), id),
199*84e33947SAndroid Build Coastguard Worker kMaxAttempts);
200*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mFailures.size(), 1);
201*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures[0], id);
202*84e33947SAndroid Build Coastguard Worker
203*84e33947SAndroid Build Coastguard Worker // The transaction should actually be gone
204*84e33947SAndroid Build Coastguard Worker EXPECT_FALSE(tm.remove(id));
205*84e33947SAndroid Build Coastguard Worker EXPECT_FALSE(mFakeTimerPool.invokeNextTimer(mTime));
206*84e33947SAndroid Build Coastguard Worker }
207*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,TwoTransactionsDifferentGroups)208*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, TwoTransactionsDifferentGroups) {
209*84e33947SAndroid Build Coastguard Worker TxnMgrF tm = defaultTxnMgrF();
210*84e33947SAndroid Build Coastguard Worker
211*84e33947SAndroid Build Coastguard Worker uint32_t id1;
212*84e33947SAndroid Build Coastguard Worker uint32_t id2;
213*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id1));
214*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/1, &id2));
215*84e33947SAndroid Build Coastguard Worker
216*84e33947SAndroid Build Coastguard Worker // Both should start
217*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), 2);
218*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[0], id1);
219*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[1], id2);
220*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures.size(), 0);
221*84e33947SAndroid Build Coastguard Worker }
222*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,TwoTransactionsSameGroup)223*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, TwoTransactionsSameGroup) {
224*84e33947SAndroid Build Coastguard Worker TxnMgrF tm = defaultTxnMgrF();
225*84e33947SAndroid Build Coastguard Worker
226*84e33947SAndroid Build Coastguard Worker uint32_t id1;
227*84e33947SAndroid Build Coastguard Worker uint32_t id2;
228*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id1));
229*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id2));
230*84e33947SAndroid Build Coastguard Worker
231*84e33947SAndroid Build Coastguard Worker // Only the first should start
232*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), 1);
233*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[0], id1);
234*84e33947SAndroid Build Coastguard Worker
235*84e33947SAndroid Build Coastguard Worker // Second starts after the first finishes
236*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.remove(id1));
237*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), 2);
238*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[1], id2);
239*84e33947SAndroid Build Coastguard Worker
240*84e33947SAndroid Build Coastguard Worker // Second completes with no funny business
241*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.remove(id2));
242*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries.size(), 2);
243*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures.size(), 0);
244*84e33947SAndroid Build Coastguard Worker EXPECT_FALSE(mFakeTimerPool.invokeNextTimer(mTime));
245*84e33947SAndroid Build Coastguard Worker }
246*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,TwoTransactionsSameGroupTimeout)247*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, TwoTransactionsSameGroupTimeout) {
248*84e33947SAndroid Build Coastguard Worker TxnMgrF tm = defaultTxnMgrF();
249*84e33947SAndroid Build Coastguard Worker
250*84e33947SAndroid Build Coastguard Worker uint32_t id1;
251*84e33947SAndroid Build Coastguard Worker uint32_t id2;
252*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id1));
253*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id2));
254*84e33947SAndroid Build Coastguard Worker
255*84e33947SAndroid Build Coastguard Worker // Time out the first transaction, which should kick off the second
256*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < kMaxAttempts; i++) {
257*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(mFakeTimerPool.invokeNextTimer(mTime));
258*84e33947SAndroid Build Coastguard Worker }
259*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), kMaxAttempts + 1);
260*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(std::count(mFakeCb.mTries.begin(), mFakeCb.mTries.end(), id1),
261*84e33947SAndroid Build Coastguard Worker kMaxAttempts);
262*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries.back(), id2);
263*84e33947SAndroid Build Coastguard Worker
264*84e33947SAndroid Build Coastguard Worker // Retry + time out behavior for second works the same as the first
265*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < kMaxAttempts; i++) {
266*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(mFakeTimerPool.invokeNextTimer(mTime));
267*84e33947SAndroid Build Coastguard Worker }
268*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), kMaxAttempts * 2);
269*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(std::count(mFakeCb.mTries.begin(), mFakeCb.mTries.end(), id2),
270*84e33947SAndroid Build Coastguard Worker kMaxAttempts);
271*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mFailures.size(), 2);
272*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures[0], id1);
273*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures[1], id2);
274*84e33947SAndroid Build Coastguard Worker EXPECT_FALSE(mFakeTimerPool.invokeNextTimer(mTime));
275*84e33947SAndroid Build Coastguard Worker }
276*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,TwoTransactionsSameGroupRemoveReverseOrder)277*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, TwoTransactionsSameGroupRemoveReverseOrder) {
278*84e33947SAndroid Build Coastguard Worker TxnMgrF tm = defaultTxnMgrF();
279*84e33947SAndroid Build Coastguard Worker
280*84e33947SAndroid Build Coastguard Worker uint32_t id1;
281*84e33947SAndroid Build Coastguard Worker uint32_t id2;
282*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id1));
283*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &id2));
284*84e33947SAndroid Build Coastguard Worker
285*84e33947SAndroid Build Coastguard Worker // Only the first should start
286*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), 1);
287*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[0], id1);
288*84e33947SAndroid Build Coastguard Worker
289*84e33947SAndroid Build Coastguard Worker // Remove second one first
290*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.remove(id2));
291*84e33947SAndroid Build Coastguard Worker
292*84e33947SAndroid Build Coastguard Worker // Finish the first one
293*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.remove(id1));
294*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mTries.size(), 1);
295*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[0], id1);
296*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures.size(), 0);
297*84e33947SAndroid Build Coastguard Worker EXPECT_FALSE(mFakeTimerPool.invokeNextTimer(mTime));
298*84e33947SAndroid Build Coastguard Worker }
299*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,MultipleTimeouts)300*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, MultipleTimeouts) {
301*84e33947SAndroid Build Coastguard Worker TxnMgrF tm = defaultTxnMgrF();
302*84e33947SAndroid Build Coastguard Worker
303*84e33947SAndroid Build Coastguard Worker // Timeout both in a single callback
304*84e33947SAndroid Build Coastguard Worker uint32_t ids[2];
305*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/0, &ids[0]));
306*84e33947SAndroid Build Coastguard Worker mTime.update(kTimeout.toRawNanoseconds() / 2);
307*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(tm.add(/*groupId=*/1, &ids[1]));
308*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(mFakeTimerPool.invokeNextTimer(mTime, kTimeout));
309*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries.size(), 4);
310*84e33947SAndroid Build Coastguard Worker
311*84e33947SAndroid Build Coastguard Worker // Since both retries were dispatched at the same time, they should time out
312*84e33947SAndroid Build Coastguard Worker // again together
313*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(mFakeTimerPool.invokeNextTimer(mTime, kTimeout));
314*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries.size(), 6);
315*84e33947SAndroid Build Coastguard Worker
316*84e33947SAndroid Build Coastguard Worker // If changing the max # of attempts, modify the below code too so it triggers
317*84e33947SAndroid Build Coastguard Worker // failure
318*84e33947SAndroid Build Coastguard Worker static_assert(kMaxAttempts == 3);
319*84e33947SAndroid Build Coastguard Worker EXPECT_TRUE(mFakeTimerPool.invokeNextTimer(mTime, kTimeout));
320*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries.size(), 6);
321*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < mFakeCb.mTries.size(); i++) {
322*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mTries[i], ids[i % 2]);
323*84e33947SAndroid Build Coastguard Worker }
324*84e33947SAndroid Build Coastguard Worker ASSERT_EQ(mFakeCb.mFailures.size(), 2);
325*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures[0], ids[0]);
326*84e33947SAndroid Build Coastguard Worker EXPECT_EQ(mFakeCb.mFailures[1], ids[1]);
327*84e33947SAndroid Build Coastguard Worker EXPECT_FALSE(mFakeTimerPool.invokeNextTimer(mTime));
328*84e33947SAndroid Build Coastguard Worker }
329*84e33947SAndroid Build Coastguard Worker
TEST_F(TransactionManagerTest,CallbackUsesCorrectGroupId)330*84e33947SAndroid Build Coastguard Worker TEST_F(TransactionManagerTest, CallbackUsesCorrectGroupId) {
331*84e33947SAndroid Build Coastguard Worker TxnMgrF tm(mMockCb, mFakeTimerPool, kTimeout, /*maxAttempts=*/1);
332*84e33947SAndroid Build Coastguard Worker
333*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mMockCb, onTransactionAttempt(_, 1)).Times(1);
334*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mMockCb, onTransactionAttempt(_, 2)).Times(1);
335*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mMockCb, onTransactionAttempt(_, 3)).Times(1);
336*84e33947SAndroid Build Coastguard Worker
337*84e33947SAndroid Build Coastguard Worker uint32_t id;
338*84e33947SAndroid Build Coastguard Worker tm.add(1, &id);
339*84e33947SAndroid Build Coastguard Worker tm.add(2, &id);
340*84e33947SAndroid Build Coastguard Worker tm.add(3, &id);
341*84e33947SAndroid Build Coastguard Worker
342*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mMockCb, onTransactionFailure(_, 1)).Times(1);
343*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mMockCb, onTransactionFailure(_, 2)).Times(1);
344*84e33947SAndroid Build Coastguard Worker EXPECT_CALL(mMockCb, onTransactionFailure(_, 3)).Times(1);
345*84e33947SAndroid Build Coastguard Worker
346*84e33947SAndroid Build Coastguard Worker mFakeTimerPool.invokeNextTimer(mTime);
347*84e33947SAndroid Build Coastguard Worker mFakeTimerPool.invokeNextTimer(mTime);
348*84e33947SAndroid Build Coastguard Worker mFakeTimerPool.invokeNextTimer(mTime);
349*84e33947SAndroid Build Coastguard Worker }
350*84e33947SAndroid Build Coastguard Worker
351*84e33947SAndroid Build Coastguard Worker } // namespace chre
352