1 /*
2  * Copyright (C) 2023 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 package com.android.launcher3.util
18 
19 import androidx.test.ext.junit.runners.AndroidJUnit4
20 import androidx.test.filters.SmallTest
21 import com.android.launcher3.util.rule.TestStabilityRule
22 import java.util.concurrent.ExecutorService
23 import java.util.concurrent.locks.ReentrantLock
24 import junit.framework.Assert.assertEquals
25 import junit.framework.Assert.assertFalse
26 import junit.framework.Assert.assertTrue
27 import org.junit.Before
28 import org.junit.Rule
29 import org.junit.Test
30 import org.junit.runner.RunWith
31 
32 /** Unit test for [CancellableTask] */
33 @SmallTest
34 @RunWith(AndroidJUnit4::class)
35 class CancellableTaskTest {
36 
37     private lateinit var underTest: CancellableTask<Int>
38 
39     private val lock = ReentrantLock()
40     private var result: Int = -1
41     private var isTaskExecuted = false
42     private var isCallbackExecuted = false
43 
44     @get:Rule(order = 0) val testStabilityRule = TestStabilityRule()
45 
46     @Before
setupnull47     fun setup() {
48         reset()
49         submitJob()
50     }
51 
submitJobnull52     private fun submitJob() {
53         underTest =
54             CancellableTask(
55                 {
56                     isTaskExecuted = true
57                     1
58                 },
59                 Executors.VIEW_PREINFLATION_EXECUTOR,
60                 {
61                     isCallbackExecuted = true
62                     result = it + 1
63                 }
64             )
65         Executors.UI_HELPER_EXECUTOR.execute(underTest)
66     }
67 
68     @Test
run_and_completenull69     fun run_and_complete() {
70         awaitAllExecutorCompleted()
71 
72         assertTrue("task should be executed", isTaskExecuted)
73         assertTrue("callback should be executed", isCallbackExecuted)
74         assertEquals(2, result)
75     }
76 
77     @Test
run_and_cancel_cancelTaskAndCallbacknull78     fun run_and_cancel_cancelTaskAndCallback() {
79         awaitAllExecutorCompleted()
80         reset()
81         lock.lock()
82         Executors.UI_HELPER_EXECUTOR.submit { lock.lock() }
83         submitJob()
84 
85         underTest.cancel()
86 
87         lock.unlock() // unblock task on UI_HELPER_EXECUTOR
88         awaitAllExecutorCompleted()
89         assertFalse("task should not be executed.", isTaskExecuted)
90         assertFalse("callback should not be executed.", isCallbackExecuted)
91         assertEquals(0, result)
92     }
93 
94     @Test
run_and_cancel_cancelCallbacknull95     fun run_and_cancel_cancelCallback() {
96         awaitAllExecutorCompleted()
97         reset()
98         lock.lock()
99         Executors.VIEW_PREINFLATION_EXECUTOR.submit { lock.lock() }
100         submitJob()
101         awaitExecutorCompleted(Executors.UI_HELPER_EXECUTOR)
102         assertTrue("task should be executed.", isTaskExecuted)
103 
104         underTest.cancel()
105 
106         lock.unlock() // unblock callback on VIEW_PREINFLATION_EXECUTOR
107         awaitExecutorCompleted(Executors.VIEW_PREINFLATION_EXECUTOR)
108         assertFalse("callback should not be executed.", isCallbackExecuted)
109         assertEquals(0, result)
110     }
111 
112     @Test
run_and_cancelAfterCompletion_executeAllnull113     fun run_and_cancelAfterCompletion_executeAll() {
114         awaitAllExecutorCompleted()
115 
116         underTest.cancel()
117 
118         assertTrue("task should be executed", isTaskExecuted)
119         assertTrue("callback should be executed", isCallbackExecuted)
120         assertEquals(2, result)
121     }
122 
awaitExecutorCompletednull123     private fun awaitExecutorCompleted(executor: ExecutorService) {
124         executor.submit<Any> { null }.get()
125     }
126 
awaitAllExecutorCompletednull127     private fun awaitAllExecutorCompleted() {
128         awaitExecutorCompleted(Executors.UI_HELPER_EXECUTOR)
129         awaitExecutorCompleted(Executors.VIEW_PREINFLATION_EXECUTOR)
130     }
131 
resetnull132     private fun reset() {
133         result = 0
134         isTaskExecuted = false
135         isCallbackExecuted = false
136     }
137 }
138