aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Nshimiye <onshimiye@google.com>2024-04-08 13:27:40 +0000
committerOlivier Nshimiye <onshimiye@google.com>2024-04-08 14:57:03 +0000
commitdbb46cf0d85303bf117ed7b8893cff1d31886601 (patch)
treed7409338b239f8352885de983e06dd8d2ca9d2ec
parentaf227103e1f11e0e8fe6d06c6baabceb0d2f1fb3 (diff)
downloadtradefederation-dbb46cf0d85303bf117ed7b8893cff1d31886601.tar.gz
Add Tradefed support for RequireRunOnPrivateProfile
Bug: 330137690 Test: tapas tradefed-all && m && tools/tradefederation/core/tradefed.sh run singleCommand host -n --class com.android.tradefed.testtype.suite.params.multiuser.RunOnPrivateProfileParameterHandlerTest Test: tapas tradefed-all && m && tools/tradefederation/core/tradefed.sh run singleCommand host -n --class com.android.tradefed.targetprep.RunOnPrivateProfileTargetPreparerTest Change-Id: Ie1e520067cee3d4177f60c7c9180c9acd8e4ea87
-rw-r--r--device_build_interfaces/com/android/tradefed/device/UserInfo.java18
-rw-r--r--javatests/com/android/tradefed/UnitTests.java4
-rw-r--r--javatests/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparerTest.java313
-rw-r--r--javatests/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandlerTest.java96
-rw-r--r--src/com/android/tradefed/targetprep/ProfileTargetPreparer.java4
-rw-r--r--src/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparer.java29
-rw-r--r--src/com/android/tradefed/testtype/suite/params/ModuleParameters.java2
-rw-r--r--src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java7
-rw-r--r--src/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandler.java40
9 files changed, 508 insertions, 5 deletions
diff --git a/device_build_interfaces/com/android/tradefed/device/UserInfo.java b/device_build_interfaces/com/android/tradefed/device/UserInfo.java
index e52163820..1ccab4a00 100644
--- a/device_build_interfaces/com/android/tradefed/device/UserInfo.java
+++ b/device_build_interfaces/com/android/tradefed/device/UserInfo.java
@@ -40,6 +40,8 @@ public final class UserInfo {
public static final String COMMUNAL_PROFILE_TYPE = "profile.COMMUNAL";
+ public static final String PRIVATE_PROFILE_TYPE = "profile.PRIVATE";
+
private final int mUserId;
private final String mUserName;
private final int mFlag;
@@ -70,7 +72,9 @@ public final class UserInfo {
/** clone profile user */
CLONE_PROFILE,
/** communal profile user */
- COMMUNAL_PROFILE;
+ COMMUNAL_PROFILE,
+ /** private profile user */
+ PRIVATE_PROFILE;
public boolean isCurrent() {
return this == CURRENT;
@@ -104,10 +108,14 @@ public final class UserInfo {
return this == CLONE_PROFILE;
}
+ public boolean isPrivateProfile() {
+ return this == PRIVATE_PROFILE;
+ }
+
/** Return whether this instance is of profile type. */
public boolean isProfile() {
// Other types are not supported
- return isManagedProfile() || isCloneProfile();
+ return isManagedProfile() || isCloneProfile() || isPrivateProfile();
}
}
@@ -167,6 +175,10 @@ public final class UserInfo {
return CLONE_PROFILE_TYPE.equals(mUserType);
}
+ public boolean isPrivateProfile() {
+ return PRIVATE_PROFILE_TYPE.equals(mUserType);
+ }
+
public boolean isCommunalProfile() {
return COMMUNAL_PROFILE_TYPE.equals(mUserType);
}
@@ -200,6 +212,8 @@ public final class UserInfo {
return isCloneProfile();
case COMMUNAL_PROFILE:
return isCommunalProfile();
+ case PRIVATE_PROFILE:
+ return isPrivateProfile();
default:
throw new RuntimeException("Variant not covered: " + userType);
}
diff --git a/javatests/com/android/tradefed/UnitTests.java b/javatests/com/android/tradefed/UnitTests.java
index d1cf792ec..fe85d26e1 100644
--- a/javatests/com/android/tradefed/UnitTests.java
+++ b/javatests/com/android/tradefed/UnitTests.java
@@ -291,6 +291,7 @@ import com.android.tradefed.targetprep.RunCommandTargetPreparerTest;
import com.android.tradefed.targetprep.RunHostCommandTargetPreparerTest;
import com.android.tradefed.targetprep.RunHostScriptTargetPreparerTest;
import com.android.tradefed.targetprep.RunOnCloneProfileTargetPreparerTest;
+import com.android.tradefed.targetprep.RunOnPrivateProfileTargetPreparerTest;
import com.android.tradefed.targetprep.RunOnSdkSandboxTargetPreparerTest;
import com.android.tradefed.targetprep.RunOnSecondaryUserTargetPreparerTest;
import com.android.tradefed.targetprep.RunOnSystemUserTargetPreparerTest;
@@ -396,6 +397,7 @@ import com.android.tradefed.testtype.suite.params.RunOnSdkSandboxHandlerTest;
import com.android.tradefed.testtype.suite.params.SecondaryUserHandlerTest;
import com.android.tradefed.testtype.suite.params.SecondaryUserOnSecondaryDisplayHandlerTest;
import com.android.tradefed.testtype.suite.params.multiuser.RunOnCloneProfileParameterHandlerTest;
+import com.android.tradefed.testtype.suite.params.multiuser.RunOnPrivateProfileParameterHandlerTest;
import com.android.tradefed.testtype.suite.params.multiuser.RunOnSecondaryUserParameterHandlerTest;
import com.android.tradefed.testtype.suite.params.multiuser.RunOnWorkProfileParameterHandlerTest;
import com.android.tradefed.testtype.suite.retry.ResultsPlayerTest;
@@ -834,6 +836,7 @@ import org.junit.runners.Suite.SuiteClasses;
RunHostCommandTargetPreparerTest.class,
RunHostScriptTargetPreparerTest.class,
RunOnCloneProfileTargetPreparerTest.class,
+ RunOnPrivateProfileTargetPreparerTest.class,
RunOnSdkSandboxTargetPreparerTest.class,
RunOnSecondaryUserTargetPreparerTest.class,
RunOnSystemUserTargetPreparerTest.class,
@@ -998,6 +1001,7 @@ import org.junit.runners.Suite.SuiteClasses;
SecondaryUserHandlerTest.class,
SecondaryUserOnSecondaryDisplayHandlerTest.class,
RunOnCloneProfileParameterHandlerTest.class,
+ RunOnPrivateProfileParameterHandlerTest.class,
// testtype/suite/retry
ResultsPlayerTest.class,
diff --git a/javatests/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparerTest.java b/javatests/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparerTest.java
new file mode 100644
index 000000000..94f75a4b0
--- /dev/null
+++ b/javatests/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparerTest.java
@@ -0,0 +1,313 @@
+/*
+ * 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.tradefed.targetprep;
+
+import static com.android.tradefed.device.UserInfo.UserType.PRIVATE_PROFILE;
+import static com.android.tradefed.targetprep.RunOnWorkProfileTargetPreparer.RUN_TESTS_AS_USER_KEY;
+import static com.android.tradefed.targetprep.RunOnWorkProfileTargetPreparer.SKIP_TESTS_REASON_KEY;
+import static com.android.tradefed.targetprep.RunOnWorkProfileTargetPreparer.TEST_PACKAGE_NAME_OPTION;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.UserInfo;
+import com.android.tradefed.invoker.TestInformation;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public final class RunOnPrivateProfileTargetPreparerTest {
+
+ private static final String CREATED_USER_10_MESSAGE = "Created user id 10";
+ public static final String CREATE_PRIVATE_PROFILE_COMMAND =
+ "pm create-user --profileOf 0 --user-type android.os.usertype.profile.PRIVATE"
+ + " --for-testing user";
+ public static final String USERTYPE_PROFILE_PRIVATE = "android.os.usertype.profile.PRIVATE";
+
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private TestInformation mTestInfo;
+
+ private OptionSetter mOptionSetter;
+
+ private ProfileTargetPreparer mPreparer;
+
+ public static final String PRIVATE_USERTYPE_DISABLED_MESSAGE =
+ "RUNNER ERROR:"
+ + " com.android.tradefed.error.HarnessRuntimeException[SHELL_COMMAND_ERROR|520100|DEPENDENCY_ISSUE]:"
+ + " Error creating profile. Command was 'pm create-user --profileOf 10 --user-type"
+ + " android.os.usertype.profile.PRIVATE user', output was 'Error:"
+ + " android.os.ServiceSpecificException: Cannot add a user of disabled type"
+ + " android.os.usertype.profile.PRIVATE.";
+
+ @Before
+ public void setUp() throws Exception {
+ mPreparer = new RunOnPrivateProfileTargetPreparer();
+ mOptionSetter = new OptionSetter(mPreparer);
+ mPreparer.setProfileUserType(USERTYPE_PROFILE_PRIVATE);
+ mPreparer.setTradefedUserType(PRIVATE_PROFILE);
+
+ ArrayList<Integer> userIds = new ArrayList<>();
+ userIds.add(0);
+
+ when(mTestInfo.getDevice().getMaxNumberOfUsersSupported()).thenReturn(2);
+ when(mTestInfo.getDevice().listUsers()).thenReturn(userIds);
+ when(mTestInfo.getDevice().getApiLevel()).thenReturn(34);
+ }
+
+ @Test
+ public void setUp_doesNotSupportPrivateUser_doesNotChangeTestUser() throws Exception {
+ when(mTestInfo.getDevice().getApiLevel()).thenReturn(30);
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.properties(), never()).put(eq(RUN_TESTS_AS_USER_KEY), any());
+ }
+
+ @Test
+ public void setUp_doesNotSupportPrivateUser_setsArgumentToSkipTests() throws Exception {
+ when(mTestInfo.getDevice().getApiLevel()).thenReturn(32);
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.properties()).put(eq(SKIP_TESTS_REASON_KEY), any());
+ }
+
+ @Test
+ public void setUp_privateUserType_createsPrivateProfileAndStartsUser() throws Exception {
+ String expectedCreateUserCommand = CREATE_PRIVATE_PROFILE_COMMAND;
+ when(mTestInfo.getDevice().executeShellCommand(expectedCreateUserCommand)).thenReturn(
+ CREATED_USER_10_MESSAGE);
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.getDevice()).executeShellCommand(expectedCreateUserCommand);
+ verify(mTestInfo.getDevice()).startUser(10, /* waitFlag= */ true);
+ }
+
+ @Test
+ public void setUp_profileAlreadyExists_doesNotCreateProfile() throws Exception {
+ Map<Integer, UserInfo> userInfos = new HashMap<>();
+ userInfos.put(
+ 10,
+ new UserInfo(
+ 10,
+ "private",
+ /* flag= */ UserInfo.FLAG_PROFILE,
+ /* isRunning= */ true,
+ "profile.PRIVATE"));
+ when(mTestInfo.getDevice().getUserInfos()).thenReturn(userInfos);
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.getDevice(), never()).executeShellCommand(any());
+ }
+
+ @Test
+ public void setUp_nonZeroCurrentUser_createsProfileForCorrectUser() throws Exception {
+ when(mTestInfo.getDevice().getCurrentUser()).thenReturn(1);
+ String expectedCreateUserCommand =
+ "pm create-user --profileOf 1 "
+ + "--user-type android.os.usertype.profile.PRIVATE --for-testing user";
+ when(mTestInfo.getDevice().executeShellCommand(expectedCreateUserCommand))
+ .thenReturn(CREATED_USER_10_MESSAGE);
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.getDevice()).executeShellCommand(expectedCreateUserCommand);
+ }
+
+ @Test
+ public void setUp_profileAlreadyExists_runsTestAsExistingUser() throws Exception {
+ Map<Integer, UserInfo> userInfos = new HashMap<>();
+ userInfos.put(
+ 11,
+ new UserInfo(
+ 11,
+ "private",
+ /* flag= */ UserInfo.FLAG_PROFILE,
+ /* isRunning= */ true,
+ "profile.PRIVATE"));
+ when(mTestInfo.getDevice().getUserInfos()).thenReturn(userInfos);
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.properties()).put(RUN_TESTS_AS_USER_KEY, "11");
+ }
+
+ @Test
+ public void setUp_setsRunTestsAsUser() throws Exception {
+ String expectedCreateUserCommand = CREATE_PRIVATE_PROFILE_COMMAND;
+ when(mTestInfo.getDevice().executeShellCommand(expectedCreateUserCommand))
+ .thenReturn(CREATED_USER_10_MESSAGE);
+ mOptionSetter.setOptionValue(TEST_PACKAGE_NAME_OPTION, "com.android.testpackage");
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.properties()).put(RUN_TESTS_AS_USER_KEY, "10");
+ }
+
+ @Test
+ public void setUp_installsPackagesInProfileUser() throws Exception {
+ String expectedCreateUserCommand = CREATE_PRIVATE_PROFILE_COMMAND;
+ when(mTestInfo.getDevice().executeShellCommand(expectedCreateUserCommand)).thenReturn(
+ CREATED_USER_10_MESSAGE);
+ mOptionSetter.setOptionValue(TEST_PACKAGE_NAME_OPTION, "com.android.testpackage");
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.getDevice()).executeShellCommand(
+ "pm install-existing --user 10 com.android.testpackage");
+ }
+
+ @Test
+ public void tearDown_profileAlreadyExists_doesNotRemoveProfile() throws Exception {
+ Map<Integer, UserInfo> userInfos = new HashMap<>();
+ userInfos.put(
+ 10,
+ new UserInfo(
+ 10,
+ "private",
+ /* flag= */ UserInfo.FLAG_PROFILE,
+ /* isRunning= */ true,
+ "profile.PRIVATE"));
+ when(mTestInfo.getDevice().getUserInfos()).thenReturn(userInfos);
+ mPreparer.setUp(mTestInfo);
+
+ mPreparer.tearDown(mTestInfo, /* throwable= */ null);
+
+ verify(mTestInfo.getDevice(), never()).removeUser(10);
+ }
+
+ @Test
+ public void setUp_doesNotDisableTearDown() throws Exception {
+ String expectedCreateUserCommand = CREATE_PRIVATE_PROFILE_COMMAND;
+ when(mTestInfo.getDevice().executeShellCommand(expectedCreateUserCommand)).thenReturn(
+ CREATED_USER_10_MESSAGE);
+ mOptionSetter.setOptionValue("disable-tear-down", "false");
+
+ mPreparer.setUp(mTestInfo);
+
+ assertThat(mPreparer.isTearDownDisabled()).isFalse();
+ }
+
+ @Test
+ public void tearDown_removesProfileUser() throws Exception {
+ String expectedCreateUserCommand = CREATE_PRIVATE_PROFILE_COMMAND;
+ when(mTestInfo.getDevice().executeShellCommand(expectedCreateUserCommand))
+ .thenReturn(CREATED_USER_10_MESSAGE);
+ mPreparer.setUp(mTestInfo);
+
+ mPreparer.tearDown(mTestInfo, /* throwable= */ null);
+
+ verify(mTestInfo.getDevice()).removeUser(10);
+ }
+
+ @Test
+ public void tearDown_clearsRunTestsAsUserProperty() throws Exception {
+ when(mTestInfo.properties().get(RUN_TESTS_AS_USER_KEY)).thenReturn("10");
+
+ mPreparer.tearDown(mTestInfo, /* throwable= */ null);
+
+ verify(mTestInfo.properties()).remove(RUN_TESTS_AS_USER_KEY);
+ }
+
+ @Test
+ public void setUp_doesNotSupportAdditionalUsers_doesNotChangeTestUser() throws Exception {
+ when(mTestInfo.getDevice().getMaxNumberOfUsersSupported()).thenReturn(1);
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.properties(), never()).put(eq(RUN_TESTS_AS_USER_KEY), any());
+ verify(mTestInfo.properties()).put(eq(SKIP_TESTS_REASON_KEY), any());
+ }
+
+ @Test
+ public void setUp_doesNotSupportAdditionalUsers_alreadyHasProfile_runsTestAsExistingUser()
+ throws Exception {
+ when(mTestInfo.getDevice().getMaxNumberOfUsersSupported()).thenReturn(1);
+ Map<Integer, UserInfo> userInfos = new HashMap<>();
+ userInfos.put(
+ 11,
+ new UserInfo(
+ 11,
+ "private",
+ /* flag= */ UserInfo.FLAG_PROFILE,
+ /* isRunning= */ true,
+ "profile.PRIVATE"));
+ when(mTestInfo.getDevice().getUserInfos()).thenReturn(userInfos);
+ mOptionSetter.setOptionValue(TEST_PACKAGE_NAME_OPTION, "com.android.testpackage");
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.getDevice()).executeShellCommand(
+ "pm install-existing --user 11 com.android.testpackage");
+ }
+
+ @Test
+ public void setUp_privateUserTypeNotSupportedOnDevice_setsArgumentToSkipTests()
+ throws DeviceNotAvailableException, TargetSetupError {
+ String expectedCreateUserCommand = CREATE_PRIVATE_PROFILE_COMMAND;
+ when(mTestInfo.getDevice().executeShellCommand(expectedCreateUserCommand)).thenReturn(
+ PRIVATE_USERTYPE_DISABLED_MESSAGE);
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.properties()).put(eq(SKIP_TESTS_REASON_KEY), any());
+ }
+
+ @Test
+ public void setUp_doesNotSupportAdditionalUsers_alreadyHasPrivateProfile_doesNotSkipTests()
+ throws Exception {
+ when(mTestInfo.getDevice().getMaxNumberOfUsersSupported()).thenReturn(1);
+ Map<Integer, UserInfo> userInfos = new HashMap<>();
+ userInfos.put(
+ 11,
+ new UserInfo(
+ 11,
+ "private",
+ /* flag= */ UserInfo.FLAG_PROFILE,
+ /* isRunning= */ true,
+ "profile.PRIVATE"));
+ when(mTestInfo.getDevice().getUserInfos()).thenReturn(userInfos);
+ mOptionSetter.setOptionValue(TEST_PACKAGE_NAME_OPTION, "com.android.testpackage");
+
+ mPreparer.setUp(mTestInfo);
+
+ verify(mTestInfo.properties(), never()).put(eq(SKIP_TESTS_REASON_KEY), any());
+ }
+}
diff --git a/javatests/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandlerTest.java b/javatests/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandlerTest.java
new file mode 100644
index 000000000..b9cff1d8e
--- /dev/null
+++ b/javatests/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandlerTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.tradefed.testtype.suite.params.multiuser;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tradefed.config.Configuration;
+import com.android.tradefed.config.IConfiguration;
+import com.android.tradefed.targetprep.RebootTargetPreparer;
+import com.android.tradefed.targetprep.RunOnPrivateProfileTargetPreparer;
+import com.android.tradefed.targetprep.RunOnSystemUserTargetPreparer;
+import com.android.tradefed.testtype.suite.params.TestFilterable;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Set;
+
+@RunWith(JUnit4.class)
+public class RunOnPrivateProfileParameterHandlerTest {
+
+ private static final String REQUIRE_RUN_ON_PRIVATE_PROFILE_NAME =
+ "com.android.bedstead.harrier.annotations.RequireRunOnPrivateProfile";
+ private static final String EXISTING_ANNOTATION_FILTER = "existing.annotation.filter";
+
+ private RunOnPrivateProfileParameterHandler mHandler;
+ private IConfiguration mModuleConfig;
+
+ private static final RunOnSystemUserTargetPreparer RUN_ON_SYSTEM_USER_TARGET_PREPARER =
+ new RunOnSystemUserTargetPreparer();
+ private static final RebootTargetPreparer OTHER_TARGET_PREPARER = new RebootTargetPreparer();
+
+ @Before
+ public void setUp() {
+ mHandler = new RunOnPrivateProfileParameterHandler();
+ mModuleConfig = new Configuration("test", "test");
+ }
+
+ @Test
+ public void applySetup_replacesIncludeAnnotationsWithRequireRunOnPrivateProfile() {
+ TestFilterable test = new TestFilterable();
+ test.addIncludeAnnotation(EXISTING_ANNOTATION_FILTER);
+ mModuleConfig.setTest(test);
+
+ mHandler.applySetup(mModuleConfig);
+
+ assertEquals(1, test.getIncludeAnnotations().size());
+ assertEquals(REQUIRE_RUN_ON_PRIVATE_PROFILE_NAME,
+ test.getIncludeAnnotations().iterator().next());
+ }
+
+ @Test
+ public void applySetup_removesRequireRunOnPrivateProfileFromExcludeFilters() {
+ TestFilterable test = new TestFilterable();
+ test.addAllExcludeAnnotation(
+ Set.of(EXISTING_ANNOTATION_FILTER, REQUIRE_RUN_ON_PRIVATE_PROFILE_NAME));
+ mModuleConfig.setTest(test);
+
+ mHandler.applySetup(mModuleConfig);
+
+ assertEquals(1, test.getExcludeAnnotations().size());
+ assertEquals(EXISTING_ANNOTATION_FILTER, test.getExcludeAnnotations().iterator().next());
+ }
+
+ @Test
+ public void addParameterSpecificConfig_replacesRunOnTargetPreparers() {
+ mModuleConfig.setTargetPreparers(
+ ImmutableList.of(RUN_ON_SYSTEM_USER_TARGET_PREPARER, OTHER_TARGET_PREPARER));
+
+ mHandler.addParameterSpecificConfig(mModuleConfig);
+
+ assertEquals(2, mModuleConfig.getTargetPreparers().size());
+ assertTrue(mModuleConfig.getTargetPreparers().get(
+ 0) instanceof RunOnPrivateProfileTargetPreparer);
+ assertEquals(OTHER_TARGET_PREPARER, mModuleConfig.getTargetPreparers().get(1));
+ }
+}
diff --git a/src/com/android/tradefed/targetprep/ProfileTargetPreparer.java b/src/com/android/tradefed/targetprep/ProfileTargetPreparer.java
index 9cf18e086..988b215ac 100644
--- a/src/com/android/tradefed/targetprep/ProfileTargetPreparer.java
+++ b/src/com/android/tradefed/targetprep/ProfileTargetPreparer.java
@@ -123,6 +123,8 @@ public abstract class ProfileTargetPreparer extends BaseTargetPreparer {
// However, major functionalities supporting clone got added in 34.
// Android U = 34
return true;
+ } else if (mTradefedUserType.isPrivateProfile() && !matchesApiLevel(testInfo, 34)) {
+ return true;
}
return false;
}
@@ -166,7 +168,7 @@ public abstract class ProfileTargetPreparer extends BaseTargetPreparer {
command += " user";
- if (mTradefedUserType.isCloneProfile() || mTradefedUserType.isManagedProfile()) {
+ if (mTradefedUserType.isProfile()) {
removeDeviceOwnerIfPresent(device);
}
diff --git a/src/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparer.java b/src/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparer.java
new file mode 100644
index 000000000..03a0aebd6
--- /dev/null
+++ b/src/com/android/tradefed/targetprep/RunOnPrivateProfileTargetPreparer.java
@@ -0,0 +1,29 @@
+/*
+ * 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.tradefed.targetprep;
+
+import static com.android.tradefed.device.UserInfo.UserType.PRIVATE_PROFILE;
+
+import com.android.tradefed.config.OptionClass;
+
+@OptionClass(alias = "run-on-clone-profile")
+public class RunOnPrivateProfileTargetPreparer extends ProfileTargetPreparer {
+
+ public RunOnPrivateProfileTargetPreparer() {
+ super(PRIVATE_PROFILE, "android.os.usertype.profile.PRIVATE");
+ }
+}
diff --git a/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java b/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java
index b32cadf02..615fbfbf5 100644
--- a/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java
+++ b/src/com/android/tradefed/testtype/suite/params/ModuleParameters.java
@@ -48,6 +48,7 @@ public enum ModuleParameters {
RUN_ON_WORK_PROFILE("run_on_work_profile", ModuleParameters.RUN_ON_WORK_PROFILE_FAMILY),
RUN_ON_SECONDARY_USER("run_on_secondary_user", ModuleParameters.RUN_ON_SECONDARY_USER_FAMILY),
RUN_ON_CLONE_PROFILE("run_on_clone_profile", ModuleParameters.RUN_ON_CLONE_PROFILE_FAMILY),
+ RUN_ON_PRIVATE_PROFILE("run_on_private_profile", ModuleParameters.RUN_ON_PRIVATE_PROFILE_FAMILY),
// Foldable mode
ALL_FOLDABLE_STATES("all_foldable_states", ModuleParameters.FOLDABLE_STATES_FAMILY),
@@ -70,6 +71,7 @@ public enum ModuleParameters {
public static final String RUN_ON_WORK_PROFILE_FAMILY = "run_on_work_profile_family";
public static final String RUN_ON_SECONDARY_USER_FAMILY = "run_on_secondary_user_family";
public static final String RUN_ON_CLONE_PROFILE_FAMILY = "run_on_clone_profile_family";
+ public static final String RUN_ON_PRIVATE_PROFILE_FAMILY = "run_on_private_profile_family";
private final String mName;
/** Defines whether several module parameters are associated and mutually exclusive. */
diff --git a/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java b/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java
index ac50b2330..01f8b91e0 100644
--- a/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java
+++ b/src/com/android/tradefed/testtype/suite/params/ModuleParametersHelper.java
@@ -27,6 +27,7 @@ import static com.android.tradefed.testtype.suite.params.ModuleParameters.NOT_SE
import static com.android.tradefed.testtype.suite.params.ModuleParameters.NOT_SECONDARY_USER_ON_SECONDARY_DISPLAY;
import static com.android.tradefed.testtype.suite.params.ModuleParameters.NO_FOLDABLE_STATES;
import static com.android.tradefed.testtype.suite.params.ModuleParameters.RUN_ON_CLONE_PROFILE;
+import static com.android.tradefed.testtype.suite.params.ModuleParameters.RUN_ON_PRIVATE_PROFILE;
import static com.android.tradefed.testtype.suite.params.ModuleParameters.RUN_ON_SDK_SANDBOX;
import static com.android.tradefed.testtype.suite.params.ModuleParameters.RUN_ON_SECONDARY_USER;
import static com.android.tradefed.testtype.suite.params.ModuleParameters.RUN_ON_WORK_PROFILE;
@@ -35,6 +36,7 @@ import static com.android.tradefed.testtype.suite.params.ModuleParameters.SECOND
import static com.android.tradefed.testtype.suite.params.ModuleParameters.SECONDARY_USER_ON_SECONDARY_DISPLAY;
import com.android.tradefed.testtype.suite.params.multiuser.RunOnCloneProfileParameterHandler;
+import com.android.tradefed.testtype.suite.params.multiuser.RunOnPrivateProfileParameterHandler;
import com.android.tradefed.testtype.suite.params.multiuser.RunOnSecondaryUserParameterHandler;
import com.android.tradefed.testtype.suite.params.multiuser.RunOnWorkProfileParameterHandler;
@@ -59,10 +61,11 @@ public final class ModuleParametersHelper {
// line separator
NO_FOLDABLE_STATES, new NegativeHandler(),
ALL_FOLDABLE_STATES, new FoldableExpandingHandler(),
- RUN_ON_CLONE_PROFILE, new RunOnCloneProfileParameterHandler());
+ RUN_ON_CLONE_PROFILE, new RunOnCloneProfileParameterHandler(),
+ RUN_ON_PRIVATE_PROFILE, new RunOnPrivateProfileParameterHandler());
private static final Map<ModuleParameters, Set<ModuleParameters>> sGroupMap =
- Map.of(MULTIUSER, Set.of(RUN_ON_WORK_PROFILE, RUN_ON_SECONDARY_USER, RUN_ON_CLONE_PROFILE));
+ Map.of(MULTIUSER, Set.of(RUN_ON_WORK_PROFILE, RUN_ON_SECONDARY_USER, RUN_ON_CLONE_PROFILE, RUN_ON_PRIVATE_PROFILE));
/**
* Optional parameters are params that will not automatically be created when the module
diff --git a/src/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandler.java b/src/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandler.java
new file mode 100644
index 000000000..c001300f6
--- /dev/null
+++ b/src/com/android/tradefed/testtype/suite/params/multiuser/RunOnPrivateProfileParameterHandler.java
@@ -0,0 +1,40 @@
+/*
+ * 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.tradefed.testtype.suite.params.multiuser;
+
+import com.android.tradefed.targetprep.RunOnPrivateProfileTargetPreparer;
+import com.android.tradefed.testtype.suite.module.Sdk34ModuleController;
+import com.android.tradefed.testtype.suite.params.IModuleParameterHandler;
+
+import java.util.Arrays;
+
+public class RunOnPrivateProfileParameterHandler extends ProfileParameterHandler implements
+ IModuleParameterHandler {
+
+ private static final String REQUIRE_RUN_ON_PRIVATE_PROFILE_NAME =
+ "com.android.bedstead.harrier.annotations.RequireRunOnPrivateProfile";
+
+ public RunOnPrivateProfileParameterHandler() {
+ super(REQUIRE_RUN_ON_PRIVATE_PROFILE_NAME, new RunOnPrivateProfileTargetPreparer(),
+ Arrays.asList(new Sdk34ModuleController()));
+ }
+
+ @Override
+ public String getParameterIdentifier() {
+ return "run-on-private-profile";
+ }
+}