1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.bedstead.enterprise; 17 18 import com.android.bedstead.enterprise.annotations.CanSetPolicyTest; 19 import com.android.bedstead.enterprise.annotations.CannotSetPolicyTest; 20 import com.android.bedstead.enterprise.annotations.PolicyAppliesTest; 21 import com.android.bedstead.enterprise.annotations.PolicyDoesNotApplyTest; 22 import com.android.bedstead.harrier.BedsteadFrameworkMethod; 23 import com.android.bedstead.harrier.FrameworkMethodWithParameter; 24 import com.android.bedstead.harrier.annotations.PolicyArgument; 25 import com.android.bedstead.nene.exceptions.NeneException; 26 27 import org.junit.runners.model.FrameworkMethod; 28 29 import java.lang.annotation.Annotation; 30 import java.lang.reflect.InvocationTargetException; 31 import java.lang.reflect.Method; 32 import java.util.ArrayList; 33 import java.util.HashSet; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Set; 37 import java.util.stream.Collectors; 38 import java.util.stream.Stream; 39 40 /** 41 * Generate policy argument tests 42 */ 43 public final class PolicyArgumentTestsGenerator { 44 45 /** 46 * Generates extra tests for test functions using 47 * {@link PolicyArgument} annotation in the function parameter 48 */ generate( FrameworkMethod frameworkMethod, Stream<FrameworkMethod> expandedMethods)49 public static Stream<FrameworkMethod> generate( 50 FrameworkMethod frameworkMethod, Stream<FrameworkMethod> expandedMethods) { 51 try { 52 Class<?>[] policyClasses; 53 PolicyAppliesTest policyAppliesTestAnnotation = 54 frameworkMethod.getMethod().getAnnotation(PolicyAppliesTest.class); 55 PolicyDoesNotApplyTest policyDoesNotApplyTestAnnotation = 56 frameworkMethod.getMethod().getAnnotation(PolicyDoesNotApplyTest.class); 57 CanSetPolicyTest canSetPolicyTestAnnotation = 58 frameworkMethod.getMethod().getAnnotation(CanSetPolicyTest.class); 59 CannotSetPolicyTest cannotSetPolicyTestAnnotation = 60 frameworkMethod.getMethod().getAnnotation(CannotSetPolicyTest.class); 61 62 if (policyAppliesTestAnnotation != null) { 63 policyClasses = policyAppliesTestAnnotation.policy(); 64 } else if (policyDoesNotApplyTestAnnotation != null) { 65 policyClasses = policyDoesNotApplyTestAnnotation.policy(); 66 } else if (canSetPolicyTestAnnotation != null) { 67 policyClasses = canSetPolicyTestAnnotation.policy(); 68 } else if (cannotSetPolicyTestAnnotation != null) { 69 policyClasses = cannotSetPolicyTestAnnotation.policy(); 70 } else { 71 throw new NeneException("PolicyArgument annotation can only by used with a test " 72 + "that is marked with either @PolicyAppliesTest, " 73 + "@PolicyDoesNotApplyTest, @CanSetPolicyTest or @CannotSetPolicyTest."); 74 } 75 76 Map<String, Set<Annotation>> policyClassToAnnotationsMap = 77 Policy.getAnnotationsForPolicies( 78 Policy.getEnterprisePolicyWithCallingClass(policyClasses)); 79 80 List<FrameworkMethod> expandedMethodList = expandedMethods.collect(Collectors.toList()); 81 Set<FrameworkMethod> tempExpandedFrameworkMethodSet = new HashSet<>(); 82 for (Class<?> policyClass : policyClasses) { 83 Method validArgumentsMethod = policyClass.getDeclaredMethod("validArguments"); 84 Set<?> validArguments = 85 (Set<?>) validArgumentsMethod.invoke(policyClass.newInstance()); 86 if (validArguments.isEmpty()) { 87 throw new NeneException( 88 "Empty valid arguments passed for " 89 + policyClass.getSimpleName() 90 + " policy"); 91 } 92 93 Set<Annotation> policyAnnotations = 94 policyClassToAnnotationsMap.get(policyClass.getName()); 95 96 for (FrameworkMethod expandedMethod : expandedMethodList) { 97 List<Annotation> parameterizedAnnotations = 98 ((BedsteadFrameworkMethod) expandedMethod) 99 .getParameterizedAnnotations(); 100 for (Annotation parameterizedAnnotation : parameterizedAnnotations) { 101 if ((policyAppliesTestAnnotation != null 102 && policyAnnotations.contains((parameterizedAnnotation))) 103 || (policyDoesNotApplyTestAnnotation != null) 104 || (canSetPolicyTestAnnotation != null 105 && policyAnnotations.contains(parameterizedAnnotation)) 106 || (cannotSetPolicyTestAnnotation != null)) { 107 tempExpandedFrameworkMethodSet.addAll( 108 applyPolicyArgumentParameter(expandedMethod, validArguments)); 109 } 110 } 111 } 112 } 113 114 return tempExpandedFrameworkMethodSet.stream(); 115 } catch (NoSuchMethodException 116 | InvocationTargetException 117 | IllegalAccessException 118 | InstantiationException e) { 119 // Should never happen as validArguments method will always have a default 120 // implementation for every EnterprisePolicy 121 throw new NeneException( 122 "PolicyArgument parameter annotation cannot be added to a test " 123 + "without the validArguments method specified for the " 124 + "EnterprisePolicy", 125 e); 126 } 127 } 128 applyPolicyArgumentParameter( FrameworkMethod frameworkMethod, Set<?> validArguments)129 private static List<FrameworkMethodWithParameter> applyPolicyArgumentParameter( 130 FrameworkMethod frameworkMethod, Set<?> validArguments) { 131 List<FrameworkMethodWithParameter> expandedMethods = new ArrayList<>(validArguments.size()); 132 for (Object arg : validArguments) { 133 expandedMethods.add(new FrameworkMethodWithParameter(frameworkMethod, arg)); 134 } 135 return expandedMethods; 136 } 137 } 138