From 2ccaaaef8657b04d86b37fe0d9fc44d3d4f49a82 Mon Sep 17 00:00:00 2001 From: samrobinson Date: Wed, 16 Feb 2022 15:10:32 +0000 Subject: [PATCH] Add exception information to AndroidTest analysis file. Tested: Verified that the additional information is available through instrumentation tests, as well as via manual testing. #mse-bug-week PiperOrigin-RevId: 429038695 --- .../transformer/AndroidTestUtil.java | 101 +++++++++++++----- 1 file changed, 73 insertions(+), 28 deletions(-) diff --git a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java index 6ed205da7c..ba35de44f8 100644 --- a/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java +++ b/library/transformer/src/androidTest/java/com/google/android/exoplayer2/transformer/AndroidTestUtil.java @@ -15,8 +15,8 @@ */ package com.google.android.exoplayer2.transformer; +import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import static com.google.android.exoplayer2.util.Assertions.checkState; -import static com.google.common.truth.Truth.assertWithMessage; import static java.util.concurrent.TimeUnit.SECONDS; import android.content.Context; @@ -26,10 +26,12 @@ import androidx.annotation.Nullable; import androidx.test.platform.app.InstrumentationRegistry; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.util.Log; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import org.checkerframework.checker.nullness.compatqual.NullableType; import org.json.JSONException; @@ -43,21 +45,42 @@ public final class AndroidTestUtil { "https://storage.googleapis.com/exoplayer-test-media-1/mp4/android-screens-10s.mp4"; /** - * Transforms the {@code uriString} with the {@link Transformer}. + * Transforms the {@code uriString} with the {@link Transformer}, saving a summary of the + * transformation to the application cache. * * @param context The {@link Context}. * @param testId An identifier for the test. * @param transformer The {@link Transformer} that performs the transformation. * @param uriString The uri (as a {@link String}) that will be transformed. - * @param timeoutSeconds The transformer timeout. An assertion confirms this is not exceeded. + * @param timeoutSeconds The transformer timeout. An exception is thrown if this is exceeded. * @return The {@link TransformationResult}. * @throws Exception The cause of the transformation not completing. */ public static TransformationResult runTransformer( Context context, String testId, Transformer transformer, String uriString, int timeoutSeconds) throws Exception { - AtomicReference<@NullableType Exception> exceptionReference = new AtomicReference<>(); - AtomicReference resultReference = new AtomicReference<>(); + JSONObject resultJson = new JSONObject(); + try { + TransformationResult transformationResult = + runTransformerInternal(context, testId, transformer, uriString, timeoutSeconds); + resultJson.put("transformationResult", getTransformationResultJson(transformationResult)); + return transformationResult; + } catch (Exception e) { + resultJson.put("exception", getExceptionJson(e)); + throw e; + } finally { + writeTestSummaryToFile(context, testId, resultJson); + } + } + + private static TransformationResult runTransformerInternal( + Context context, String testId, Transformer transformer, String uriString, int timeoutSeconds) + throws Exception { + AtomicReference<@NullableType TransformationException> transformationExceptionReference = + new AtomicReference<>(); + AtomicReference<@NullableType Exception> unexpectedExceptionReference = new AtomicReference<>(); + AtomicReference<@NullableType TransformationResult> transformationResultReference = + new AtomicReference<>(); CountDownLatch countDownLatch = new CountDownLatch(1); Transformer testTransformer = @@ -68,14 +91,14 @@ public final class AndroidTestUtil { @Override public void onTransformationCompleted( MediaItem inputMediaItem, TransformationResult result) { - resultReference.set(result); + transformationResultReference.set(result); countDownLatch.countDown(); } @Override public void onTransformationError( MediaItem inputMediaItem, TransformationException exception) { - exceptionReference.set(exception); + transformationExceptionReference.set(exception); countDownLatch.countDown(); } }) @@ -89,38 +112,49 @@ public final class AndroidTestUtil { try { testTransformer.startTransformation( MediaItem.fromUri(uri), outputVideoFile.getAbsolutePath()); - } catch (IOException e) { - exceptionReference.set(e); + // Catch all exceptions to report. Exceptions thrown here and not caught will NOT + // propagate. + } catch (Exception e) { + unexpectedExceptionReference.set(e); + countDownLatch.countDown(); } }); - assertWithMessage("Transformer timed out after " + timeoutSeconds + " seconds.") - .that(countDownLatch.await(timeoutSeconds, SECONDS)) - .isTrue(); - @Nullable Exception exception = exceptionReference.get(); - if (exception != null) { - throw exception; + if (!countDownLatch.await(timeoutSeconds, SECONDS)) { + throw new TimeoutException("Transformer timed out after " + timeoutSeconds + " seconds."); } - TransformationResult result = - resultReference.get().buildUpon().setFileSizeBytes(outputVideoFile.length()).build(); + @Nullable Exception unexpectedException = unexpectedExceptionReference.get(); + if (unexpectedException != null) { + throw unexpectedException; + } - writeResultToFile(context, testId, result); - return result; + @Nullable + TransformationException transformationException = transformationExceptionReference.get(); + if (transformationException != null) { + throw transformationException; + } + + // If both exceptions are null, the Transformation must have succeeded, and a + // transformationResult will be available. + return checkNotNull(transformationResultReference.get()) + .buildUpon() + .setFileSizeBytes(outputVideoFile.length()) + .build(); } - private static void writeResultToFile( - Context context, String testId, TransformationResult transformationResult) + private static void writeTestSummaryToFile(Context context, String testId, JSONObject resultJson) throws IOException, JSONException { + resultJson.put("testId", testId).put("device", getDeviceJson()); + + String analysisContents = resultJson.toString(/* indentSpaces= */ 2); + + // Log contents as well as writing to file, for easier visibility on individual device testing. + Log.i("TransformerAndroidTest_" + testId, analysisContents); + File analysisFile = createExternalCacheFile(context, /* fileName= */ testId + "-result.txt"); - String analysisContent = - new JSONObject() - .put("testId", testId) - .put("device", getDeviceJson()) - .put("transformationResult", getTransformationResultJson(transformationResult)) - .toString(/* indentSpaces= */ 2); try (FileWriter fileWriter = new FileWriter(analysisFile)) { - fileWriter.write(analysisContent); + fileWriter.write(analysisContents); } } @@ -154,5 +188,16 @@ public final class AndroidTestUtil { return transformationResultJson; } + private static JSONObject getExceptionJson(Exception exception) throws JSONException { + JSONObject exceptionJson = new JSONObject(); + exceptionJson.put("message", exception.getMessage()); + exceptionJson.put("type", exception.getClass()); + if (exception instanceof TransformationException) { + exceptionJson.put("errorCode", ((TransformationException) exception).errorCode); + } + exceptionJson.put("stackTrace", Log.getThrowableString(exception)); + return exceptionJson; + } + private AndroidTestUtil() {} }