1 /* 2 * Copyright (C) 2022 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 17 package android.car.test; 18 19 import static android.car.test.JUnitHelper.newTestMethod; 20 21 import static com.google.common.truth.Truth.assertWithMessage; 22 23 import static org.junit.Assert.assertThrows; 24 import static org.mockito.Mockito.any; 25 import static org.mockito.Mockito.never; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.app.UiAutomation; 30 import android.car.test.JUnitHelper.SimpleStatement; 31 import android.car.test.PermissionsCheckerRule.EnsureHasPermission; 32 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.Description; 36 import org.junit.runner.RunWith; 37 import org.mockito.ArgumentCaptor; 38 import org.mockito.Mock; 39 import org.mockito.junit.MockitoJUnitRunner; 40 41 import java.lang.annotation.Annotation; 42 import java.util.Arrays; 43 import java.util.Set; 44 45 @RunWith(MockitoJUnitRunner.class) 46 public final class PermissionsCheckerRuleTest { 47 48 private static final String TAG = PermissionsCheckerRuleTest.class.getSimpleName(); 49 50 @Mock 51 private UiAutomation mUiAutomation; 52 53 private final SimpleStatement<Exception> mBaseStatement = new SimpleStatement<>(); 54 55 private PermissionsCheckerRule mRule; 56 57 @Before setFixtures()58 public void setFixtures() { 59 mRule = new PermissionsCheckerRule(mUiAutomation); 60 } 61 62 @Test testNoAnnotation()63 public void testNoAnnotation() throws Throwable { 64 Description testMethod = newTestMethod(); 65 66 mRule.apply(mBaseStatement, testMethod).evaluate(); 67 68 mBaseStatement.assertEvaluated(); 69 verify(mUiAutomation, never()).adoptShellPermissionIdentity(any(String[].class)); 70 verify(mUiAutomation, never()).dropShellPermissionIdentity(); 71 } 72 73 @Test testEnsureHasPermission_onePermission()74 public void testEnsureHasPermission_onePermission() throws Throwable { 75 Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To Kill")); 76 77 mRule.apply(mBaseStatement, testMethod).evaluate(); 78 79 mBaseStatement.assertEvaluated(); 80 verify(mUiAutomation).adoptShellPermissionIdentity("To Kill"); 81 verify(mUiAutomation).dropShellPermissionIdentity(); 82 } 83 84 @Test testEnsureHasPermission_onePermissionTestThrows()85 public void testEnsureHasPermission_onePermissionTestThrows() throws Throwable { 86 Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To Kill")); 87 Throwable exception = new Throwable("D'OH!"); 88 mBaseStatement.failWith(exception); 89 90 Throwable actualException = assertThrows(Throwable.class, 91 () -> mRule.apply(mBaseStatement, testMethod).evaluate()); 92 93 assertWithMessage("exception thrown").that(actualException).isSameInstanceAs(exception); 94 verify(mUiAutomation).adoptShellPermissionIdentity("To Kill"); 95 verify(mUiAutomation).dropShellPermissionIdentity(); 96 } 97 98 @Test testEnsureHasPermission_multiplePermissions()99 public void testEnsureHasPermission_multiplePermissions() throws Throwable { 100 Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To", "Kill")); 101 102 mRule.apply(mBaseStatement, testMethod).evaluate(); 103 104 mBaseStatement.assertEvaluated(); 105 verify(mUiAutomation).adoptShellPermissionIdentity("To", "Kill"); 106 verify(mUiAutomation).dropShellPermissionIdentity(); 107 } 108 109 @Test testEnsureHasPermission_permissionsAdoptedBefore()110 public void testEnsureHasPermission_permissionsAdoptedBefore() throws Throwable { 111 Description testMethod = newTestMethod(new EnsureHasPermissionAnnotation("To Kill")); 112 when(mUiAutomation.getAdoptedShellPermissions()).thenReturn(Set.of("Thou shalt not kill!")); 113 114 mRule.apply(mBaseStatement, testMethod).evaluate(); 115 116 mBaseStatement.assertEvaluated(); 117 verify(mUiAutomation).adoptShellPermissionIdentity("To Kill"); 118 verify(mUiAutomation).dropShellPermissionIdentity(); 119 verify(mUiAutomation).adoptShellPermissionIdentity("Thou shalt not kill!"); 120 } 121 122 @Test testEnsureHasPermission_annotatedClass()123 public void testEnsureHasPermission_annotatedClass() throws Throwable { 124 Description testMethod = Description.createTestDescription(SuperClass.class, "testIAm", 125 new EnsureHasPermissionAnnotation("To", "Kill")); 126 127 mRule.apply(mBaseStatement, testMethod).evaluate(); 128 129 mBaseStatement.assertEvaluated(); 130 131 // Must use a captor as there's no guarantee of the order in the set 132 ArgumentCaptor<String[]> permissionsCaptor = ArgumentCaptor.forClass(String[].class); 133 verify(mUiAutomation).adoptShellPermissionIdentity(permissionsCaptor.capture()); 134 assertWithMessage("arguments of adoptShellPermissionIdentity() call") 135 .that(permissionsCaptor.getAllValues()) 136 .containsExactly("SuPermission", "Common", "To", "Kill"); 137 verify(mUiAutomation).dropShellPermissionIdentity(); 138 } 139 140 @Test testEnsureHasPermission_annotatedClassAndParent()141 public void testEnsureHasPermission_annotatedClassAndParent() throws Throwable { 142 Description testMethod = Description.createTestDescription(SubClass.class, "testIAm", 143 new EnsureHasPermissionAnnotation("To", "Kill")); 144 145 mRule.apply(mBaseStatement, testMethod).evaluate(); 146 147 148 // Must use a captor as there's no guarantee of the order in the set 149 ArgumentCaptor<String[]> permissionsCaptor = ArgumentCaptor.forClass(String[].class); 150 verify(mUiAutomation).adoptShellPermissionIdentity(permissionsCaptor.capture()); 151 assertWithMessage("arguments of adoptShellPermissionIdentity() call") 152 .that(permissionsCaptor.getAllValues()) 153 .containsExactly("SuPermission", "Common", "WhatSub", "To", "Kill"); 154 verify(mUiAutomation).dropShellPermissionIdentity(); 155 } 156 157 @EnsureHasPermission(value = {"SuPermission", "Common"}) 158 private static class SuperClass { 159 160 } 161 162 @EnsureHasPermission(value = {"Common", "WhatSub"}) 163 private static class SubClass extends SuperClass { 164 165 } 166 167 @SuppressWarnings("BadAnnotationImplementation") // We don't care about equals() / hashCode() 168 private static final class EnsureHasPermissionAnnotation implements EnsureHasPermission { 169 170 private final String[] mValue; 171 EnsureHasPermissionAnnotation(String... value)172 EnsureHasPermissionAnnotation(String... value) { 173 mValue = value; 174 } 175 176 @Override annotationType()177 public Class<? extends Annotation> annotationType() { 178 return EnsureHasPermission.class; 179 } 180 181 @Override value()182 public String[] value() { 183 return mValue; 184 } 185 186 @Override toString()187 public String toString() { 188 return "@EnsureHasPermissionAnnotation(" + Arrays.toString(mValue) + ")"; 189 } 190 } 191 } 192