• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.cts;
18 
19 import static com.google.common.truth.Truth.assertWithMessage;
20 
21 import android.app.UiAutomation;
22 import android.car.Car;
23 import android.car.FuelType;
24 import android.car.PortLocationType;
25 import android.car.test.AbstractExpectableTestCase;
26 import android.car.test.ApiCheckerRule;
27 import android.car.test.PermissionsCheckerRule;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.ServiceConnection;
31 import android.os.IBinder;
32 import android.os.Looper;
33 import android.os.ParcelFileDescriptor;
34 import android.util.Log;
35 
36 import androidx.test.platform.app.InstrumentationRegistry;
37 
38 import org.junit.After;
39 import org.junit.Before;
40 import org.junit.Rule;
41 
42 import java.io.ByteArrayOutputStream;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.concurrent.Semaphore;
48 import java.util.concurrent.TimeUnit;
49 
50 /**
51  * Base class for tests that don't need to connect to a {@link android.car.Car} object.
52  *
53  * <p>For tests that don't need a {@link android.car.Car} object, use
54  * {@link AbstractCarLessTestCase} instead.
55  */
56 abstract class AbstractCarTestCase extends AbstractExpectableTestCase {
57 
58     private static final String TAG = AbstractCarTestCase.class.getSimpleName();
59 
60     protected static final long DEFAULT_WAIT_TIMEOUT_MS = 1000;
61 
62     // Enums in FuelType
63     protected static final List<Integer> EXPECTED_FUEL_TYPES =
64             Arrays.asList(FuelType.UNKNOWN, FuelType.UNLEADED, FuelType.LEADED, FuelType.DIESEL_1,
65                     FuelType.DIESEL_2, FuelType.BIODIESEL, FuelType.E85, FuelType.LPG, FuelType.CNG,
66                     FuelType.LNG, FuelType.ELECTRIC, FuelType.HYDROGEN, FuelType.OTHER);
67     // Enums in PortLocationType
68     protected static final List<Integer> EXPECTED_PORT_LOCATIONS =
69             Arrays.asList(PortLocationType.UNKNOWN, PortLocationType.FRONT_LEFT,
70                     PortLocationType.FRONT_RIGHT, PortLocationType.REAR_RIGHT,
71                     PortLocationType.REAR_LEFT, PortLocationType.FRONT, PortLocationType.REAR);
72 
73     // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
74     // when not needed anymore
75     private final ApiCheckerRule.Builder mApiCheckerRuleBuilder = new ApiCheckerRule.Builder();
76 
77     @Rule
78     public final PermissionsCheckerRule mPermissionsCheckerRule = new PermissionsCheckerRule();
79 
80     @Rule
81     public final ApiCheckerRule mApiCheckerRule;
82 
83     protected final Context mContext = InstrumentationRegistry.getInstrumentation().getContext();
84 
85     private final DefaultServiceConnectionListener mConnectionListener =
86             new DefaultServiceConnectionListener();
87 
88     private Car mCar;
89 
90     // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
91     // when not needed anymore
AbstractCarTestCase()92     protected AbstractCarTestCase() {
93         configApiCheckerRule(mApiCheckerRuleBuilder);
94         mApiCheckerRule = mApiCheckerRuleBuilder.build();
95     }
96 
97     // TODO(b/242350638): temporary hack to allow subclasses to disable checks - should be removed
98     // when not needed anymore
configApiCheckerRule(ApiCheckerRule.Builder builder)99     protected void configApiCheckerRule(ApiCheckerRule.Builder builder) {
100         Log.v(TAG, "Good News, Everyone! Class " + getClass()
101                 + " doesn't override configApiCheckerRule()");
102     }
103 
assertMainThread()104     protected void assertMainThread() {
105         assertWithMessage("Looper.getMainLooper().isCurrentThread()")
106                 .that(Looper.getMainLooper().isCurrentThread()).isTrue();
107     }
108 
109     @Before
createCar()110     public final void createCar() throws Exception {
111         mCar = Car.createCar(mContext);
112     }
113 
114     @After
disconnectCar()115     public final void disconnectCar() throws Exception {
116         if (mCar != null) {
117             mCar.disconnect();
118         }
119     }
120 
startUser(int userId)121     public void startUser(int userId) throws Exception {
122         executeShellCommand("am start-user %d", userId);
123     }
124 
getCar()125     protected synchronized Car getCar() {
126         return mCar;
127     }
128 
129     protected class DefaultServiceConnectionListener implements ServiceConnection {
130         private final Semaphore mConnectionWait = new Semaphore(0);
131 
waitForConnection(long timeoutMs)132         public void waitForConnection(long timeoutMs) throws InterruptedException {
133             mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS);
134         }
135 
136         @Override
onServiceDisconnected(ComponentName name)137         public void onServiceDisconnected(ComponentName name) {
138             assertMainThread();
139         }
140 
141         @Override
onServiceConnected(ComponentName name, IBinder service)142         public void onServiceConnected(ComponentName name, IBinder service) {
143             assertMainThread();
144             mConnectionWait.release();
145         }
146     }
147 
executeShellCommand(String commandFormat, Object... args)148     protected static String executeShellCommand(String commandFormat, Object... args)
149             throws IOException {
150         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
151         return executeShellCommand(uiAutomation, commandFormat, args);
152     }
153 
executeShellCommandWithPermission(String permission, String commandFormat, Object... args)154     protected static String executeShellCommandWithPermission(String permission,
155             String commandFormat, Object... args) throws IOException {
156         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
157         String result;
158         try {
159             uiAutomation.adoptShellPermissionIdentity(permission);
160             result = executeShellCommand(uiAutomation, commandFormat, args);
161         } finally {
162             uiAutomation.dropShellPermissionIdentity();
163         }
164         return result;
165     }
166 
executeShellCommand(UiAutomation uiAutomation, String commandFormat, Object... args)167     private static String executeShellCommand(UiAutomation uiAutomation, String commandFormat,
168             Object... args) throws IOException {
169         ParcelFileDescriptor stdout = uiAutomation.executeShellCommand(
170                 String.format(commandFormat, args));
171         try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) {
172             ByteArrayOutputStream result = new ByteArrayOutputStream();
173             byte[] buffer = new byte[1024];
174             int length;
175             while ((length = inputStream.read(buffer)) != -1) {
176                 result.write(buffer, 0, length);
177             }
178             return result.toString("UTF-8");
179         }
180     }
181 }
182