Attempt to make CollectingTestListener merging thread-safe
Ensure dirty count and merging can be done safely.
Test: unit tests
Bug: 120568293
Change-Id: Ie1d39d027c665665a6384f23620a5e05ab6cadd8
diff --git a/src/com/android/tradefed/result/CollectingTestListener.java b/src/com/android/tradefed/result/CollectingTestListener.java
index a36cc7d..13530af 100644
--- a/src/com/android/tradefed/result/CollectingTestListener.java
+++ b/src/com/android/tradefed/result/CollectingTestListener.java
@@ -33,6 +33,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* A {@link ITestInvocationListener} that will collect all test results.
@@ -63,7 +64,7 @@
private TestRunResult mCurrentTestRunResult = new TestRunResult();
// Tracks if mStatusCounts are accurate, or if they need to be recalculated
- private boolean mIsCountDirty = true;
+ private AtomicBoolean mIsCountDirty = new AtomicBoolean(true);
// Represents the merged test results. This should not be accessed directly since it's only
// calculated when needed.
private final List<TestRunResult> mMergedTestRunResults = new ArrayList<>();
@@ -159,7 +160,7 @@
/** {@inheritDoc} */
@Override
public void testRunStarted(String name, int numTests, int attemptNumber) {
- mIsCountDirty = true;
+ setCountDirty();
// Associate the run name with the current module context
if (mCurrentModuleContext != null) {
@@ -210,21 +211,21 @@
/** {@inheritDoc} */
@Override
public void testRunEnded(long elapsedTime, HashMap<String, Metric> runMetrics) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testRunEnded(elapsedTime, runMetrics);
}
/** {@inheritDoc} */
@Override
public void testRunFailed(String errorMessage) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testRunFailed(errorMessage);
}
/** {@inheritDoc} */
@Override
public void testRunStopped(long elapsedTime) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testRunStopped(elapsedTime);
}
@@ -237,7 +238,7 @@
/** {@inheritDoc} */
@Override
public void testStarted(TestDescription test, long startTime) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testStarted(test, startTime);
}
@@ -250,26 +251,26 @@
/** {@inheritDoc} */
@Override
public void testEnded(TestDescription test, long endTime, HashMap<String, Metric> testMetrics) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testEnded(test, endTime, testMetrics);
}
/** {@inheritDoc} */
@Override
public void testFailed(TestDescription test, String trace) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testFailed(test, trace);
}
@Override
public void testAssumptionFailure(TestDescription test, String trace) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testAssumptionFailure(test, trace);
}
@Override
public void testIgnored(TestDescription test) {
- mIsCountDirty = true;
+ setCountDirty();
mCurrentTestRunResult.testIgnored(test);
}
@@ -374,9 +375,11 @@
* expensive.
*/
private synchronized void computeMergedResults() {
- if (!mIsCountDirty) {
+ // If not dirty, nothing to be done
+ if (!mIsCountDirty.compareAndSet(true, false)) {
return;
}
+
mMergedTestRunResults.clear();
// Merge results
if (mTestRunResultMap.isEmpty() && mCurrentTestRunResult.isRunFailure()) {
@@ -406,8 +409,14 @@
mStatusCounts[s.ordinal()] += result.getNumTestsInState(s);
}
}
+ }
- mIsCountDirty = false;
+ /**
+ * Keep dirty count as AtomicBoolean to ensure when accessed from another thread the state is
+ * consistent.
+ */
+ private void setCountDirty() {
+ mIsCountDirty.set(true);
}
/**