Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c00bf29 authored by John Wu's avatar John Wu
Browse files

[Ravenwood] Always initialize Ravenwood environment

Even if no configuration or rules are set, we still want tests to run in
the default Ravenwood environment.

Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh
Flag: EXEMPT host test change only
Bug: 356918135
Change-Id: Ic065953881229c2e226f55db4db9fc46b1e0e08f
parent 6774f72a
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 com.android.ravenwoodtest.bivalenttest;

import static org.junit.Assert.assertNotNull;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Test;
import org.junit.runner.RunWith;

/**
 * Test to make sure the environment is still initialized when no config and no rules are set.
 */
@RunWith(AndroidJUnit4.class)
public class RavenwoodNoConfigNoRuleTest {

    @Test
    public void testInitialization() {
        assertNotNull(InstrumentationRegistry.getInstrumentation());
    }
}
+28 −18
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ public final class RavenwoodRunnerState {

    private RavenwoodConfig mCurrentConfig;
    private RavenwoodRule mCurrentRule;
    private boolean mHasRavenwoodRule;

    public Description getClassDescription() {
        return mClassDescription;
@@ -71,6 +72,7 @@ public final class RavenwoodRunnerState {
    public void enterTestClass(Description classDescription) throws IOException {
        mClassDescription = classDescription;

        mHasRavenwoodRule = hasRavenwoodRule(mRunner.getTestClass().getJavaClass());
        mCurrentConfig = extractConfiguration(mRunner.getTestClass().getJavaClass());

        if (mCurrentConfig != null) {
@@ -97,9 +99,13 @@ public final class RavenwoodRunnerState {
    }

    public void enterRavenwoodRule(RavenwoodRule rule) throws IOException {
        if (!mHasRavenwoodRule) {
            fail("If you have a RavenwoodRule in your test, make sure the field type is"
                    + " RavenwoodRule so Ravenwood can detect it.");
        }
        if (mCurrentConfig != null) {
            fail("RavenwoodConfiguration and RavenwoodRule cannot be used in the same class."
                    + " Suggest migrating to RavenwoodConfiguration.");
            fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class."
                    + " Suggest migrating to RavenwoodConfig.");
        }
        if (mCurrentRule != null) {
            fail("Multiple nesting RavenwoodRule's are detected in the same class,"
@@ -125,16 +131,20 @@ public final class RavenwoodRunnerState {
     * @return a configuration from a test class, if any.
     */
    @Nullable
    private static RavenwoodConfig extractConfiguration(Class<?> testClass) {
        final boolean hasRavenwoodRule = hasRavenwoodRule(testClass);

    private RavenwoodConfig extractConfiguration(Class<?> testClass) {
        var field = findConfigurationField(testClass);
        if (field == null) {
            if (mHasRavenwoodRule) {
                // Should be handled by RavenwoodRule
                return null;
            }
        if (hasRavenwoodRule) {
            fail("RavenwoodConfiguration and RavenwoodRule cannot be used in the same class."
                    + " Suggest migrating to RavenwoodConfiguration.");

            // If no RavenwoodConfig and no RavenwoodRule, return a default config
            return new RavenwoodConfig.Builder().build();
        }
        if (mHasRavenwoodRule) {
            fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class."
                    + " Suggest migrating to RavenwoodConfig.");
        }

        try {
@@ -155,7 +165,7 @@ public final class RavenwoodRunnerState {
    private static boolean hasRavenwoodRule(Class<?> testClass) {
        for (var field : testClass.getDeclaredFields()) {
            if (!field.isAnnotationPresent(Rule.class)
                    && field.isAnnotationPresent(ClassRule.class)) {
                    && !field.isAnnotationPresent(ClassRule.class)) {
                continue;
            }
            if (field.getType().equals(RavenwoodRule.class)) {
@@ -165,7 +175,7 @@ public final class RavenwoodRunnerState {
        // JUnit supports rules as methods, so we need to check them too.
        for (var method : testClass.getDeclaredMethods()) {
            if (!method.isAnnotationPresent(Rule.class)
                    && method.isAnnotationPresent(ClassRule.class)) {
                    && !method.isAnnotationPresent(ClassRule.class)) {
                continue;
            }
            if (method.getReturnType().equals(RavenwoodRule.class)) {
@@ -180,8 +190,8 @@ public final class RavenwoodRunnerState {
    }

    /**
     * Find and return a field with @RavenwoodConfiguration.Config, which must be of type
     * RavenwoodConfiguration.
     * Find and return a field with @RavenwoodConfig.Config, which must be of type
     * RavenwoodConfig.
     */
    @Nullable
    private static Field findConfigurationField(Class<?> testClass) {
@@ -198,7 +208,7 @@ public final class RavenwoodRunnerState {
                        fail(String.format(
                                "Class %s has multiple fields with %s",
                                testClass.getCanonicalName(),
                                "@RavenwoodConfiguration.Config"));
                                "@RavenwoodConfig.Config"));
                    }
                    // Make sure it's static public
                    ensureIsPublicMember(field, true);
@@ -209,8 +219,8 @@ public final class RavenwoodRunnerState {
                            "Field %s.%s has %s but type is not %s",
                            testClass.getCanonicalName(),
                            field.getName(),
                            "@RavenwoodConfiguration.Config",
                            "RavenwoodConfiguration"));
                            "@RavenwoodConfig.Config",
                            "RavenwoodConfig"));
                    return null; // unreachable
                }
            } else {
@@ -219,8 +229,8 @@ public final class RavenwoodRunnerState {
                            "Field %s.%s does not have %s but type is %s",
                            testClass.getCanonicalName(),
                            field.getName(),
                            "@RavenwoodConfiguration.Config",
                            "RavenwoodConfiguration"));
                            "@RavenwoodConfig.Config",
                            "RavenwoodConfig"));
                    return null; // unreachable
                } else {
                    // Unrelated field, ignore.
+25 −16
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runner.notification.StoppedByUserException;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Suite;
import org.junit.runners.model.MultipleFailureException;
import org.junit.runners.model.RunnerBuilder;
import org.junit.runners.model.Statement;
@@ -170,6 +171,7 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable
    private Runner mRealRunner = null;
    private Description mDescription = null;
    private Throwable mExceptionInConstructor = null;
    private boolean mRealRunnerTakesRunnerBuilder = false;

    /**
     * Stores internal states / methods associated with this runner that's only needed in
@@ -243,7 +245,7 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable
        }
    }

    private static Runner instantiateRealRunner(
    private Runner instantiateRealRunner(
            Class<? extends Runner> realRunnerClass,
            Class<?> testClass)
            throws NoSuchMethodException, InvocationTargetException, InstantiationException,
@@ -251,9 +253,9 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable
        try {
            return realRunnerClass.getConstructor(Class.class).newInstance(testClass);
        } catch (NoSuchMethodException e) {
            var runnerBuilder = new AllDefaultPossibilitiesBuilder();
            return realRunnerClass.getConstructor(Class.class,
                    RunnerBuilder.class).newInstance(testClass, runnerBuilder);
            var constructor = realRunnerClass.getConstructor(Class.class, RunnerBuilder.class);
            mRealRunnerTakesRunnerBuilder = true;
            return constructor.newInstance(testClass, new AllDefaultPossibilitiesBuilder());
        }
    }

@@ -317,8 +319,13 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable
            return;
        }

        // TODO(b/365976974): handle nested classes better
        final boolean skipRunnerHook =
                mRealRunnerTakesRunnerBuilder && mRealRunner instanceof Suite;

        sCurrentRunner.set(this);
        try {
            if (!skipRunnerHook) {
                try {
                    RavenwoodAwareTestRunnerHook.onBeforeInnerRunnerStart(
                            this, getDescription());
@@ -326,18 +333,20 @@ public final class RavenwoodAwareTestRunner extends Runner implements Filterable
                    notifier.reportBeforeTestFailure(getDescription(), th);
                    return;
                }
            }

            // Delegate to the inner runner.
            mRealRunner.run(notifier);
        } finally {
            sCurrentRunner.remove();

            if (!skipRunnerHook) {
                try {
                    RavenwoodAwareTestRunnerHook.onAfterInnerRunnerFinished(
                            this, getDescription());
                } catch (Throwable th) {
                    notifier.reportAfterTestFailure(th);
                return;
                }
            }
        }
    }
+37 −8
Original line number Diff line number Diff line
@@ -146,7 +146,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    testRunStarted: classes
    testSuiteStarted: classes
    testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateConfigTest)
    testFailure: Class com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.DuplicateConfigTest has multiple fields with @RavenwoodConfiguration.Config
    testFailure: Class com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.DuplicateConfigTest has multiple fields with @RavenwoodConfig.Config
    testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$DuplicateConfigTest)
    testSuiteFinished: classes
    testRunFinished: 1,1,0,0
@@ -220,7 +220,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    }

    /**
     * @Config's must be of type RavenwoodConfiguration.
     * @Config's must be of type RavenwoodConfig.
     */
    @RunWith(AndroidJUnit4.class)
    // CHECKSTYLE:OFF
@@ -228,7 +228,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    testRunStarted: classes
    testSuiteStarted: classes
    testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeConfigTest)
    testFailure: Field com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.WrongTypeConfigTest.sConfig has @RavenwoodConfiguration.Config but type is not RavenwoodConfiguration
    testFailure: Field com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest.WrongTypeConfigTest.sConfig has @RavenwoodConfig.Config but type is not RavenwoodConfig
    testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeConfigTest)
    testSuiteFinished: classes
    testRunFinished: 1,1,0,0
@@ -237,7 +237,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    public static class WrongTypeConfigTest {

        @RavenwoodConfig.Config
        public Object sConfig =
        public static Object sConfig =
                new RavenwoodConfig.Builder().build();

        @Test
@@ -246,6 +246,34 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase

    }

    /**
     * @Rule must be of type RavenwoodRule.
     */
    @RunWith(AndroidJUnit4.class)
    // CHECKSTYLE:OFF
    @Expected("""
    testRunStarted: classes
    testSuiteStarted: classes
    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest
    testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest)
    testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
    testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest)
    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WrongTypeRuleTest
    testSuiteFinished: classes
    testRunFinished: 1,1,0,0
    """)
    // CHECKSTYLE:ON
    public static class WrongTypeRuleTest {

        @Rule
        public TestRule mRule = new RavenwoodRule.Builder().build();

        @Test
        public void testConfig() {
        }

    }

    /**
     * Config can't be used with a (instance) Rule.
     */
@@ -255,7 +283,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    testRunStarted: classes
    testSuiteStarted: classes
    testStarted: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithInstanceRuleTest)
    testFailure: RavenwoodConfiguration and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfiguration.
    testFailure: RavenwoodConfig and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfig.
    testFinished: testConfig(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$WithInstanceRuleTest)
    testSuiteFinished: classes
    testRunFinished: 1,1,0,0
@@ -373,7 +401,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    testRunStarted: classes
    testSuiteStarted: classes
    testStarted: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleInBaseClassTest)
    testFailure: RavenwoodConfiguration and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfiguration.
    testFailure: RavenwoodConfig and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfig.
    testFinished: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleInBaseClassTest)
    testSuiteFinished: classes
    testRunFinished: 1,1,0,0
@@ -408,10 +436,11 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    testSuiteStarted: classes
    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
    testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
    testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
    testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
    testSuiteFinished: classes
    testRunFinished: 1,0,0,0
    testRunFinished: 1,1,0,0
    """)
    // CHECKSTYLE:ON
    public static class RuleWithDifferentTypeInBaseClassSuccessTest extends RuleWithDifferentTypeInBaseClass {
@@ -434,7 +463,7 @@ public class RavenwoodRunnerConfigValidationTest extends RavenwoodRunnerTestBase
    testSuiteStarted: classes
    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest
    testStarted: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest)
    testFailure: RavenwoodConfiguration and RavenwoodRule cannot be used in the same class. Suggest migrating to RavenwoodConfiguration.
    testFailure: If you have a RavenwoodRule in your test, make sure the field type is RavenwoodRule so Ravenwood can detect it.
    testFinished: test(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest)
    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRunnerConfigValidationTest$ConfigWithRuleWithDifferentTypeInBaseClassTest
    testSuiteFinished: classes