am d9d0ba5c: am 0ec02670: Merge "Save all sensor events when a verification fails. b/17838681" into lmp-mr1-dev
* commit 'd9d0ba5cde8104dfc4e4164121f253409a14d15e':
Save all sensor events when a verification fails. b/17838681
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
index 4a0c135..52b3dee 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/AccelerometerMeasurementTestActivity.java
@@ -101,7 +101,7 @@
verifyMeasurements.addVerification(new MeanVerification(
expectations,
new float[]{1.95f, 1.95f, 1.95f} /* m / s^2 */));
- verifyMeasurements.execute();
+ verifyMeasurements.execute(getCurrentTestNode());
return null;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
index 2d58c64..7ef63d7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/BatchingTestActivity.java
@@ -150,8 +150,7 @@
private String executeTest(TestSensorOperation operation) throws InterruptedException {
operation.addDefaultVerifications();
- operation.setLogEvents(true);
- operation.execute();
+ operation.execute(getCurrentTestNode());
return null;
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
index d6ec951..7be0fb1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/GyroscopeMeasurementTestActivity.java
@@ -167,7 +167,7 @@
sensorOperation.addVerification(integrationVerification);
try {
- sensorOperation.execute();
+ sensorOperation.execute(getCurrentTestNode());
} finally {
playSound();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
index 22ff1e5..229a9dc 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -87,7 +87,7 @@
verifyNorm.addVerification(new MagnitudeVerification(
expectedMagneticFieldEarth,
magneticFieldEarthThreshold));
- verifyNorm.execute();
+ verifyNorm.execute(getCurrentTestNode());
return null;
}
@@ -127,7 +127,7 @@
verifyStdDev.addVerification(new StandardDeviationVerification(
new float[]{2f, 2f, 2f} /* uT */));
- verifyStdDev.execute();
+ verifyStdDev.execute(getCurrentTestNode());
return null;
}
@@ -169,6 +169,7 @@
getApplicationContext(),
Sensor.TYPE_MAGNETIC_FIELD,
SensorManager.SENSOR_DELAY_NORMAL);
+
TestSensorEventListener listener = new TestSensorEventListener(environment) {
@Override
public void onSensorChanged(SensorEvent event) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
index 5bbaaf7..380b282 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsTestResult.java
@@ -26,6 +26,8 @@
import android.content.Context;
import android.hardware.cts.SensorTestCase;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import java.util.Enumeration;
@@ -138,10 +140,24 @@
SensorTestCase sensorTestCase = (SensorTestCase) testCase;
sensorTestCase.setContext(mContext);
sensorTestCase.setEmulateSensorUnderLoad(false);
+ sensorTestCase.setCurrentTestNode(new TestNode(testCase));
// TODO: set delayed assertion provider
} else {
throw new IllegalStateException("TestCase must be an instance of SensorTestCase.");
}
super.run(testCase);
}
+
+ private class TestNode implements ISensorTestNode {
+ private final TestCase mTestCase;
+
+ public TestNode(TestCase testCase) {
+ mTestCase = testCase;
+ }
+
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return mTestCase.getClass().getSimpleName() + "_" + mTestCase.getName();
+ }
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
index a88abd0..8cf287a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/base/SensorCtsVerifierTestActivity.java
@@ -19,6 +19,8 @@
import com.android.cts.verifier.sensors.reporting.SensorTestDetails;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
+
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -35,6 +37,7 @@
private volatile int mTestPassedCounter;
private volatile int mTestSkippedCounter;
private volatile int mTestFailedCounter;
+ private volatile ISensorTestNode mCurrentTestNode;
/**
* {@inheritDoc}
@@ -63,8 +66,12 @@
mTestFailedCounter);
}
+ protected ISensorTestNode getCurrentTestNode() {
+ return mCurrentTestNode;
+ }
+
private List<Method> findTestMethods() {
- ArrayList<Method> testMethods = new ArrayList<Method>();
+ ArrayList<Method> testMethods = new ArrayList<>();
for (Method method : mTestClass.getDeclaredMethods()) {
if (Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
@@ -79,6 +86,7 @@
private SensorTestDetails executeTest(Method testMethod) throws InterruptedException {
String testMethodName = testMethod.getName();
String testName = String.format("%s#%s", getTestClassName(), testMethodName);
+ mCurrentTestNode = new TestNode(testMethod);
SensorTestDetails testDetails;
try {
@@ -112,4 +120,17 @@
return testDetails;
}
+
+ private class TestNode implements ISensorTestNode {
+ private final Method mTestMethod;
+
+ public TestNode(Method testMethod) {
+ mTestMethod = testMethod;
+ }
+
+ @Override
+ public String getName() {
+ return mTestClass.getSimpleName() + "_" + mTestMethod.getName();
+ }
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
index e2b7561..7640cd7 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
@@ -288,10 +288,9 @@
TestSensorOperation operation,
boolean flushExpected) throws Throwable {
operation.addDefaultVerifications();
- operation.setLogEvents(true);
try {
- operation.execute();
+ operation.execute(getCurrentTestNode());
} finally {
SensorStats stats = operation.getStats();
stats.log(TAG);
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
index 1f070c4..8c3fb7a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorIntegrationTests.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.sensoroperations.ParallelSensorOperation;
import android.hardware.cts.helpers.sensoroperations.RepeatingSensorOperation;
@@ -96,7 +95,7 @@
batchingOperation.addVerification(new EventOrderingVerification());
operation.add(new RepeatingSensorOperation(batchingOperation, ITERATIONS));
}
- operation.execute();
+ operation.execute(getCurrentTestNode());
operation.getStats().log(TAG);
}
@@ -152,7 +151,7 @@
}
}
- operation.execute();
+ operation.execute(getCurrentTestNode());
operation.getStats().log(TAG);
}
@@ -242,11 +241,11 @@
ParallelSensorOperation operation = new ParallelSensorOperation();
operation.add(tester, testee);
- operation.execute();
+ operation.execute(getCurrentTestNode());
operation.getStats().log(TAG);
testee = testee.clone();
- testee.execute();
+ testee.execute(getCurrentTestNode());
testee.getStats().log(TAG);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index 87c74ee..c16c135 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -364,7 +364,7 @@
}
Log.i(TAG, "Testing batch/flush for sensors: " + builder);
- parallelSensorOperation.execute();
+ parallelSensorOperation.execute(getCurrentTestNode());
}
private void assertSensorValues(Sensor sensor) {
@@ -436,7 +436,7 @@
EventTimestampSynchronizationVerification.getDefault(environment));
Log.i(TAG, "Running timestamp test on: " + sensor.getName());
- operation.execute();
+ operation.execute(getCurrentTestNode());
} catch (InterruptedException e) {
// propagate so the test can stop
throw e;
@@ -471,7 +471,7 @@
TestSensorOperation operation = new TestSensorOperation(environment, executor, handler);
Log.i(TAG, "Running flush test on: " + sensor.getName());
- operation.execute();
+ operation.execute(getCurrentTestNode());
} catch (InterruptedException e) {
// propagate so the test can stop
throw e;
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java b/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
index 8dba5d6..42b8d33 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
@@ -16,16 +16,10 @@
package android.hardware.cts;
-import com.android.cts.util.ReportLog;
-import com.android.cts.util.ResultType;
-import com.android.cts.util.ResultUnit;
-
-import android.app.Instrumentation;
-import android.cts.util.DeviceReportLog;
import android.hardware.Sensor;
-import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.hardware.cts.helpers.sensoroperations.SensorOperation;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -48,6 +42,11 @@
*/
private volatile boolean mEmulateSensorUnderLoad = true;
+ /**
+ * By default the test class is the root of the test hierarchy.
+ */
+ private volatile ISensorTestNode mCurrentTestNode = new TestClassNode(getClass());
+
protected SensorTestCase() {}
@Override
@@ -68,33 +67,24 @@
return mEmulateSensorUnderLoad;
}
- /**
- * Utility method to log selected stats to a {@link ReportLog} object. The stats must be
- * a number or an array of numbers.
- */
- public static void logSelectedStatsToReportLog(Instrumentation instrumentation, int depth,
- String[] keys, SensorStats stats) {
- DeviceReportLog reportLog = new DeviceReportLog(depth);
+ public void setCurrentTestNode(ISensorTestNode value) {
+ mCurrentTestNode = value;
+ }
- for (String key : keys) {
- Object value = stats.getValue(key);
- if (value instanceof Integer) {
- reportLog.printValue(key, (Integer) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof Double) {
- reportLog.printValue(key, (Double) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof Float) {
- reportLog.printValue(key, (Float) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof double[]) {
- reportLog.printArray(key, (double[]) value, ResultType.NEUTRAL, ResultUnit.NONE);
- } else if (value instanceof float[]) {
- float[] tmpFloat = (float[]) value;
- double[] tmpDouble = new double[tmpFloat.length];
- for (int i = 0; i < tmpDouble.length; i++) tmpDouble[i] = tmpFloat[i];
- reportLog.printArray(key, tmpDouble, ResultType.NEUTRAL, ResultUnit.NONE);
- }
+ protected ISensorTestNode getCurrentTestNode() {
+ return mCurrentTestNode;
+ }
+
+ private class TestClassNode implements ISensorTestNode {
+ private final Class<?> mTestClass;
+
+ public TestClassNode(Class<?> testClass) {
+ mTestClass = testClass;
}
- reportLog.printSummary("summary", 0, ResultType.NEUTRAL, ResultUnit.NONE);
- reportLog.deliverReportToHost(instrumentation);
+ @Override
+ public String getName() {
+ return mTestClass.getSimpleName();
+ }
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java b/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
index 23feef8..42cbdfb 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SingleSensorTests.java
@@ -544,9 +544,9 @@
TestSensorOperation op =
TestSensorOperation.createOperation(environment, 5, TimeUnit.SECONDS);
op.addDefaultVerifications();
- op.setLogEvents(true);
+
try {
- op.execute();
+ op.execute(getCurrentTestNode());
} finally {
SensorStats stats = op.getStats();
stats.log(TAG);
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
index e8500f1..86b2436 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEvent.java
@@ -21,6 +21,8 @@
import android.hardware.SensorEventListener2;
import android.os.SystemClock;
+import java.util.Arrays;
+
/**
* Class for holding information about individual {@link SensorEvent}s.
*/
@@ -75,4 +77,14 @@
this.accuracy = accuracy;
this.values = values;
}
+
+ @Override
+ public String toString() {
+ return String.format(
+ "Timestamp=%sns, ReceivedTimestamp=%sns, Accuracy=%s, Values=%s",
+ this.timestamp,
+ this.receivedTimestamp,
+ this.accuracy,
+ Arrays.toString(this.values));
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 6c313d2..a60428f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -25,7 +25,12 @@
import android.os.Looper;
import android.os.SystemClock;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -40,6 +45,7 @@
*/
public class TestSensorEventListener implements SensorEventListener2 {
public static final String LOG_TAG = "TestSensorEventListener";
+
private static final long EVENT_TIMEOUT_US = TimeUnit.SECONDS.toMicros(5);
private static final long FLUSH_TIMEOUT_US = TimeUnit.SECONDS.toMicros(10);
@@ -84,7 +90,6 @@
synchronized (mCollectedEvents) {
mCollectedEvents.add(new TestSensorEvent(event, timestampNs));
}
-
synchronized (mEventLatches) {
for (CountDownLatch latch : mEventLatches) {
latch.countDown();
@@ -138,6 +143,40 @@
}
}
+
+ /**
+ * Utility method to log the collected events to a file.
+ * It will overwrite the file if it already exists, the file is created in a relative directory
+ * named 'events' under the sensor test directory (part of external storage).
+ */
+ public void logCollectedEventsToFile(String fileName) throws IOException {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Sensor='").append(mEnvironment.getSensor()).append("', ");
+ builder.append("SamplingRateOverloaded=")
+ .append(mEnvironment.isSensorSamplingRateOverloaded()).append(", ");
+ builder.append("RequestedSamplingPeriod=")
+ .append(mEnvironment.getRequestedSamplingPeriodUs()).append("us, ");
+ builder.append("MaxReportLatency=")
+ .append(mEnvironment.getMaxReportLatencyUs()).append("us");
+
+ synchronized (mCollectedEvents) {
+ for (TestSensorEvent event : mCollectedEvents) {
+ builder.append("\n");
+ builder.append("Timestamp=").append(event.timestamp).append("ns, ");
+ builder.append("ReceivedTimestamp=").append(event.receivedTimestamp).append("ns, ");
+ builder.append("Accuracy=").append(event.accuracy).append(", ");
+ builder.append("Values=").append(Arrays.toString(event.values));
+ }
+ }
+
+ File eventsDirectory = SensorCtsHelper.getSensorTestDataDirectory("events/");
+ File logFile = new File(eventsDirectory, fileName);
+ FileWriter fileWriter = new FileWriter(logFile, false /* append */);
+ try (BufferedWriter writer = new BufferedWriter(fileWriter)) {
+ writer.write(builder.toString());
+ }
+ }
+
/**
* Wait for {@link #onFlushCompleted(Sensor)} to be called.
*
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java b/tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java
new file mode 100644
index 0000000..d34c0af
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/reporting/ISensorTestNode.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 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 android.hardware.cts.helpers.reporting;
+
+import android.hardware.cts.helpers.SensorTestPlatformException;
+
+/**
+ * Interface that represents a node in a hierarchy built by the sensor test platform.
+ */
+// TODO: this is an intermediate state to introduce a full-blown centralized recorder data produced
+// by sensor tests
+public interface ISensorTestNode {
+
+ /**
+ * Provides a name (tag) that can be used to identify the current node.
+ */
+ String getName() throws SensorTestPlatformException;
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
index 8848337..436a7cf 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
@@ -22,7 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
@@ -76,7 +76,7 @@
* {@inheritDoc}
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
// Start alarm
IntentFilter intentFilter = new IntentFilter(ACTION);
BroadcastReceiver receiver = new BroadcastReceiver() {
@@ -96,7 +96,7 @@
// Execute operation
try {
- mOperation.execute();
+ mOperation.execute(asTestNode(parent));
} finally {
releaseWakeLock();
}
@@ -106,14 +106,6 @@
* {@inheritDoc}
*/
@Override
- public SensorStats getStats() {
- return mOperation.getStats();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public AlarmOperation clone() {
return new AlarmOperation(mOperation, mContext, mSleepDuration, mTimeUnit);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
index 3ee08f6..8c52222 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
@@ -17,7 +17,7 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorCtsHelper;
-import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import java.util.concurrent.TimeUnit;
@@ -38,9 +38,7 @@
* @param timeUnit the unit of the delay
*/
public DelaySensorOperation(SensorOperation operation, long delay, TimeUnit timeUnit) {
- if (operation == null || timeUnit == null) {
- throw new IllegalArgumentException("Arguments cannot be null");
- }
+ super(operation.getStats());
mOperation = operation;
mDelay = delay;
mTimeUnit = timeUnit;
@@ -50,17 +48,9 @@
* {@inheritDoc}
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
SensorCtsHelper.sleep(mDelay, mTimeUnit);
- mOperation.execute();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public SensorStats getStats() {
- return mOperation.getStats();
+ mOperation.execute(asTestNode(parent));
}
/**
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
index 8cfd351..238956b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
@@ -16,9 +16,10 @@
package android.hardware.cts.helpers.sensoroperations;
-import junit.framework.Assert;
-
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
+
+import junit.framework.Assert;
import java.util.concurrent.TimeUnit;
@@ -56,7 +57,7 @@
* {@inheritDoc}
*/
@Override
- public void execute() {
+ public void execute(ISensorTestNode parent) {
long delayNs = TimeUnit.NANOSECONDS.convert(mDelay, mTimeUnit);
try {
Thread.sleep(delayNs / NANOS_PER_MILLI, (int) (delayNs % NANOS_PER_MILLI));
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
index e55c6cb..ed70b70 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
@@ -19,6 +19,7 @@
import junit.framework.Assert;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.os.SystemClock;
import java.util.ArrayList;
@@ -80,7 +81,7 @@
* operations, the first exception will be thrown once all operations are completed.
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(final ISensorTestNode parent) throws InterruptedException {
int operationsCount = mOperations.size();
ThreadPoolExecutor executor = new ThreadPoolExecutor(
operationsCount,
@@ -91,12 +92,13 @@
executor.allowCoreThreadTimeOut(true);
executor.prestartAllCoreThreads();
+ final ISensorTestNode currentNode = asTestNode(parent);
ArrayList<Future<SensorOperation>> futures = new ArrayList<>();
for (final SensorOperation operation : mOperations) {
Future<SensorOperation> future = executor.submit(new Callable<SensorOperation>() {
@Override
public SensorOperation call() throws Exception {
- operation.execute();
+ operation.execute(currentNode);
return operation;
}
});
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
index 2e3af36..5b333b8 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
@@ -17,6 +17,8 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
/**
* A {@link SensorOperation} that executes a single {@link SensorOperation} a given number of
@@ -40,7 +42,6 @@
}
mOperation = operation;
mIterations = iterations;
-
}
/**
@@ -48,11 +49,12 @@
* one iterations, it is thrown and all subsequent iterations will not run.
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
+ ISensorTestNode currentNode = asTestNode(parent);
for(int i = 0; i < mIterations; ++i) {
SensorOperation operation = mOperation.clone();
try {
- operation.execute();
+ operation.execute(new TestNode(currentNode, i));
} catch (AssertionError e) {
String msg = String.format("Iteration %d failed: \"%s\"", i, e.getMessage());
getStats().addValue(SensorStats.ERROR, msg);
@@ -70,4 +72,19 @@
public RepeatingSensorOperation clone() {
return new RepeatingSensorOperation(mOperation.clone(), mIterations);
}
+
+ private class TestNode implements ISensorTestNode {
+ private final ISensorTestNode mTestNode;
+ private final int mIteration;
+
+ public TestNode(ISensorTestNode parent, int iteration) {
+ mTestNode = asTestNode(parent);
+ mIteration = iteration;
+ }
+
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return String.format("%s-iteration%d", mTestNode.getName(), mIteration);
+ }
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
index ea16716..66604d3 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
@@ -17,6 +17,8 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
/**
* Base class used by all sensor operations. This allows for complex operations such as chaining
@@ -24,11 +26,12 @@
* <p>
* Certain restrictions exist for {@link SensorOperation}s:
* <p><ul>
- * <li>{@link #execute()} should only be called once and behavior is undefined for subsequent calls.
- * Once {@link #execute()} is called, the class should not be modified. Generally, there is no
- * synchronization for operations.</li>
- * <li>{@link #getStats()} should only be called after {@link #execute()}. If it is called before,
- * the returned value is undefined.</li>
+ * <li>{@link #execute(ISensorTestNode)} should only be called once and behavior is undefined for
+ * subsequent calls.
+ * Once {@link #execute(ISensorTestNode)} is called, the class should not be modified. Generally,
+ * there is no synchronization for operations.</li>
+ * <li>{@link #getStats()} should only be called after {@link #execute(ISensorTestNode)}. If it
+ * is called before, the returned value is undefined.</li>
* <li>{@link #clone()} may be called any time and should return an operation with the same
* parameters as the original.</li>
* </ul>
@@ -59,7 +62,7 @@
* - cleaning up on {@link InterruptedException}
* - propagating the exception down the stack
*/
- public abstract void execute() throws InterruptedException;
+ public abstract void execute(ISensorTestNode parent) throws InterruptedException;
/**
* @return The cloned {@link SensorOperation}.
@@ -85,4 +88,23 @@
protected void addSensorStats(String key, int index, SensorStats stats) {
addSensorStats(String.format("%s_%03d", key, index), stats);
}
+
+ protected ISensorTestNode asTestNode(ISensorTestNode parent) {
+ return new SensorTestNode(parent, this);
+ }
+
+ private class SensorTestNode implements ISensorTestNode {
+ private final ISensorTestNode mParent;
+ private final SensorOperation mOperation;
+
+ public SensorTestNode(ISensorTestNode parent, SensorOperation operation) {
+ mParent = parent;
+ mOperation = operation;
+ }
+
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return mParent.getName() + "-" + mOperation.getClass().getSimpleName();
+ }
+ }
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
index 033f3c5..30da9a0 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
@@ -19,6 +19,8 @@
import junit.framework.TestCase;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@@ -31,6 +33,13 @@
public class SensorOperationTest extends TestCase {
private static final long TEST_DURATION_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(5);
+ private final ISensorTestNode mTestNode = new ISensorTestNode() {
+ @Override
+ public String getName() throws SensorTestPlatformException {
+ return "SensorOperationUnitTest";
+ }
+ };
+
/**
* Test that the {@link FakeSensorOperation} functions correctly. Other tests in this class
* rely on this operation.
@@ -42,14 +51,14 @@
assertFalse(op.getStats().flatten().containsKey("executed"));
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long duration = System.currentTimeMillis() - start;
assertTrue(Math.abs(opDurationMs - duration) < TEST_DURATION_THRESHOLD_MS);
assertTrue(op.getStats().flatten().containsKey("executed"));
op = new FakeSensorOperation(true, 0, TimeUnit.MILLISECONDS);
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -68,7 +77,7 @@
SensorOperation op = new DelaySensorOperation(subOp, opDurationMs, TimeUnit.MILLISECONDS);
long startMs = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long durationMs = System.currentTimeMillis() - startMs;
long durationDeltaMs = Math.abs(opDurationMs + subOpDurationMs - durationMs);
assertTrue(durationDeltaMs < TEST_DURATION_THRESHOLD_MS);
@@ -92,7 +101,7 @@
assertEquals(0, statsKeys.size());
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long durationMs = System.currentTimeMillis() - start;
long durationDeltaMs = Math.abs(subOpDurationMs - durationMs);
String message = String.format(
@@ -132,7 +141,7 @@
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -172,7 +181,7 @@
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -203,7 +212,7 @@
assertEquals(0, statsKeys.size());
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long duration = System.currentTimeMillis() - start;
assertTrue(Math.abs(subOpDurationMs * iterations - duration) < TEST_DURATION_THRESHOLD_MS);
@@ -228,8 +237,8 @@
private SensorStats mFakeStats = new SensorStats();
@Override
- public void execute() {
- super.execute();
+ public void execute(ISensorTestNode parent) {
+ super.execute(parent);
mExecutedCount++;
if (failCount == mExecutedCount) {
@@ -255,7 +264,7 @@
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
@@ -292,7 +301,7 @@
assertEquals(0, statsKeys.size());
long start = System.currentTimeMillis();
- op.execute();
+ op.execute(mTestNode);
long duration = System.currentTimeMillis() - start;
assertTrue(Math.abs(subOpDurationMs * subOpCount - duration) < TEST_DURATION_THRESHOLD_MS);
@@ -324,7 +333,7 @@
assertEquals(0, statsKeys.size());
try {
- op.execute();
+ op.execute(mTestNode);
fail("AssertionError expected");
} catch (AssertionError e) {
// Expected
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
index 85d189a..847c0f2 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
@@ -17,6 +17,7 @@
package android.hardware.cts.helpers.sensoroperations;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import java.util.ArrayList;
@@ -47,11 +48,12 @@
* in one operation, it is thrown and all subsequent operations will not run.
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
+ ISensorTestNode currentNode = asTestNode(parent);
for (int i = 0; i < mOperations.size(); i++) {
SensorOperation operation = mOperations.get(i);
try {
- operation.execute();
+ operation.execute(currentNode);
} catch (AssertionError e) {
String msg = String.format("Operation %d failed: \"%s\"", i, e.getMessage());
getStats().addValue(SensorStats.ERROR, msg);
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index 7347fc7..901216a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -20,10 +20,12 @@
import android.hardware.cts.helpers.SensorCtsHelper;
import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.SensorTestPlatformException;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
import android.hardware.cts.helpers.TestSensorEventListener;
import android.hardware.cts.helpers.TestSensorManager;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.hardware.cts.helpers.sensorverification.EventGapVerification;
import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
@@ -34,7 +36,9 @@
import android.hardware.cts.helpers.sensorverification.MeanVerification;
import android.hardware.cts.helpers.sensorverification.StandardDeviationVerification;
import android.os.Handler;
+import android.util.Log;
+import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -43,11 +47,13 @@
* A {@link SensorOperation} used to verify that sensor events and sensor values are correct.
* <p>
* Provides methods to set test expectations as well as providing a set of default expectations
- * depending on sensor type. When {{@link #execute()} is called, the sensor will collect the
- * events and then run all the tests.
+ * depending on sensor type. When {{@link #execute(ISensorTestNode)} is called, the sensor will
+ * collect the events and then run all the tests.
* </p>
*/
public class TestSensorOperation extends SensorOperation {
+ private static final String TAG = "TestSensorOperation";
+
private final HashSet<ISensorVerification> mVerifications = new HashSet<>();
private final TestSensorManager mSensorManager;
@@ -55,8 +61,6 @@
private final Executor mExecutor;
private final Handler mHandler;
- private boolean mLogEvents;
-
/**
* An interface that defines an abstraction for operations to be performed by the
* {@link TestSensorOperation}.
@@ -87,13 +91,6 @@
}
/**
- * Set whether to log events.
- */
- public void setLogEvents(boolean logEvents) {
- mLogEvents = logEvents;
- }
-
- /**
* Set all of the default test expectations.
*/
public void addDefaultVerifications() {
@@ -117,10 +114,9 @@
* Collect the specified number of events from the sensor and run all enabled verifications.
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
TestSensorEventListener listener = new TestSensorEventListener(mEnvironment, mHandler);
-
mExecutor.execute(mSensorManager, listener);
boolean failed = false;
@@ -131,6 +127,8 @@
}
if (failed) {
+ trySaveCollectedEvents(parent, listener);
+
String msg = SensorCtsHelper
.formatAssertionMessage("VerifySensorOperation", mEnvironment, sb.toString());
getStats().addValue(SensorStats.ERROR, msg);
@@ -173,6 +171,34 @@
}
/**
+ * Tries to save collected {@link TestSensorEvent}s to a file.
+ *
+ * NOTE: it is more important to handle verifications and its results, than failing if the file
+ * cannot be created. So we silently fail if necessary.
+ */
+ private void trySaveCollectedEvents(ISensorTestNode parent, TestSensorEventListener listener) {
+ String sanitizedFileName;
+ try {
+ String fileName = asTestNode(parent).getName();
+ sanitizedFileName = String.format(
+ "%s-%s-%s_%dus.txt",
+ SensorCtsHelper.sanitizeStringForFileName(fileName),
+ SensorStats.getSanitizedSensorName(mEnvironment.getSensor()),
+ mEnvironment.getFrequencyString(),
+ mEnvironment.getMaxReportLatencyUs());
+ } catch (SensorTestPlatformException e) {
+ Log.w(TAG, "Unable to generate file name to save collected events", e);
+ return;
+ }
+
+ try {
+ listener.logCollectedEventsToFile(sanitizedFileName);
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to save collected events to file: " + sanitizedFileName, e);
+ }
+ }
+
+ /**
* Creates an operation that will wait for a given amount of events to arrive.
*
* @param environment The test environment.
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
index 5f4f5d8..9f03f31 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
@@ -17,7 +17,7 @@
package android.hardware.cts.helpers.sensoroperations;
import android.content.Context;
-import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.reporting.ISensorTestNode;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
@@ -40,6 +40,7 @@
* @param wakeLockFlags the flags used when acquiring the wake-lock
*/
public WakeLockOperation(SensorOperation operation, Context context, int wakeLockFlags) {
+ super(operation.getStats());
mOperation = operation;
mContext = context;
mWakeLockFlags = wakeLockFlags;
@@ -59,13 +60,12 @@
* {@inheritDoc}
*/
@Override
- public void execute() throws InterruptedException {
+ public void execute(ISensorTestNode parent) throws InterruptedException {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(mWakeLockFlags, TAG);
-
wakeLock.acquire();
try {
- mOperation.execute();
+ mOperation.execute(asTestNode(parent));
} finally {
wakeLock.release();
}
@@ -75,15 +75,7 @@
* {@inheritDoc}
*/
@Override
- public SensorStats getStats() {
- return mOperation.getStats();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public SensorOperation clone() {
- return new WakeLockOperation(mOperation, mContext, mWakeLockFlags);
+ return new WakeLockOperation(mOperation.clone(), mContext, mWakeLockFlags);
}
}