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.cts.statsd.atom;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import android.cts.statsd.validation.ValidationTestUtil;
23 
24 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
25 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
26 import com.android.ddmlib.testrunner.TestResult.TestStatus;
27 import com.android.tradefed.build.IBuildInfo;
28 import com.android.tradefed.device.CollectingByteOutputReceiver;
29 import com.android.tradefed.device.DeviceNotAvailableException;
30 import com.android.tradefed.log.LogUtil.CLog;
31 import com.android.tradefed.result.CollectingTestListener;
32 import com.android.tradefed.result.TestDescription;
33 import com.android.tradefed.result.TestResult;
34 import com.android.tradefed.result.TestRunResult;
35 import com.android.tradefed.testtype.DeviceTestCase;
36 import com.android.tradefed.testtype.IBuildReceiver;
37 
38 import com.google.protobuf.InvalidProtocolBufferException;
39 import com.google.protobuf.MessageLite;
40 import com.google.protobuf.Parser;
41 
42 import java.io.FileNotFoundException;
43 import java.util.Map;
44 
45 import javax.annotation.Nonnull;
46 import javax.annotation.Nullable;
47 
48 // Largely copied from incident's ProtoDumpTestCase
49 public class BaseTestCase extends DeviceTestCase implements IBuildReceiver {
50 
51     protected IBuildInfo mCtsBuild;
52 
53     private static final String TEST_RUNNER = "androidx.test.runner.AndroidJUnitRunner";
54 
55     @Override
setUp()56     protected void setUp() throws Exception {
57         super.setUp();
58         assertThat(mCtsBuild).isNotNull();
59     }
60 
61     @Override
setBuild(IBuildInfo buildInfo)62     public void setBuild(IBuildInfo buildInfo) {
63         mCtsBuild = buildInfo;
64     }
65 
getBuild()66     public IBuildInfo getBuild() {
67         return mCtsBuild;
68     }
69 
70     /**
71      * Create and return {@link ValidationTestUtil} and give it the current build.
72      */
createValidationUtil()73     public ValidationTestUtil createValidationUtil() {
74         ValidationTestUtil util = new ValidationTestUtil();
75         util.setBuild(getBuild());
76         return util;
77     }
78 
79     /**
80      * Call onto the device with an adb shell command and get the results of
81      * that as a proto of the given type.
82      *
83      * @param parser A protobuf parser object. e.g. MyProto.parser()
84      * @param command The adb shell command to run. e.g. "dumpsys fingerprint --proto"
85      *
86      * @throws DeviceNotAvailableException If there was a problem communicating with
87      *      the test device.
88      * @throws InvalidProtocolBufferException If there was an error parsing
89      *      the proto. Note that a 0 length buffer is not necessarily an error.
90      */
getDump(Parser<T> parser, String command)91     public <T extends MessageLite> T getDump(Parser<T> parser, String command)
92             throws DeviceNotAvailableException, InvalidProtocolBufferException {
93         final CollectingByteOutputReceiver receiver = new CollectingByteOutputReceiver();
94         getDevice().executeShellCommand(command, receiver);
95         if (false) {
96             CLog.d("Command output while parsing " + parser.getClass().getCanonicalName()
97                     + " for command: " + command + "\n"
98                     + BufferDebug.debugString(receiver.getOutput(), -1));
99         }
100         try {
101             return parser.parseFrom(receiver.getOutput());
102         } catch (Exception ex) {
103             CLog.d("Error parsing " + parser.getClass().getCanonicalName() + " for command: "
104                     + command
105                     + BufferDebug.debugString(receiver.getOutput(), 16384));
106             throw ex;
107         }
108     }
109 
110     /**
111      * Install a device side test package.
112      *
113      * @param appFileName Apk file name, such as "CtsNetStatsApp.apk".
114      * @param grantPermissions whether to give runtime permissions.
115      */
installPackage(String appFileName, boolean grantPermissions)116     protected void installPackage(String appFileName, boolean grantPermissions)
117             throws FileNotFoundException, DeviceNotAvailableException {
118         CLog.d("Installing app " + appFileName);
119         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
120         final String result = getDevice().installPackage(
121                 buildHelper.getTestFile(appFileName), true, grantPermissions);
122         assertWithMessage(String.format("Failed to install %s: %s", appFileName, result))
123             .that(result).isNull();
124     }
125 
getBuildHelper()126     protected CompatibilityBuildHelper getBuildHelper() {
127         return new CompatibilityBuildHelper(mCtsBuild);
128     }
129 
130     /**
131      * Run a device side test.
132      *
133      * @param pkgName Test package name, such as "com.android.server.cts.netstats".
134      * @param testClassName Test class name; either a fully qualified name, or "." + a class name.
135      * @param testMethodName Test method name.
136      * @return {@link TestRunResult} of this invocation.
137      * @throws DeviceNotAvailableException
138      */
139     @Nonnull
runDeviceTests(@onnull String pkgName, @Nullable String testClassName, @Nullable String testMethodName)140     protected TestRunResult runDeviceTests(@Nonnull String pkgName,
141             @Nullable String testClassName, @Nullable String testMethodName)
142             throws DeviceNotAvailableException {
143         if (testClassName != null && testClassName.startsWith(".")) {
144             testClassName = pkgName + testClassName;
145         }
146 
147         RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
148                 pkgName, TEST_RUNNER, getDevice().getIDevice());
149         if (testClassName != null && testMethodName != null) {
150             testRunner.setMethodName(testClassName, testMethodName);
151         } else if (testClassName != null) {
152             testRunner.setClassName(testClassName);
153         }
154 
155         CollectingTestListener listener = new CollectingTestListener();
156         assertThat(getDevice().runInstrumentationTests(testRunner, listener)).isTrue();
157 
158         final TestRunResult result = listener.getCurrentRunResults();
159         if (result.isRunFailure()) {
160             throw new Error("Failed to successfully run device tests for "
161                     + result.getName() + ": " + result.getRunFailureMessage());
162         }
163         if (result.getNumTests() == 0) {
164             throw new Error("No tests were run on the device");
165         }
166 
167         if (result.hasFailedTests()) {
168             // build a meaningful error message
169             StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
170             for (Map.Entry<TestDescription, TestResult> resultEntry :
171                     result.getTestResults().entrySet()) {
172                 if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
173                     errorBuilder.append(resultEntry.getKey().toString());
174                     errorBuilder.append(":\n");
175                     errorBuilder.append(resultEntry.getValue().getStackTrace());
176                 }
177             }
178             throw new AssertionError(errorBuilder.toString());
179         }
180 
181         return result;
182     }
183 }
184