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

Commit 558cd71f authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "[Ravenwood] Fully remove RavenwoodConfig support" into main

parents 36dfec66 a2379ea6
Loading
Loading
Loading
Loading
+1 −161
Original line number Diff line number Diff line
@@ -15,22 +15,10 @@
 */
package android.platform.test.ravenwood;

import static com.android.ravenwood.common.RavenwoodCommonUtils.ensureIsPublicMember;

import static org.junit.Assert.fail;

import android.annotation.Nullable;
import android.util.Log;

import com.android.ravenwood.common.RavenwoodRuntimeException;

import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.TestRule;
import org.junit.runner.Description;

import java.lang.reflect.Field;

/**
 * Used to store various states associated with the current test runner that's inly needed
 * in junit-impl.
@@ -52,30 +40,10 @@ public final class RavenwoodRunnerState {
        mRunner = runner;
    }

    /**
     * The RavenwoodConfig declared in the test class
     */
    private RavenwoodConfig mConfig;
    /**
     * The RavenwoodRule currently in effect, declared in the test class
     */
    private RavenwoodRule mRule;
    private boolean mHasRavenwoodRule;
    private Description mMethodDescription;

    public void enterTestRunner() {
        Log.i(TAG, "enterTestRunner: " + mRunner);

        mHasRavenwoodRule = hasRavenwoodRule(mRunner.mTestJavaClass);
        mConfig = extractConfiguration(mRunner.mTestJavaClass);

        if (mConfig != null) {
            if (mHasRavenwoodRule) {
                fail("RavenwoodConfig and RavenwoodRule cannot be used in the same class."
                        + " Suggest migrating to RavenwoodConfig.");
            }
        }

        RavenwoodRuntimeEnvironmentController.initForRunner();
    }

@@ -85,12 +53,7 @@ public final class RavenwoodRunnerState {

    public void exitTestClass() {
        Log.i(TAG, "exitTestClass: " + mRunner.mTestJavaClass.getName());
        try {
        RavenwoodRuntimeEnvironmentController.exitTestClass();
        } finally {
            mConfig = null;
            mRule = null;
        }
    }

    public void enterTestMethod(Description description) {
@@ -103,132 +66,9 @@ public final class RavenwoodRunnerState {
    }

    public void enterRavenwoodRule(RavenwoodRule rule) {
        if (!mHasRavenwoodRule) {
            fail("If you have a RavenwoodRule in your test, make sure the field type is"
                    + " RavenwoodRule so Ravenwood can detect it.");
        }
        if (mRule != null) {
            fail("Multiple nesting RavenwoodRule's are detected in the same class,"
                    + " which is not supported.");
        }
        mRule = rule;
        RavenwoodRuntimeEnvironmentController.setSystemProperties(rule.mSystemProperties);
    }

    public void exitRavenwoodRule(RavenwoodRule rule) {
        if (mRule != rule) {
            fail("RavenwoodRule did not take effect.");
        }
        mRule = null;
    }

    /**
     * @return a configuration from a test class, if any.
     */
    @Nullable
    private static RavenwoodConfig extractConfiguration(Class<?> testClass) {
        var field = findConfigurationField(testClass);
        if (field == null) {
            return null;
        }

        try {
            return (RavenwoodConfig) field.get(null);
        } catch (IllegalAccessException e) {
            throw new RavenwoodRuntimeException("Failed to fetch from the configuration field", e);
        }
    }

    /**
     * @return true if the current target class (or its super classes) has any @Rule / @ClassRule
     * fields of type RavenwoodRule.
     *
     * Note, this check won't detect cases where a Rule is of type
     * {@link TestRule} and still be a {@link RavenwoodRule}. But that'll be detected at runtime
     * as a failure, in {@link #enterRavenwoodRule}.
     */
    private static boolean hasRavenwoodRule(Class<?> testClass) {
        for (var field : testClass.getDeclaredFields()) {
            if (!field.isAnnotationPresent(Rule.class)
                    && !field.isAnnotationPresent(ClassRule.class)) {
                continue;
            }
            if (field.getType().equals(RavenwoodRule.class)) {
                return true;
            }
        }
        // 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)) {
                continue;
            }
            if (method.getReturnType().equals(RavenwoodRule.class)) {
                return true;
            }
        }
        // Look into the super class.
        if (!testClass.getSuperclass().equals(Object.class)) {
            return hasRavenwoodRule(testClass.getSuperclass());
        }
        return false;
    }

    /**
     * Find and return a field with @RavenwoodConfig.Config, which must be of type
     * RavenwoodConfig.
     */
    @Nullable
    private static Field findConfigurationField(Class<?> testClass) {
        Field foundField = null;

        for (var field : testClass.getDeclaredFields()) {
            final var hasAnot = field.isAnnotationPresent(RavenwoodConfig.Config.class);
            final var isType = field.getType().equals(RavenwoodConfig.class);

            if (hasAnot) {
                if (isType) {
                    // Good, use this field.
                    if (foundField != null) {
                        fail(String.format(
                                "Class %s has multiple fields with %s",
                                testClass.getCanonicalName(),
                                "@RavenwoodConfig.Config"));
                    }
                    // Make sure it's static public
                    ensureIsPublicMember(field, true);

                    foundField = field;
                } else {
                    fail(String.format(
                            "Field %s.%s has %s but type is not %s",
                            testClass.getCanonicalName(),
                            field.getName(),
                            "@RavenwoodConfig.Config",
                            "RavenwoodConfig"));
                    return null; // unreachable
                }
            } else {
                if (isType) {
                    fail(String.format(
                            "Field %s.%s does not have %s but type is %s",
                            testClass.getCanonicalName(),
                            field.getName(),
                            "@RavenwoodConfig.Config",
                            "RavenwoodConfig"));
                    return null; // unreachable
                } else {
                    // Unrelated field, ignore.
                    continue;
                }
            }
        }
        if (foundField != null) {
            return foundField;
        }
        if (!testClass.getSuperclass().equals(Object.class)) {
            return findConfigurationField(testClass.getSuperclass());
        }
        return null;
    }
}
+0 −57
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 android.platform.test.ravenwood.RavenwoodConfig;
import android.platform.test.ravenwood.RavenwoodRule;

import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

/**
 * Make sure having multiple RavenwoodRule's is detected.
 * (But only when running on ravenwod. Otherwise it'll be ignored.)
 */
@RunWith(AndroidJUnit4.class)
public class RavenwoodMultipleRuleTest {

    @Rule(order = Integer.MIN_VALUE)
    public final ExpectedException mExpectedException = ExpectedException.none();

    @Rule
    public final RavenwoodRule mRavenwood1 = new RavenwoodRule();

    @Rule
    public final RavenwoodRule mRavenwood2 = new RavenwoodRule();

    public RavenwoodMultipleRuleTest() {
        // We can't call it within the test method because the exception happens before
        // calling the method, so set it up here.
        if (RavenwoodConfig.isOnRavenwood()) {
            mExpectedException.expectMessage("Multiple nesting RavenwoodRule");
        }
    }

    @Test
    public void testMultipleRulesNotAllowed() {
        Assume.assumeTrue(RavenwoodConfig.isOnRavenwood());
    }
}
+103 −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.runnercallbacktests;

import static com.google.common.truth.Truth.assertThat;

import android.os.SystemProperties;
import android.platform.test.annotations.NoRavenizer;
import android.platform.test.ravenwood.RavenwoodRule;

import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;

/**
 * Test for RavenwoodRule.
 */
@NoRavenizer // This class shouldn't be executed with RavenwoodAwareTestRunner.
public class RavenwoodRuleValidationTest extends RavenwoodRunnerTestBase {

    public static class RuleInBaseClass {
        static String PROPERTY_KEY = "debug.ravenwood.prop.in.base";
        static String PROPERTY_VAL = "ravenwood";
        @Rule
        public final RavenwoodRule mRavenwood1 = new RavenwoodRule.Builder()
                .setSystemPropertyImmutable(PROPERTY_KEY, PROPERTY_VAL).build();
    }

    /**
     * Make sure that RavenwoodRule in a base class takes effect.
     */
    @RunWith(AndroidJUnit4.class)
    // CHECKSTYLE:OFF
    @Expected("""
    testRunStarted: classes
    testSuiteStarted: classes
    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest
    testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest)
    testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest)
    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleInBaseClassSuccessTest
    testSuiteFinished: classes
    testRunFinished: 1,0,0,0
    """)
    // CHECKSTYLE:ON
    public static class RuleInBaseClassSuccessTest extends RuleInBaseClass {

        @Test
        public void testRuleInBaseClass() {
            assertThat(SystemProperties.get(PROPERTY_KEY)).isEqualTo(PROPERTY_VAL);
        }
    }

    /**
     * Same as {@link RuleInBaseClass}, but the type of the rule field is not {@link RavenwoodRule}.
     */
    public abstract static class RuleWithDifferentTypeInBaseClass {
        static String PROPERTY_KEY = "debug.ravenwood.prop.in.base.different.type";
        static String PROPERTY_VAL = "ravenwood";
        @Rule
        public final TestRule mRavenwood1 = new RavenwoodRule.Builder()
                .setSystemPropertyImmutable(PROPERTY_KEY, PROPERTY_VAL).build();
    }

    /**
     * Make sure that RavenwoodRule in a base class takes effect, even if the field type is not
     */
    @RunWith(AndroidJUnit4.class)
    // CHECKSTYLE:OFF
    @Expected("""
    testRunStarted: classes
    testSuiteStarted: classes
    testSuiteStarted: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
    testStarted: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
    testFinished: testRuleInBaseClass(com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest)
    testSuiteFinished: com.android.ravenwoodtest.runnercallbacktests.RavenwoodRuleValidationTest$RuleWithDifferentTypeInBaseClassSuccessTest
    testSuiteFinished: classes
    testRunFinished: 1,0,0,0
    """)
    // CHECKSTYLE:ON
    public static class RuleWithDifferentTypeInBaseClassSuccessTest extends RuleWithDifferentTypeInBaseClass {

        @Test
        public void testRuleInBaseClass() {
            assertThat(SystemProperties.get(PROPERTY_KEY)).isEqualTo(PROPERTY_VAL);
        }
    }
}
+0 −484

File deleted.

Preview size limit exceeded, changes collapsed.

+2 −11
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 */
package com.android.ravenwoodtest.runtimetest;

import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
import static android.os.Process.FIRST_APPLICATION_UID;

import static org.junit.Assert.assertEquals;
@@ -23,7 +22,6 @@ import static org.junit.Assert.assertEquals;
import android.os.Binder;
import android.os.Build;
import android.os.Process;
import android.platform.test.ravenwood.RavenwoodConfig;
import android.system.Os;

import com.android.ravenwood.RavenwoodRuntimeState;
@@ -34,13 +32,6 @@ import org.junit.Test;

public class IdentityTest {

    @RavenwoodConfig.Config
    public static final RavenwoodConfig sConfig =
            new RavenwoodConfig.Builder()
                    .setTargetSdkLevel(UPSIDE_DOWN_CAKE)
                    .setProcessApp()
                    .build();

    @Test
    public void testUid() {
        assertEquals(FIRST_APPLICATION_UID, RavenwoodRuntimeState.sUid);
@@ -60,7 +51,7 @@ public class IdentityTest {
    @Test
    public void testTargetSdkLevel() {
        assertEquals(Build.VERSION_CODES.CUR_DEVELOPMENT, RavenwoodRuntimeState.CUR_DEVELOPMENT);
        assertEquals(UPSIDE_DOWN_CAKE, RavenwoodRuntimeState.sTargetSdkLevel);
        assertEquals(UPSIDE_DOWN_CAKE, VMRuntime.getRuntime().getTargetSdkVersion());
        assertEquals(RavenwoodRuntimeState.sTargetSdkLevel,
                VMRuntime.getRuntime().getTargetSdkVersion());
    }
}
Loading