aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Desprez <jdesprez@google.com>2017-09-29 19:08:40 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-09-29 19:08:40 +0000
commit6392958350f7b886cba3d5d7fa394a00aa892e79 (patch)
tree091c18705e9f23ad246e96c880365712483be93b
parent6d7988df6512678b17cd5bfbde01a47ae4afd47c (diff)
parent71fa109b10b558354063fa7c38762d415cc15529 (diff)
downloadtradefederation-6392958350f7b886cba3d5d7fa394a00aa892e79.tar.gz
Merge "Introduce testModuleStart/End callbacks" into oc-dev am: 82e24a3a7c
am: 71fa109b10 Change-Id: Ice8bff46082f8781c4477db28f61f85b2755133f
-rw-r--r--src/com/android/tradefed/invoker/ShardListener.java17
-rw-r--r--src/com/android/tradefed/result/CollectingTestListener.java25
-rw-r--r--src/com/android/tradefed/result/ITestInvocationListener.java13
-rw-r--r--src/com/android/tradefed/result/ResultForwarder.java14
-rw-r--r--src/com/android/tradefed/testtype/suite/ITestSuite.java4
-rw-r--r--tests/src/com/android/tradefed/UnitTests.java2
-rw-r--r--tests/src/com/android/tradefed/invoker/ShardListenerTest.java121
-rw-r--r--tests/src/com/android/tradefed/testtype/suite/ITestSuiteMultiTest.java4
-rw-r--r--tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java6
-rw-r--r--tests/src/com/android/tradefed/testtype/suite/TfSuiteRunnerTest.java2
10 files changed, 204 insertions, 4 deletions
diff --git a/src/com/android/tradefed/invoker/ShardListener.java b/src/com/android/tradefed/invoker/ShardListener.java
index ea0f1fb31..8aa56251c 100644
--- a/src/com/android/tradefed/invoker/ShardListener.java
+++ b/src/com/android/tradefed/invoker/ShardListener.java
@@ -113,7 +113,19 @@ public class ShardListener extends CollectingTestListener {
super.invocationEnded(elapsedTime);
synchronized (mMasterListener) {
logShardContent(getRunResults());
+ IInvocationContext moduleContext = null;
for (TestRunResult runResult : getRunResults()) {
+ // Stop or start the module
+ if (moduleContext != null
+ && !getModuleContextForRunResult(runResult).equals(moduleContext)) {
+ mMasterListener.testModuleEnded();
+ moduleContext = null;
+ }
+ if (moduleContext == null && getModuleContextForRunResult(runResult) != null) {
+ moduleContext = getModuleContextForRunResult(runResult);
+ mMasterListener.testModuleStarted(moduleContext);
+ }
+
mMasterListener.testRunStarted(runResult.getName(), runResult.getNumTests());
forwardTestResults(runResult.getTestResults());
if (runResult.isRunFailure()) {
@@ -121,6 +133,11 @@ public class ShardListener extends CollectingTestListener {
}
mMasterListener.testRunEnded(runResult.getElapsedTime(), runResult.getRunMetrics());
}
+ // Close the last module
+ if (moduleContext != null) {
+ mMasterListener.testModuleEnded();
+ moduleContext = null;
+ }
mMasterListener.invocationEnded(elapsedTime);
}
}
diff --git a/src/com/android/tradefed/result/CollectingTestListener.java b/src/com/android/tradefed/result/CollectingTestListener.java
index 80d5987eb..edecf7258 100644
--- a/src/com/android/tradefed/result/CollectingTestListener.java
+++ b/src/com/android/tradefed/result/CollectingTestListener.java
@@ -42,7 +42,10 @@ public class CollectingTestListener implements ITestInvocationListener {
// Uses a LinkedHashmap to have predictable iteration order
private Map<String, TestRunResult> mRunResultsMap =
Collections.synchronizedMap(new LinkedHashMap<String, TestRunResult>());
+ private Map<TestRunResult, IInvocationContext> mModuleContextMap =
+ Collections.synchronizedMap(new LinkedHashMap<TestRunResult, IInvocationContext>());
private TestRunResult mCurrentResults = new TestRunResult();
+ private IInvocationContext mCurrentModuleContext = null;
/** represents sums of tests in each TestStatus state for all runs.
* Indexed by TestStatus.ordinal() */
@@ -116,6 +119,16 @@ public class CollectingTestListener implements ITestInvocationListener {
mBuildInfo = buildInfo;
}
+ @Override
+ public void testModuleStarted(IInvocationContext moduleContext) {
+ mCurrentModuleContext = moduleContext;
+ }
+
+ @Override
+ public void testModuleEnded() {
+ mCurrentModuleContext = null;
+ }
+
/**
* {@inheritDoc}
*/
@@ -130,6 +143,10 @@ public class CollectingTestListener implements ITestInvocationListener {
mCurrentResults.setAggregateMetrics(mIsAggregateMetrics);
mRunResultsMap.put(name, mCurrentResults);
+ // track the module context associated with the results.
+ if (mCurrentModuleContext != null) {
+ mModuleContextMap.put(mCurrentResults, mCurrentModuleContext);
+ }
}
mCurrentResults.testRunStarted(name, numTests);
mIsCountDirty = true;
@@ -232,6 +249,14 @@ public class CollectingTestListener implements ITestInvocationListener {
return mRunResultsMap.values();
}
+ /**
+ * Returns the {@link IInvocationContext} of the module associated with the results or null if
+ * it was not associated with any module.
+ */
+ public IInvocationContext getModuleContextForRunResult(TestRunResult res) {
+ return mModuleContextMap.get(res);
+ }
+
/** Returns True if the result map already has an entry for the run name. */
public boolean hasResultFor(String runName) {
return mRunResultsMap.containsKey(runName);
diff --git a/src/com/android/tradefed/result/ITestInvocationListener.java b/src/com/android/tradefed/result/ITestInvocationListener.java
index c8fbd7c2d..5e951d8db 100644
--- a/src/com/android/tradefed/result/ITestInvocationListener.java
+++ b/src/com/android/tradefed/result/ITestInvocationListener.java
@@ -20,6 +20,7 @@ import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.command.ICommandScheduler;
import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.log.ITestLogger;
+import com.android.tradefed.testtype.suite.ITestSuite;
import java.util.Map;
@@ -95,6 +96,18 @@ public interface ITestInvocationListener extends ITestRunListener, ITestLogger {
}
/**
+ * Reports the beginning of a module running. This callback is associated with {@link
+ * #testModuleEnded()} and is optional in the sequence. It is only used during a run that uses
+ * modules: {@link ITestSuite} based runners.
+ *
+ * @param moduleContext the {@link IInvocationContext} of the module.
+ */
+ public default void testModuleStarted(IInvocationContext moduleContext) {}
+
+ /** Reports the end of a module run. */
+ public default void testModuleEnded() {}
+
+ /**
* {@inheritDoc}
*/
@Override
diff --git a/src/com/android/tradefed/result/ResultForwarder.java b/src/com/android/tradefed/result/ResultForwarder.java
index 494fc7aef..41a3e8809 100644
--- a/src/com/android/tradefed/result/ResultForwarder.java
+++ b/src/com/android/tradefed/result/ResultForwarder.java
@@ -297,4 +297,18 @@ public class ResultForwarder implements ITestInvocationListener {
}
}
}
+
+ @Override
+ public void testModuleStarted(IInvocationContext moduleContext) {
+ for (ITestInvocationListener listener : mListeners) {
+ listener.testModuleStarted(moduleContext);
+ }
+ }
+
+ @Override
+ public void testModuleEnded() {
+ for (ITestInvocationListener listener : mListeners) {
+ listener.testModuleEnded();
+ }
+ }
}
diff --git a/src/com/android/tradefed/testtype/suite/ITestSuite.java b/src/com/android/tradefed/testtype/suite/ITestSuite.java
index cdef58310..90ed34c7c 100644
--- a/src/com/android/tradefed/testtype/suite/ITestSuite.java
+++ b/src/com/android/tradefed/testtype/suite/ITestSuite.java
@@ -233,7 +233,7 @@ public abstract class ITestSuite
}
try {
- mContext.setModuleInvocationContext(module.getModuleInvocationContext());
+ listener.testModuleStarted(module.getModuleInvocationContext());
// Populate the module context with devices and builds
for (String deviceName : mContext.getDeviceConfigNames()) {
module.getModuleInvocationContext()
@@ -245,7 +245,7 @@ public abstract class ITestSuite
} finally {
// clear out module invocation context since we are now done with module
// execution
- mContext.setModuleInvocationContext(null);
+ listener.testModuleEnded();
}
}
} catch (DeviceNotAvailableException e) {
diff --git a/tests/src/com/android/tradefed/UnitTests.java b/tests/src/com/android/tradefed/UnitTests.java
index 5b9e12e1f..8e599eee5 100644
--- a/tests/src/com/android/tradefed/UnitTests.java
+++ b/tests/src/com/android/tradefed/UnitTests.java
@@ -64,6 +64,7 @@ import com.android.tradefed.device.TopHelperTest;
import com.android.tradefed.device.WaitDeviceRecoveryTest;
import com.android.tradefed.device.WifiHelperTest;
import com.android.tradefed.invoker.InvocationContextTest;
+import com.android.tradefed.invoker.ShardListenerTest;
import com.android.tradefed.invoker.TestInvocationMultiTest;
import com.android.tradefed.invoker.TestInvocationTest;
import com.android.tradefed.invoker.shard.ShardHelperTest;
@@ -299,6 +300,7 @@ import org.junit.runners.Suite.SuiteClasses;
// invoker
InvocationContextTest.class,
+ ShardListenerTest.class,
TestInvocationMultiTest.class,
TestInvocationTest.class,
diff --git a/tests/src/com/android/tradefed/invoker/ShardListenerTest.java b/tests/src/com/android/tradefed/invoker/ShardListenerTest.java
new file mode 100644
index 000000000..705b55c49
--- /dev/null
+++ b/tests/src/com/android/tradefed/invoker/ShardListenerTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 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.tradefed.invoker;
+
+import com.android.ddmlib.testrunner.TestIdentifier;
+import com.android.tradefed.build.BuildInfo;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.ITestInvocationListener;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Collections;
+
+/** Unit tests for {@link ShardListener}. */
+@RunWith(JUnit4.class)
+public class ShardListenerTest {
+ private ShardListener mShardListener;
+ private ITestInvocationListener mMockListener;
+ private IInvocationContext mContext;
+ private ITestDevice mMockDevice;
+
+ @Before
+ public void setUp() {
+ mMockListener = EasyMock.createMock(ITestInvocationListener.class);
+ mShardListener = new ShardListener(mMockListener);
+ mMockDevice = EasyMock.createMock(ITestDevice.class);
+ EasyMock.expect(mMockDevice.getSerialNumber()).andStubReturn("serial");
+ mContext = new InvocationContext();
+ mContext.addDeviceBuildInfo("default", new BuildInfo());
+ mContext.addAllocatedDevice("default", mMockDevice);
+ }
+
+ /** Ensure that all the events given to the shardlistener are replayed on invocationEnded. */
+ @Test
+ public void testBufferAndReplay() {
+ mMockListener.invocationStarted(mContext);
+ mMockListener.testRunStarted("run1", 1);
+ TestIdentifier tid = new TestIdentifier("class1", "name1");
+ mMockListener.testStarted(tid, 0l);
+ mMockListener.testEnded(tid, 0l, Collections.emptyMap());
+ mMockListener.testRunEnded(0l, Collections.emptyMap());
+ mMockListener.invocationEnded(0l);
+
+ EasyMock.replay(mMockListener, mMockDevice);
+ mShardListener.invocationStarted(mContext);
+ mShardListener.testRunStarted("run1", 1);
+ mShardListener.testStarted(tid, 0l);
+ mShardListener.testEnded(tid, 0l, Collections.emptyMap());
+ mShardListener.testRunEnded(0l, Collections.emptyMap());
+ mShardListener.invocationEnded(0l);
+ EasyMock.verify(mMockListener, mMockDevice);
+ }
+
+ /** Test that the buffering of events is properly done in respect to the modules too. */
+ @Test
+ public void testBufferAndReplay_withModule() {
+ IInvocationContext module1 = new InvocationContext();
+ IInvocationContext module2 = new InvocationContext();
+ mMockListener.invocationStarted(mContext);
+ mMockListener.testModuleStarted(module1);
+ mMockListener.testRunStarted("run1", 1);
+ TestIdentifier tid = new TestIdentifier("class1", "name1");
+ mMockListener.testStarted(tid, 0l);
+ mMockListener.testEnded(tid, 0l, Collections.emptyMap());
+ mMockListener.testRunEnded(0l, Collections.emptyMap());
+ mMockListener.testRunStarted("run2", 1);
+ mMockListener.testStarted(tid, 0l);
+ mMockListener.testEnded(tid, 0l, Collections.emptyMap());
+ mMockListener.testRunEnded(0l, Collections.emptyMap());
+ mMockListener.testModuleEnded();
+ // expectation on second module
+ mMockListener.testModuleStarted(module2);
+ mMockListener.testRunStarted("run3", 1);
+ mMockListener.testStarted(tid, 0l);
+ mMockListener.testEnded(tid, 0l, Collections.emptyMap());
+ mMockListener.testRunEnded(0l, Collections.emptyMap());
+ mMockListener.testModuleEnded();
+ mMockListener.invocationEnded(0l);
+
+ EasyMock.replay(mMockListener, mMockDevice);
+ mShardListener.invocationStarted(mContext);
+ // 1st module
+ mShardListener.testModuleStarted(module1);
+ mShardListener.testRunStarted("run1", 1);
+ mShardListener.testStarted(tid, 0l);
+ mShardListener.testEnded(tid, 0l, Collections.emptyMap());
+ mShardListener.testRunEnded(0l, Collections.emptyMap());
+ mShardListener.testRunStarted("run2", 1);
+ mShardListener.testStarted(tid, 0l);
+ mShardListener.testEnded(tid, 0l, Collections.emptyMap());
+ mShardListener.testRunEnded(0l, Collections.emptyMap());
+ mShardListener.testModuleEnded();
+ // 2nd module
+ mShardListener.testModuleStarted(module2);
+ mShardListener.testRunStarted("run3", 1);
+ mShardListener.testStarted(tid, 0l);
+ mShardListener.testEnded(tid, 0l, Collections.emptyMap());
+ mShardListener.testRunEnded(0l, Collections.emptyMap());
+ mShardListener.testModuleEnded();
+
+ mShardListener.invocationEnded(0l);
+ EasyMock.verify(mMockListener, mMockDevice);
+ }
+}
diff --git a/tests/src/com/android/tradefed/testtype/suite/ITestSuiteMultiTest.java b/tests/src/com/android/tradefed/testtype/suite/ITestSuiteMultiTest.java
index d2bafe11d..0dc0fda15 100644
--- a/tests/src/com/android/tradefed/testtype/suite/ITestSuiteMultiTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/ITestSuiteMultiTest.java
@@ -111,7 +111,7 @@ public class ITestSuiteMultiTest {
mTestSuite.setInvocationContext(mContext);
mTestSuite.setSystemStatusChecker(new ArrayList<>());
-
+ mMockListener.testModuleStarted(EasyMock.anyObject());
mMockListener.testRunStarted("test1", 2);
TestIdentifier test1 =
new TestIdentifier(MultiDeviceStubTest.class.getSimpleName(), "test0");
@@ -122,7 +122,7 @@ public class ITestSuiteMultiTest {
mMockListener.testStarted(test2, 0l);
mMockListener.testEnded(test2, 5l, Collections.emptyMap());
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
-
+ mMockListener.testModuleEnded();
EasyMock.replay(
mMockListener, mMockBuildInfo1, mMockBuildInfo2, mMockDevice1, mMockDevice2);
mTestSuite.run(mMockListener);
diff --git a/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java b/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java
index 3750c4d02..f691558e4 100644
--- a/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/ITestSuiteTest.java
@@ -166,11 +166,13 @@ public class ITestSuiteTest {
/** Helper to expect the test run callback. */
private void expectTestRun(ITestInvocationListener listener) {
+ listener.testModuleStarted(EasyMock.anyObject());
listener.testRunStarted(TEST_CONFIG_NAME, 1);
TestIdentifier test = new TestIdentifier(EMPTY_CONFIG, EMPTY_CONFIG);
listener.testStarted(test, 0);
listener.testEnded(test, 5, Collections.emptyMap());
listener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
+ listener.testModuleEnded();
}
/** Test for {@link ITestSuite#run(ITestInvocationListener)}. */
@@ -307,11 +309,13 @@ public class ITestSuiteTest {
setter.setOptionValue("skip-all-system-status-check", "true");
setter.setOptionValue("reboot-per-module", "true");
EasyMock.expect(mMockDevice.getProperty("ro.build.type")).andReturn("user");
+ mMockListener.testModuleStarted(EasyMock.anyObject());
mMockListener.testRunStarted(TEST_CONFIG_NAME, 1);
EasyMock.expectLastCall().times(1);
mMockListener.testRunFailed("Module test only ran 0 out of 1 expected tests.");
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.expectLastCall().times(1);
+ mMockListener.testModuleEnded();
replayMocks();
mTestSuite.run(mMockListener);
verifyMocks();
@@ -352,11 +356,13 @@ public class ITestSuiteTest {
setter.setOptionValue("skip-all-system-status-check", "true");
setter.setOptionValue("reboot-per-module", "true");
EasyMock.expect(mMockDevice.getProperty("ro.build.type")).andReturn("user");
+ mMockListener.testModuleStarted(EasyMock.anyObject());
mMockListener.testRunStarted(TEST_CONFIG_NAME, 1);
EasyMock.expectLastCall().times(1);
mMockListener.testRunFailed("Module test only ran 0 out of 1 expected tests.");
mMockListener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
EasyMock.expectLastCall().times(1);
+ mMockListener.testModuleEnded();
replayMocks();
mTestSuite.run(mMockListener);
verifyMocks();
diff --git a/tests/src/com/android/tradefed/testtype/suite/TfSuiteRunnerTest.java b/tests/src/com/android/tradefed/testtype/suite/TfSuiteRunnerTest.java
index b67d8789f..240e50885 100644
--- a/tests/src/com/android/tradefed/testtype/suite/TfSuiteRunnerTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/TfSuiteRunnerTest.java
@@ -182,8 +182,10 @@ public class TfSuiteRunnerTest {
mRunner.setSystemStatusChecker(new ArrayList<>());
mRunner.setInvocationContext(new InvocationContext());
// runs the expanded suite
+ listener.testModuleStarted(EasyMock.anyObject());
listener.testRunStarted("suite/stub1", 0);
listener.testRunEnded(EasyMock.anyLong(), EasyMock.anyObject());
+ listener.testModuleEnded();
EasyMock.replay(listener);
mRunner.run(listener);
EasyMock.verify(listener);