blob: 1e7e4811fa38ca4de92cca8a8fe5cd6132c4d1a7 [file] [log] [blame]
/*
* Copyright (C) 2016 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.cts.verifier.location.base;
import android.location.cts.GnssTestCase;
import android.location.cts.MultiConstellationNotSupportedException;
import android.view.WindowManager;
import com.android.cts.verifier.R;
import com.android.cts.verifier.location.reporting.GnssTestDetails;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.junit.internal.runners.JUnit38ClassRunner;
import org.junit.internal.runners.SuiteMethod;
import org.junit.runner.Computer;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runners.model.RunnerBuilder;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* An Activity that allows Gnss CTS tests to be executed inside CtsVerifier.
*
* Sub-classes pass the test class as part of construction.
* One JUnit test class is executed per Activity, the test class can still be executed outside
* CtsVerifier.
*/
public class GnssCtsTestActivity extends BaseGnssTestActivity {
/**
* Constructor for a CTS test executor. It will execute a standalone CTS test class.
*
* @param testClass The test class to execute, it must be a subclass of {@link AndroidTestCase}.
*/
protected GnssCtsTestActivity(Class<? extends GnssTestCase> testClass) {
super(testClass);
}
@Override
protected void activitySetUp() throws InterruptedException {
waitForUserToBegin();
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.setText("");
}
});
}
@Override
protected void activityCleanUp() {
runOnUiThread(new Runnable() {
@Override
public void run() {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
}
/**
* For reference on the implementation of this test executor see:
* android.support.test.runner.AndroidJUnitRunner
*/
@Override
protected GnssTestDetails executeTests() {
JUnitCore testRunner = new JUnitCore();
testRunner.addListener(new GnssRunListener());
Computer computer = new Computer();
RunnerBuilder runnerBuilder = new GnssRunnerBuilder();
Runner runner;
try {
runner = computer.getSuite(runnerBuilder, new Class[]{ mTestClass });
} catch (Exception e) {
return new GnssTestDetails(
getTestClassName(),
GnssTestDetails.ResultCode.FAIL,
"[JUnit Initialization]" + e.getMessage());
}
Request request = Request.runner(runner);
Result result = testRunner.run(request);
// Handle MultiConstellationNotSupportedException warning: If there is a
// "MultiConstellationNotSupportedException" then it will just print the warning and
// mark test as pass.
int failureCount = result.getFailureCount();
List<Failure> failures = result.getFailures();
for (Failure f: failures) {
// TODO: Refactor this to use a more general exception instead of
// MultiConstellationNotSupportedException.
if (f.getException() instanceof MultiConstellationNotSupportedException) {
failureCount = failureCount - 1;
int passCount = result.getRunCount() - failureCount - result.getIgnoreCount();
return new GnssTestDetails(
getApplicationContext(), getClass().getName(), passCount,
result.getIgnoreCount(), failureCount);
}
}
return new GnssTestDetails(getApplicationContext(), getClass().getName(), result);
}
/**
* A {@link RunnerBuilder} that is used to inject during execution a {@link GnssCtsTestSuite}.
*/
private class GnssRunnerBuilder extends RunnerBuilder {
@Override
public Runner runnerForClass(Class<?> testClass) throws Throwable {
TestSuite testSuite;
if (hasSuiteMethod(testClass)) {
Test test = SuiteMethod.testFromSuiteMethod(testClass);
if (test instanceof TestSuite) {
testSuite = (TestSuite) test;
} else {
throw new IllegalArgumentException(
testClass.getName() + "#suite() did not return a TestSuite.");
}
} else {
testSuite = new TestSuite(testClass);
}
GnssCtsTestSuite gnssTestSuite =
new GnssCtsTestSuite(getApplicationContext(), testSuite);
return new JUnit38ClassRunner(gnssTestSuite);
}
private boolean hasSuiteMethod(Class<?> testClass) {
try {
testClass.getMethod("suite");
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
}
/**
* Dummy {@link RunListener}.
* It is only used to handle logging into the UI.
*/
private class GnssRunListener extends RunListener {
private volatile boolean mCurrentTestReported;
private StringBuilder mTestsResults = new StringBuilder("Test summary:\n");
private int mPassTestCase = 0;
private int mFailTestCase = 0;
public void testRunStarted(Description description) throws Exception {
// nothing to log
}
public void testRunFinished(Result result) throws Exception {
// nothing to log
runOnUiThread(new Runnable() {
@Override
public void run() {
int totalTestCase = mPassTestCase + mFailTestCase;
mTestsResults.append(String.format("\n\n %d/%d verification passed.",
mPassTestCase, totalTestCase));
if (mFailTestCase == 0) {
mTestsResults.append(" All test pass!");
} else {
mTestsResults.append("\n\n" + mTextView.getResources().getString(
R.string.location_gnss_test_retry_info) + "\n");
}
mTextView.setText(mTestsResults);
}
});
vibrate((int)TimeUnit.SECONDS.toMillis(2));
playSound();
}
public void testStarted(Description description) throws Exception {
mCurrentTestReported = false;
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.append("\n Running test: " + description.getMethodName());
}
});
}
public void testFinished(Description description) throws Exception {
if (!mCurrentTestReported) {
mPassTestCase++;
appendTestDetail("\n Test passed: " + description.getMethodName());
mTestsResults.append("\n Test passed: " + description.getMethodName());
}
}
public void testFailure(Failure failure) throws Exception {
mCurrentTestReported = true;
if (failure.getException() instanceof MultiConstellationNotSupportedException) {
// append warning for MultiConstellationNotSupportedException's.
mTestsResults.append(failure.getException());
} else {
mFailTestCase++;
mTestsResults.append("\n Test failed: "
+ failure.getDescription().getMethodName()
+ "\n\n Error: " + failure.toString() + "\n");
}
}
public void testAssumptionFailure(Failure failure) {
mCurrentTestReported = true;
}
public void testIgnored(Description description) throws Exception {
mCurrentTestReported = true;
}
private void appendTestDetail(final String testDetail) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextView.append(testDetail);
}
});
}
}
}