1 /* 2 * Copyright (C) 2018 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 static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 22 import androidx.test.filters.LargeTest; 23 import androidx.test.runner.AndroidJUnit4; 24 25 import org.junit.Ignore; 26 import org.junit.Test; 27 import org.junit.runner.RunWith; 28 29 @LargeTest 30 @RunWith(AndroidJUnit4.class) 31 public class RaceConditionReproducerTest { 32 private final static String SOME_VALID_SEQUENCE_3_3 = "B1|A1|A2|B2|A3|B3"; 33 factorial(int n)34 private static int factorial(int n) { 35 int res = 1; 36 for (int i = 2; i <= n; ++i) res *= i; 37 return res; 38 } 39 run3_3_TestAction()40 private static void run3_3_TestAction() throws InterruptedException { 41 Thread tb = new Thread(() -> { 42 RaceConditionTracker.onEvent("B1"); 43 RaceConditionTracker.onEvent("B2"); 44 RaceConditionTracker.onEvent("B3"); 45 }); 46 tb.start(); 47 48 RaceConditionTracker.onEvent("A1"); 49 RaceConditionTracker.onEvent("A2"); 50 RaceConditionTracker.onEvent("A3"); 51 52 tb.join(); 53 } 54 55 @Test 56 @Ignore // The test is too long for continuous testing. 57 // 2 threads, 3 events each. test3_3()58 public void test3_3() throws Exception { 59 final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); 60 boolean sawTheValidSequence = false; 61 62 for (; ; ) { 63 eventProcessor.startIteration(); 64 run3_3_TestAction(); 65 final boolean needMoreIterations = eventProcessor.finishIteration(); 66 67 sawTheValidSequence = sawTheValidSequence || 68 SOME_VALID_SEQUENCE_3_3.equals(eventProcessor.getCurrentSequenceString()); 69 70 if (!needMoreIterations) break; 71 } 72 73 assertEquals("Wrong number of leaf nodes", 74 factorial(3 + 3) / (factorial(3) * factorial(3)), 75 eventProcessor.numberOfLeafNodes()); 76 assertTrue(sawTheValidSequence); 77 } 78 79 @Test 80 @Ignore // The test is too long for continuous testing. 81 // 2 threads, 3 events, including enter-exit pairs each. test3_3_enter_exit()82 public void test3_3_enter_exit() throws Exception { 83 final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); 84 boolean sawTheValidSequence = false; 85 86 for (; ; ) { 87 eventProcessor.startIteration(); 88 Thread tb = new Thread(() -> { 89 RaceConditionTracker.onEvent("B1:enter"); 90 RaceConditionTracker.onEvent("B1:exit"); 91 RaceConditionTracker.onEvent("B2"); 92 RaceConditionTracker.onEvent("B3:enter"); 93 RaceConditionTracker.onEvent("B3:exit"); 94 }); 95 tb.start(); 96 97 RaceConditionTracker.onEvent("A1"); 98 RaceConditionTracker.onEvent("A2:enter"); 99 RaceConditionTracker.onEvent("A2:exit"); 100 RaceConditionTracker.onEvent("A3:enter"); 101 RaceConditionTracker.onEvent("A3:exit"); 102 103 tb.join(); 104 final boolean needMoreIterations = eventProcessor.finishIteration(); 105 106 sawTheValidSequence = sawTheValidSequence || 107 "B1:enter|B1:exit|A1|A2:enter|A2:exit|B2|A3:enter|A3:exit|B3:enter|B3:exit". 108 equals(eventProcessor.getCurrentSequenceString()); 109 110 if (!needMoreIterations) break; 111 } 112 113 assertEquals("Wrong number of leaf nodes", 114 factorial(3 + 3) / (factorial(3) * factorial(3)), 115 eventProcessor.numberOfLeafNodes()); 116 assertTrue(sawTheValidSequence); 117 } 118 119 @Test 120 // 2 threads, 3 events each; reproducing a particular event sequence. test3_3_ReproMode()121 public void test3_3_ReproMode() throws Exception { 122 final RaceConditionReproducer eventProcessor = new RaceConditionReproducer( 123 SOME_VALID_SEQUENCE_3_3); 124 125 eventProcessor.startIteration(); 126 run3_3_TestAction(); 127 assertTrue(!eventProcessor.finishIteration()); 128 assertEquals(SOME_VALID_SEQUENCE_3_3, eventProcessor.getCurrentSequenceString()); 129 130 assertEquals("Wrong number of leaf nodes", 1, eventProcessor.numberOfLeafNodes()); 131 } 132 133 @Test 134 @Ignore // The test is too long for continuous testing. 135 // 2 threads with 2 events; 1 thread with 1 event. test2_1_2()136 public void test2_1_2() throws Exception { 137 final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); 138 139 for (; ; ) { 140 eventProcessor.startIteration(); 141 Thread tb = new Thread(() -> { 142 RaceConditionTracker.onEvent("B1"); 143 RaceConditionTracker.onEvent("B2"); 144 }); 145 tb.start(); 146 147 Thread tc = new Thread(() -> { 148 RaceConditionTracker.onEvent("C1"); 149 }); 150 tc.start(); 151 152 RaceConditionTracker.onEvent("A1"); 153 RaceConditionTracker.onEvent("A2"); 154 155 tb.join(); 156 tc.join(); 157 158 if (!eventProcessor.finishIteration()) break; 159 } 160 161 assertEquals("Wrong number of leaf nodes", 162 factorial(2 + 2 + 1) / (factorial(2) * factorial(2) * factorial(1)), 163 eventProcessor.numberOfLeafNodes()); 164 } 165 166 @Test 167 @Ignore // The test is too long for continuous testing. 168 // 2 threads with 2 events; 1 thread with 1 event. Includes enter-exit pairs. test2_1_2_enter_exit()169 public void test2_1_2_enter_exit() throws Exception { 170 final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(); 171 172 for (; ; ) { 173 eventProcessor.startIteration(); 174 Thread tb = new Thread(() -> { 175 RaceConditionTracker.onEvent("B1:enter"); 176 RaceConditionTracker.onEvent("B1:exit"); 177 RaceConditionTracker.onEvent("B2:enter"); 178 RaceConditionTracker.onEvent("B2:exit"); 179 }); 180 tb.start(); 181 182 Thread tc = new Thread(() -> { 183 RaceConditionTracker.onEvent("C1:enter"); 184 RaceConditionTracker.onEvent("C1:exit"); 185 }); 186 tc.start(); 187 188 RaceConditionTracker.onEvent("A1:enter"); 189 RaceConditionTracker.onEvent("A1:exit"); 190 RaceConditionTracker.onEvent("A2:enter"); 191 RaceConditionTracker.onEvent("A2:exit"); 192 193 tb.join(); 194 tc.join(); 195 196 if (!eventProcessor.finishIteration()) break; 197 } 198 199 assertEquals("Wrong number of leaf nodes", 200 factorial(2 + 2 + 1) / (factorial(2) * factorial(2) * factorial(1)), 201 eventProcessor.numberOfLeafNodes()); 202 } 203 } 204