blob: e01c8f1c148558d870a4ab942dcf506f941b3c04 [file] [log] [blame]
/*
* Copyright (C) 2021 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.bedstead.harrier;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_PACKAGE;
import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_AFFILIATED_OTHER_USERS;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_PARENT;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_UNAFFILIATED_OTHER_USERS;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DO_NOT_APPLY_TO_NEGATIVE_TESTS;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.NO;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
import com.android.bedstead.harrier.annotations.parameterized.IncludeNone;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnAffiliatedDeviceOwnerSecondaryUser;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnAffiliatedProfileOwnerSecondaryUser;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnBackgroundDeviceOwnerUser;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnDeviceOwnerUser;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnNonAffiliatedDeviceOwnerSecondaryUser;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnParentOfCorporateOwnedProfileOwner;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnParentOfProfileOwnerWithNoDeviceOwner;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnProfileOwnerPrimaryUser;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnProfileOwnerProfileWithNoDeviceOwner;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnUnaffiliatedProfileOwnerSecondaryUser;
import com.google.auto.value.AutoAnnotation;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Utility class for enterprise policy tests.
*/
public final class Policy {
// Delegate scopes to be used for a "CannotSet" state. All delegate scopes except the ones which
// should allow use of the API will be granted
private static final ImmutableSet<String> ALL_DELEGATE_SCOPES = ImmutableSet.of(
DELEGATION_CERT_INSTALL,
DELEGATION_APP_RESTRICTIONS,
DELEGATION_BLOCK_UNINSTALL,
DELEGATION_PERMISSION_GRANT,
DELEGATION_PACKAGE_ACCESS,
DELEGATION_ENABLE_SYSTEM_APP,
DELEGATION_INSTALL_EXISTING_PACKAGE,
DELEGATION_KEEP_UNINSTALLED_PACKAGES,
DELEGATION_NETWORK_LOGGING,
DELEGATION_CERT_SELECTION,
DELEGATION_SECURITY_LOGGING
);
// This is a map containing all Include* annotations and the flags which lead to them
// This is not validated - every state must have a single APPLIED_BY annotation
private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
STATE_ANNOTATIONS =
ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnDeviceOwnerUser()))
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnDeviceOwnerUser(), /* isPrimary= */ true))
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, singleAnnotation(includeRunOnBackgroundDeviceOwnerUser()))
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnBackgroundDeviceOwnerUser(), /* isPrimary= */ true))
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser()))
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser()))
.put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
.put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
.put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser()))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
.put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
.put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerPrimaryUser(), /* isPrimary= */ true))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner(), /* isPrimary= */ true))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, singleAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner()))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner(), /* isPrimary= */ true))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile()))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile(), /* isPrimary= */ true))
.build();
// This must contain one key for every APPLIED_BY that is being used, and maps to the
// "default" for testing that DPC type
// in general this will be a state which runs on the same user as the dpc.
private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
DPC_STATE_ANNOTATIONS_BASE =
ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
.put(APPLIED_BY_DEVICE_OWNER, (flags) -> hasFlag(flags.dpc(), APPLIED_BY_DEVICE_OWNER | APPLIES_IN_BACKGROUND) ? ImmutableSet.of(includeRunOnBackgroundDeviceOwnerUser()) : ImmutableSet.of(includeRunOnDeviceOwnerUser()))
.put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
.put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
.put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
.build();
private static final Map<Integer, Function<EnterprisePolicy, Set<Annotation>>>
DPC_STATE_ANNOTATIONS = DPC_STATE_ANNOTATIONS_BASE.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Policy::addGeneratedStates));
private static final int APPLIED_BY_FLAGS =
APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
| APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
| APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
| APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
private static final Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>>
ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
private Policy() {
}
@AutoAnnotation
private static IncludeNone includeNone() {
return new AutoAnnotation_Policy_includeNone();
}
@AutoAnnotation
private static IncludeRunOnDeviceOwnerUser includeRunOnDeviceOwnerUser() {
return new AutoAnnotation_Policy_includeRunOnDeviceOwnerUser();
}
@AutoAnnotation
private static IncludeRunOnNonAffiliatedDeviceOwnerSecondaryUser includeRunOnNonAffiliatedDeviceOwnerSecondaryUser() {
return new AutoAnnotation_Policy_includeRunOnNonAffiliatedDeviceOwnerSecondaryUser();
}
@AutoAnnotation
private static IncludeRunOnAffiliatedDeviceOwnerSecondaryUser includeRunOnAffiliatedDeviceOwnerSecondaryUser() {
return new AutoAnnotation_Policy_includeRunOnAffiliatedDeviceOwnerSecondaryUser();
}
@AutoAnnotation
private static IncludeRunOnAffiliatedProfileOwnerSecondaryUser includeRunOnAffiliatedProfileOwnerSecondaryUser() {
return new AutoAnnotation_Policy_includeRunOnAffiliatedProfileOwnerSecondaryUser();
}
@AutoAnnotation
private static IncludeRunOnUnaffiliatedProfileOwnerSecondaryUser includeRunOnUnaffiliatedProfileOwnerSecondaryUser() {
return new AutoAnnotation_Policy_includeRunOnUnaffiliatedProfileOwnerSecondaryUser();
}
@AutoAnnotation
private static IncludeRunOnProfileOwnerProfileWithNoDeviceOwner includeRunOnProfileOwnerProfileWithNoDeviceOwner() {
return new AutoAnnotation_Policy_includeRunOnProfileOwnerProfileWithNoDeviceOwner();
}
@AutoAnnotation
private static IncludeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile() {
return new AutoAnnotation_Policy_includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile();
}
@AutoAnnotation
private static IncludeRunOnParentOfProfileOwnerWithNoDeviceOwner includeRunOnParentOfProfileOwnerWithNoDeviceOwner() {
return new AutoAnnotation_Policy_includeRunOnParentOfProfileOwnerWithNoDeviceOwner();
}
@AutoAnnotation
private static IncludeRunOnParentOfCorporateOwnedProfileOwner includeRunOnParentOfCorporateOwnedProfileOwner() {
return new AutoAnnotation_Policy_includeRunOnParentOfCorporateOwnedProfileOwner();
}
@AutoAnnotation
private static IncludeRunOnProfileOwnerPrimaryUser includeRunOnProfileOwnerPrimaryUser() {
return new AutoAnnotation_Policy_includeRunOnProfileOwnerPrimaryUser();
}
@AutoAnnotation
private static IncludeRunOnBackgroundDeviceOwnerUser includeRunOnBackgroundDeviceOwnerUser() {
return new AutoAnnotation_Policy_includeRunOnBackgroundDeviceOwnerUser();
}
@AutoAnnotation
private static EnsureHasDelegate ensureHasDelegate(EnsureHasDelegate.AdminType admin,
String[] scopes, boolean isPrimary) {
return new AutoAnnotation_Policy_ensureHasDelegate(admin, scopes, isPrimary);
}
private static Function<EnterprisePolicy, Set<Annotation>> singleAnnotation(
Annotation annotation) {
return (i) -> ImmutableSet.of(annotation);
}
private static Function<EnterprisePolicy, Set<Annotation>> generateDelegateAnnotation(
Annotation annotation, boolean isPrimary) {
return (policy) -> {
Annotation[] existingAnnotations = annotation.annotationType().getAnnotations();
return Arrays.stream(policy.delegatedScopes())
.map(scope -> {
Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
existingAnnotations.length + 1);
newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope},
isPrimary);
return new DynamicParameterizedAnnotation(
annotation.annotationType().getSimpleName() + "Delegate:" + scope,
newAnnotations);
}).collect(Collectors.toSet());
};
}
private static Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> calculateAnnotationsMap(
Map<Integer, Function<EnterprisePolicy, Set<Annotation>>> annotations) {
Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> b = new HashMap<>();
for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> i :
annotations.entrySet()) {
if (!b.containsKey(i.getValue())) {
b.put(i.getValue(), new HashSet<>());
}
b.get(i.getValue()).add(i.getKey());
}
return b;
}
private static Function<EnterprisePolicy, Set<Annotation>> addGeneratedStates(
ImmutableMap.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> entry) {
return (policy) -> {
if (hasFlag(policy.dpc(), entry.getKey() | CAN_BE_DELEGATED)) {
Set<Annotation> results = new HashSet<>(entry.getValue().apply(policy));
results.addAll(results.stream().flatMap(
t -> generateDelegateAnnotation(t, /* isPrimary= */ true).apply(
policy).stream())
.collect(Collectors.toSet()));
return results;
}
return entry.getValue().apply(policy);
};
}
/**
* Get parameterized test runs for the given policy.
*
* <p>These are states which should be run where the policy is able to be applied.
*/
public static List<Annotation> positiveStates(String policyName,
EnterprisePolicy enterprisePolicy) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
ANNOTATIONS_MAP.entrySet()) {
if (isPositive(enterprisePolicy.dpc(), annotation.getValue())) {
annotations.addAll(annotation.getKey().apply(enterprisePolicy));
}
}
if (annotations.isEmpty()) {
// Don't run the original test unparameterized
annotations.add(includeNone());
}
return new ArrayList<>(annotations);
}
private static boolean isPositive(int[] policyFlags, Set<Integer> annotationFlags) {
for (int annotationFlag : annotationFlags) {
if (hasFlag(policyFlags, annotationFlag)) {
return true;
}
}
return false;
}
private static boolean isNegative(int[] policyFlags, Set<Integer> annotationFlags) {
for (int annotationFlag : annotationFlags) {
if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */
NO)) {
return false; // We don't support using this annotation for negative tests
}
int appliedByFlag = APPLIED_BY_FLAGS & annotationFlag;
int otherFlags = annotationFlag ^ appliedByFlag; // remove the appliedByFlag
if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */
otherFlags)) {
return true;
}
}
return false;
}
/**
* Get negative parameterized test runs for the given policy.
*
* <p>These are states which should be run where the policy is not able to be applied.
*/
public static List<Annotation> negativeStates(String policyName,
EnterprisePolicy enterprisePolicy) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
ANNOTATIONS_MAP.entrySet()) {
if (isNegative(enterprisePolicy.dpc(), annotation.getValue())) {
annotations.addAll(annotation.getKey().apply(enterprisePolicy));
}
}
if (annotations.isEmpty()) {
// Don't run the original test unparameterized
annotations.add(includeNone());
}
return new ArrayList<>(annotations);
}
/**
* Get parameterized test runs where the policy cannot be set for the given policy.
*/
public static List<Annotation> cannotSetPolicyStates(String policyName,
EnterprisePolicy enterprisePolicy, boolean includeDeviceAdminStates,
boolean includeNonDeviceAdminStates) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
if (includeDeviceAdminStates) {
int allFlags = 0;
for (int p : enterprisePolicy.dpc()) {
allFlags = allFlags | p;
}
for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
DPC_STATE_ANNOTATIONS.entrySet()) {
if ((appliedByFlag.getKey() & allFlags) == 0) {
annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
}
}
}
if (includeNonDeviceAdminStates) {
Set<String> validScopes = ImmutableSet.copyOf(enterprisePolicy.delegatedScopes());
String[] scopes = ALL_DELEGATE_SCOPES.stream()
.filter(i -> !validScopes.contains(i))
.toArray(String[]::new);
Annotation[] existingAnnotations = IncludeRunOnDeviceOwnerUser.class.getAnnotations();
if (BedsteadJUnit4.isDebug()) {
// Add a non-DPC with no delegate scopes
Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
existingAnnotations.length + 1);
newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
EnsureHasDelegate.AdminType.PRIMARY, new String[]{}, /* isPrimary= */ true);
annotations.add(
new DynamicParameterizedAnnotation("DelegateWithNoScopes", newAnnotations));
for (String scope : scopes) {
newAnnotations = Arrays.copyOf(existingAnnotations,
existingAnnotations.length + 1);
newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope}, /* isPrimary= */ true);
annotations.add(
new DynamicParameterizedAnnotation("DelegateWithScope:" + scope, newAnnotations));
}
} else {
Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
existingAnnotations.length + 1);
newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
EnsureHasDelegate.AdminType.PRIMARY, scopes, /* isPrimary= */ true);
annotations.add(
new DynamicParameterizedAnnotation("DelegateWithoutValidScope", newAnnotations));
}
}
if (annotations.isEmpty()) {
// Don't run the original test unparameterized
annotations.add(includeNone());
}
return new ArrayList<>(annotations);
}
/**
* Get state annotations where the policy can be set for the given policy.
*/
public static List<Annotation> canSetPolicyStates(
String policyName, EnterprisePolicy enterprisePolicy, boolean singleTestOnly) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
int allFlags = 0;
for (int p : enterprisePolicy.dpc()) {
allFlags = allFlags | p;
}
for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
DPC_STATE_ANNOTATIONS.entrySet()) {
if ((appliedByFlag.getKey() & allFlags) == appliedByFlag.getKey()) {
annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
}
}
if (annotations.isEmpty()) {
// Don't run the original test unparameterized
annotations.add(includeNone());
}
List<Annotation> annotationList = new ArrayList<>(annotations);
if (singleTestOnly) {
// We select one annotation in an arbitrary but deterministic way
annotationList.sort(Comparator.comparing(
a -> a instanceof DynamicParameterizedAnnotation
? "DynamicParameterizedAnnotation" : a.annotationType().getName()));
// We don't want a delegate to be the representative test
Annotation firstAnnotation = annotationList.stream()
.filter(i -> !(i instanceof DynamicParameterizedAnnotation))
.findFirst().get();
annotationList.clear();
annotationList.add(firstAnnotation);
}
return annotationList;
}
private static void validateFlags(String policyName, int[] values) {
int usedAppliedByFlags = 0;
for (int value : values) {
validateFlags(policyName, value);
int newUsedAppliedByFlags = usedAppliedByFlags | (value & APPLIED_BY_FLAGS);
if (newUsedAppliedByFlags == usedAppliedByFlags) {
throw new IllegalStateException(
"Cannot have more than one policy flag APPLIED by the same component. "
+ "Error in policy " + policyName);
}
usedAppliedByFlags = newUsedAppliedByFlags;
}
}
private static void validateFlags(String policyName, int value) {
int matchingAppliedByFlags = APPLIED_BY_FLAGS & value;
if (matchingAppliedByFlags == 0) {
throw new IllegalStateException(
"All policy flags must specify 1 APPLIED_BY flag. Policy " + policyName
+ " did not.");
}
}
private static boolean hasFlag(int[] values, int matchingFlag) {
return hasFlag(values, matchingFlag, /* nonMatchingFlag= */ NO);
}
private static boolean hasFlag(int[] values, int matchingFlag, int nonMatchingFlag) {
for (int value : values) {
if (hasFlag(value, matchingFlag, nonMatchingFlag)) {
return true;
}
}
return false;
}
private static boolean hasFlag(int value, int matchingFlag, int nonMatchingFlag) {
if (!((value & matchingFlag) == matchingFlag)) {
return false;
}
if (nonMatchingFlag != NO) {
return (value & nonMatchingFlag) != nonMatchingFlag;
}
return true;
}
}