Be ultra stable, and go waaaaay faster
Thread.sleep() does not a flake-free test make, eliminate it.
And since we aren't sleeping, go 10x+ faster.
Bug: 38270821
Test: this
Change-Id: I94530edbd740f5901233b92eadc43ed9c18a9bc4
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 3fdd96e..5f3e99f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,5 +8,6 @@
tests/tests/text/
tests/tests/graphics/
tests/tests/transition/
+ tests/tests/uirendering/
tests/tests/view/
tests/tests/widget/
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
index fe79329..2f0ed64 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
@@ -15,10 +15,11 @@
*/
package android.uirendering.cts.testclasses;
+import static android.uirendering.cts.util.MockVsyncHelper.nextFrame;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -29,12 +30,11 @@
import android.graphics.Color;
import android.graphics.Paint;
import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.uirendering.cts.R;
import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
import android.uirendering.cts.util.BitmapAsserter;
+import android.uirendering.cts.util.MockVsyncHelper;
import android.view.ContextThemeWrapper;
import android.widget.EdgeEffect;
@@ -45,7 +45,7 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-@MediumTest
+@SmallTest
@RunWith(AndroidJUnit4.class)
public class EdgeEffectTests {
@@ -190,30 +190,27 @@
// validates changes to the alpha of draw commands produced by EdgeEffect
// over the course of an animation
private void verifyAlpha(EdgeEffectInitializer initializer, AlphaVerifier alphaVerifier) {
- Canvas canvas = mock(Canvas.class);
- ArgumentCaptor<Paint> captor = ArgumentCaptor.forClass(Paint.class);
- EdgeEffect edgeEffect = new EdgeEffect(getContext());
- edgeEffect.setSize(200, 200);
- initializer.initialize(edgeEffect);
- edgeEffect.draw(canvas);
- verify(canvas).drawCircle(anyFloat(), anyFloat(), anyFloat(), captor.capture());
- int oldAlpha = captor.getValue().getAlpha();
- for (int i = 0; i < 3; i++) {
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- fail();
- }
- canvas = mock(Canvas.class);
+ MockVsyncHelper.runOnVsyncThread(() -> {
+ Canvas canvas = mock(Canvas.class);
+ ArgumentCaptor<Paint> captor = ArgumentCaptor.forClass(Paint.class);
+ EdgeEffect edgeEffect = new EdgeEffect(getContext());
+ edgeEffect.setSize(200, 200);
+ initializer.initialize(edgeEffect);
edgeEffect.draw(canvas);
verify(canvas).drawCircle(anyFloat(), anyFloat(), anyFloat(), captor.capture());
- int newAlpha = captor.getValue().getAlpha();
- alphaVerifier.verify(oldAlpha, newAlpha);
- oldAlpha = newAlpha;
- }
+ int oldAlpha = captor.getValue().getAlpha();
+ for (int i = 0; i < 3; i++) {
+ nextFrame();
+ canvas = mock(Canvas.class);
+ edgeEffect.draw(canvas);
+ verify(canvas).drawCircle(anyFloat(), anyFloat(), anyFloat(), captor.capture());
+ int newAlpha = captor.getValue().getAlpha();
+ alphaVerifier.verify(oldAlpha, newAlpha);
+ oldAlpha = newAlpha;
+ }
+ });
}
- @LargeTest
@Test
public void testOnAbsorb() {
verifyAlpha(edgeEffect -> {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/MockVsyncHelper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/MockVsyncHelper.java
new file mode 100644
index 0000000..4109cc2
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/MockVsyncHelper.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uirendering.cts.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.view.animation.AnimationUtils;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class MockVsyncHelper {
+
+ private static ExecutorService sExecutor = Executors.newSingleThreadExecutor();
+ private static Future<Thread> sExecutorThread;
+
+ static {
+ // We can't wait on the future here because the lambda cannot be executed until
+ // the class has finished loading
+ sExecutorThread = sExecutor.submit(() -> {
+ AnimationUtils.lockAnimationClock(16);
+ return Thread.currentThread();
+ });
+ }
+
+ private static boolean isOnExecutorThread() {
+ try {
+ return Thread.currentThread().equals(sExecutorThread.get());
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void nextFrame() {
+ assertTrue("nextFrame() must be called inside #unOnVsyncThread block",
+ isOnExecutorThread());
+ AnimationUtils.lockAnimationClock(AnimationUtils.currentAnimationTimeMillis() + 16);
+ }
+
+ public static void runOnVsyncThread(CallableVoid callable) {
+ assertFalse("Cannot runOnVsyncThread inside #runOnVsyncThread block",
+ isOnExecutorThread());
+ try {
+ sExecutor.submit(() -> {
+ callable.call();
+ return (Void) null;
+ }).get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } catch (ExecutionException e) {
+ SneakyThrow.sneakyThrow(e.getCause() != null ? e.getCause() : e);
+ }
+ }
+
+ public interface CallableVoid {
+ void call() throws Exception;
+ }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/SneakyThrow.java b/tests/tests/uirendering/src/android/uirendering/cts/util/SneakyThrow.java
new file mode 100644
index 0000000..d4f09bd
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/SneakyThrow.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.uirendering.cts.util;
+
+/**
+ * Provides a hacky method that always throws {@code t} even if {@code t} is a checked exception.
+ * and is not declared to be thrown.
+ *
+ * See
+ * http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
+ */
+public class SneakyThrow {
+ /**
+ * A hacky method that always throws {@code t} even if {@code t} is a checked exception,
+ * and is not declared to be thrown.
+ */
+ public static void sneakyThrow(Throwable t) {
+ SneakyThrow.<RuntimeException>sneakyThrow_(t);
+ }
+
+ private static <T extends Throwable> void sneakyThrow_(Throwable t) throws T {
+ throw (T) t;
+ }
+}