Mobly: report test events to listener in real-time
Also:
* Added complete support for include/exclude filters.
Bug: 270963463
Test: None
Change-Id: Ic93fece249b447c5a3c35de3ff37c59ca5d703cc
diff --git a/javatests/com/android/tradefed/testtype/mobly/MoblyBinaryHostTestTest.java b/javatests/com/android/tradefed/testtype/mobly/MoblyBinaryHostTestTest.java
index 311a1a7..96bf479 100644
--- a/javatests/com/android/tradefed/testtype/mobly/MoblyBinaryHostTestTest.java
+++ b/javatests/com/android/tradefed/testtype/mobly/MoblyBinaryHostTestTest.java
@@ -20,12 +20,12 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -53,9 +53,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import org.mockito.InOrder;
import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -135,21 +134,23 @@
// Mimics the behavior of a successful test run.
Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
.thenAnswer(
- new Answer<CommandResult>() {
- @Override
- public CommandResult answer(InvocationOnMock invocation)
- throws Throwable {
- FileUtils.createFile(testResult, "");
- FileUtils.createFile(
- new File(mSpyTest.getLogDirAbsolutePath(), "log"),
- "log content");
- return new CommandResult(CommandStatus.SUCCESS);
- }
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
});
mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
- verify(mSpyTest.getRunUtil()).runTimedCmd(anyLong(), any());
+ verify(mSpyTest.getRunUtil(), times(2)).runTimedCmd(anyLong(), any());
assertNull(mSpyTest.getLogDirFile());
}
@@ -174,21 +175,23 @@
File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
.thenAnswer(
- new Answer<CommandResult>() {
- @Override
- public CommandResult answer(InvocationOnMock invocation)
- throws Throwable {
- FileUtils.createFile(testResult, "");
- FileUtils.createFile(
- new File(mSpyTest.getLogDirAbsolutePath(), "log"),
- "log content");
- return new CommandResult(CommandStatus.SUCCESS);
- }
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
});
mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
- verify(mSpyTest.getRunUtil()).runTimedCmd(anyLong(), any());
+ verify(mSpyTest.getRunUtil(), times(2)).runTimedCmd(anyLong(), any());
assertNull(mSpyTest.getLogDirFile());
}
@@ -216,20 +219,23 @@
setter.setOptionValue("mobly-std-log", "true");
File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
// Mimics the behavior of a successful test run.
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ });
Mockito.when(
mMockRunUtil.runTimedCmd(
anyLong(), any(OutputStream.class), any(OutputStream.class), any()))
.thenAnswer(
- new Answer<CommandResult>() {
- @Override
- public CommandResult answer(InvocationOnMock invocation)
- throws Throwable {
- FileUtils.createFile(testResult, "");
- FileUtils.createFile(
- new File(mSpyTest.getLogDirAbsolutePath(), "log"),
- "log content");
- return new CommandResult(CommandStatus.SUCCESS);
- }
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
});
mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
@@ -239,26 +245,22 @@
public void testRun_testResultIsMissing() throws Exception {
OptionSetter setter = new OptionSetter(mSpyTest);
setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
// Test result and log files were not created for some reasons during test run.
Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
.thenAnswer(
- new Answer<CommandResult>() {
- @Override
- public CommandResult answer(InvocationOnMock invocation)
- throws Throwable {
- return new CommandResult(CommandStatus.SUCCESS);
- }
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ return new CommandResult(CommandStatus.SUCCESS);
});
- try {
- mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
- fail("Should have thrown an exception");
- } catch (RuntimeException e) {
- assertThat(e)
- .hasMessageThat()
- .contains("Fail to find test summary file test_summary.yaml under directory");
- assertNull(mSpyTest.getLogDirFile());
- }
+ mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
+ assertFalse(testResult.exists());
}
@Test
@@ -267,25 +269,30 @@
OptionSetter setter = new OptionSetter(mSpyTest);
setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
- Mockito.when(
- mMockRunUtil.runTimedCmd(
- anyLong(),
- anyString(),
- eq("--"),
- contains("--config="),
- contains("--device_serial="),
- contains("--log_path=")))
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
.thenAnswer(
- new Answer<CommandResult>() {
- @Override
- public CommandResult answer(InvocationOnMock invocation)
- throws Throwable {
- FileUtils.createFile(testResult, "");
- FileUtils.createFile(
- new File(mSpyTest.getLogDirAbsolutePath(), "log"),
- "log content");
- return new CommandResult(CommandStatus.SUCCESS);
- }
+ invocation -> {
+ CommandResult result = new CommandResult(CommandStatus.SUCCESS);
+ result.setStdout(
+ "Name: pip\nLocation: "
+ + new File(
+ mVenvDir.getAbsolutePath(),
+ "lib/python3.8/site-packages"));
+ return result;
+ })
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
});
CommandResult result = new CommandResult(CommandStatus.SUCCESS);
result.setStdout(
@@ -296,6 +303,7 @@
mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
+ verify(mSpyTest.getRunUtil(), times(3)).runTimedCmd(anyLong(), any());
verify(mSpyTest.getRunUtil(), times(1))
.setEnvVariable(eq("VIRTUAL_ENV"), eq(mVenvDir.getAbsolutePath()));
assertFalse(mVenvDir.exists());
@@ -309,16 +317,18 @@
File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
.thenAnswer(
- new Answer<CommandResult>() {
- @Override
- public CommandResult answer(InvocationOnMock invocation)
- throws Throwable {
- FileUtils.createFile(testResult, "");
- FileUtils.createFile(
- new File(mSpyTest.getLogDirAbsolutePath(), "log"),
- "log content");
- return new CommandResult(CommandStatus.SUCCESS);
- }
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
});
mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
@@ -358,31 +368,29 @@
.when(mTestInfo)
.getDependencyFile(eq(mMoblyBinary2.getName()), eq(false));
File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
- Mockito.when(
- mMockRunUtil.runTimedCmd(
- anyLong(),
- any(),
- eq("--"),
- contains("--config="),
- contains("--device_serial="),
- contains("--log_path=")))
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
.thenAnswer(
- new Answer<CommandResult>() {
- @Override
- public CommandResult answer(InvocationOnMock invocation)
- throws Throwable {
- FileUtils.createFile(testResult, "");
- FileUtils.createFile(
- new File(mSpyTest.getLogDirAbsolutePath(), "log"),
- "log content");
- return new CommandResult(CommandStatus.SUCCESS);
- }
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
});
mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
// Verify the command line contains "--config"
- verify(mSpyTest.getRunUtil(), times(1))
+ InOrder inOrder = inOrder(mSpyTest.getRunUtil());
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(anyLong(), any(), eq("--"), eq("--list_tests"));
+ inOrder.verify(mSpyTest.getRunUtil())
.runTimedCmd(
anyLong(),
any(),
@@ -393,6 +401,387 @@
}
@Test
+ public void testRun_withoutTests() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-par-file-name", mMoblyBinary2.getName());
+ Mockito.doReturn(mMoblyTestDir)
+ .when(mTestInfo)
+ .getDependencyFile(eq(mMoblyBinary2.getName()), eq(false));
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout(""); // No tests.
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
+
+ // Verify no tests where run.
+ verify(mSpyTest.getRunUtil()).runTimedCmd(anyLong(), any(), eq("--"), eq("--list_tests"));
+ }
+
+ @Test
+ public void testRun_withoutFilters() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-par-file-name", mMoblyBinary2.getName());
+ Mockito.doReturn(mMoblyTestDir)
+ .when(mTestInfo)
+ .getDependencyFile(eq(mMoblyBinary2.getName()), eq(false));
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ mSpyTest.run(mTestInfo, Mockito.mock(ITestInvocationListener.class));
+
+ // Verify the command line contains "--tests"
+ InOrder inOrder = inOrder(mSpyTest.getRunUtil());
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(anyLong(), any(), eq("--"), eq("--list_tests"));
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(
+ anyLong(),
+ any(),
+ eq("--"),
+ contains("--config="),
+ contains("--device_serial="),
+ contains("--log_path="));
+ }
+
+ @Test
+ public void testRun_withInvalidIncludeFilters() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addIncludeFilter("test_bar");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(0));
+ verify(mockListener, times(1)).testRunFailed(any(FailureDescription.class));
+ verify(mockListener, times(1)).testRunEnded(eq(0L), eq(new HashMap<String, Metric>()));
+ }
+
+ @Test
+ public void testRun_withInvalidExcludeFilters() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addExcludeFilter("test_bar");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(0));
+ }
+
+ @Test
+ public void testRun_withInvalidExcludeFiltersPrefix() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addExcludeFilter("test_f");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(0));
+ }
+
+ @Test
+ public void testRun_withIncludeFiltersExact() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addIncludeFilter("test_bar");
+ mSpyTest.addIncludeFilter("test_foo");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo\ntest_baz\ntest_bar");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(2));
+
+ // Verify the command line contains "--tests"
+ InOrder inOrder = inOrder(mSpyTest.getRunUtil());
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(anyLong(), any(), eq("--"), eq("--list_tests"));
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(
+ anyLong(),
+ any(),
+ eq("--"),
+ contains("--config="),
+ contains("--device_serial="),
+ contains("--log_path="),
+ eq("--tests"),
+ eq("test_foo"),
+ eq("test_bar"));
+ }
+
+ @Test
+ public void testRun_withPrefixIncludeFiltersPrefix() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addIncludeFilter("test_b");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo\ntest_baz\ntest_bar");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(2));
+
+ // Verify the command line contains "--tests"
+ InOrder inOrder = inOrder(mSpyTest.getRunUtil());
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(anyLong(), any(), eq("--"), eq("--list_tests"));
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(
+ anyLong(),
+ any(),
+ eq("--"),
+ contains("--config="),
+ contains("--device_serial="),
+ contains("--log_path="),
+ eq("--tests"),
+ eq("test_baz"),
+ eq("test_bar"));
+ }
+
+ @Test
+ public void testRun_withExcludeFiltersExact() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addExcludeFilter("test_bar");
+ mSpyTest.addExcludeFilter("test_foo");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo\ntest_baz\ntest_bar");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(1));
+
+ // Verify the command line contains "--tests"
+ InOrder inOrder = inOrder(mSpyTest.getRunUtil());
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(anyLong(), any(), eq("--"), eq("--list_tests"));
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(
+ anyLong(),
+ any(),
+ eq("--"),
+ contains("--config="),
+ contains("--device_serial="),
+ contains("--log_path="),
+ eq("--tests"),
+ eq("test_baz"));
+ }
+
+ @Test
+ public void testRun_withExcludeFiltersNoTests() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addExcludeFilter("test_bar");
+ mSpyTest.addExcludeFilter("test_baz");
+ mSpyTest.addExcludeFilter("test_foo");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo\ntest_baz\ntest_bar");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(0));
+ }
+
+ @Test
+ public void testRun_withBothIncludeAndExcludeFilters() throws Exception {
+ Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
+ OptionSetter setter = new OptionSetter(mSpyTest);
+ setter.setOptionValue("mobly-binaries", mMoblyBinary.getAbsolutePath());
+ File testResult = new File(mSpyTest.getLogDirAbsolutePath(), TEST_RESULT_FILE_NAME);
+ mSpyTest.addIncludeFilter("test_b");
+ mSpyTest.addExcludeFilter("test_bar");
+ Mockito.when(mMockRunUtil.runTimedCmd(anyLong(), any()))
+ .thenAnswer(
+ invocation -> {
+ CommandResult res = new CommandResult(CommandStatus.SUCCESS);
+ res.setStdout("test_foo\ntest_baz\ntest_bar");
+ return res;
+ })
+ .thenAnswer(
+ invocation -> {
+ FileUtils.createFile(testResult, "");
+ FileUtils.createFile(
+ new File(mSpyTest.getLogDirAbsolutePath(), "log"),
+ "log content");
+ return new CommandResult(CommandStatus.SUCCESS);
+ });
+
+ ITestInvocationListener mockListener = Mockito.mock(ITestInvocationListener.class);
+
+ mSpyTest.run(mTestInfo, mockListener);
+
+ verify(mockListener, times(1)).testRunStarted(anyString(), eq(1));
+
+ // Verify the command line contains "--tests"
+ InOrder inOrder = inOrder(mSpyTest.getRunUtil());
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(anyLong(), any(), eq("--"), eq("--list_tests"));
+ inOrder.verify(mSpyTest.getRunUtil())
+ .runTimedCmd(
+ anyLong(),
+ any(),
+ eq("--"),
+ contains("--config="),
+ contains("--device_serial="),
+ contains("--log_path="),
+ eq("--tests"),
+ eq("test_baz"));
+ }
+
+ @Test
public void testBuildCommandLineArrayWithConfig() throws Exception {
Mockito.doNothing().when(mSpyTest).reportLogs(any(), any());
Mockito.doReturn(DEVICE_SERIAL).when(mMockDevice).getSerialNumber();
diff --git a/javatests/com/android/tradefed/testtype/mobly/MoblyYamlResultParserTest.java b/javatests/com/android/tradefed/testtype/mobly/MoblyYamlResultParserTest.java
index 9d87fff..daa2108 100644
--- a/javatests/com/android/tradefed/testtype/mobly/MoblyYamlResultParserTest.java
+++ b/javatests/com/android/tradefed/testtype/mobly/MoblyYamlResultParserTest.java
@@ -24,7 +24,6 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.android.tradefed.result.FailureDescription;
import com.android.tradefed.result.ITestInvocationListener;
@@ -34,8 +33,6 @@
import com.android.tradefed.testtype.mobly.MoblyYamlResultRecordHandler.Record;
import com.android.tradefed.testtype.mobly.MoblyYamlResultSummaryHandler.Summary;
import com.android.tradefed.testtype.mobly.MoblyYamlResultUserDataHandler.UserData;
-import com.android.tradefed.util.FileUtil;
-import com.android.tradefed.util.ResourceUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -45,12 +42,9 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
-import org.mockito.InOrder;
import org.mockito.Mockito;
import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
@@ -63,7 +57,7 @@
private static final String DEFAULT_BEGIN_TIME = "1571681517464";
private static final String DEFAULT_END_TIME = "1571681520407";
private static final String DEFAULT_TEST_CLASS = "DefaultTestClass";
- private static final String DEFAULT_TEST_NAME = "default_test_name";
+ private static final String DEFAULT_TEST_NAME = "test_default_name";
private static final String TEST_ERROR_YAML = "/testtype/test_summary_error.yaml";
private static final String SAMPLE_STACK_TRACE =
"\"Traceback (most recent call last):\\n"
@@ -137,16 +131,12 @@
private MoblyYamlResultParser mParser;
private ITestInvocationListener mMockListener;
private ImmutableList<ITestInvocationListener> mListeners;
- private String mRunName;
- private ArgumentCaptor<String> mRunNameCaptor;
- private ArgumentCaptor<Integer> mCountCaptor;
private ArgumentCaptor<TestDescription> mStartedDescCaptor;
private ArgumentCaptor<Long> mBeginTimeCaptor;
private ArgumentCaptor<TestDescription> mFailedDescCaptor;
private ArgumentCaptor<FailureDescription> mFailureDescriptionCaptor;
private ArgumentCaptor<TestDescription> mEndDescCaptor;
private ArgumentCaptor<Long> mEndTimeCaptor;
- private ArgumentCaptor<Long> mElapseTimeCaptor;
@Before
public void setUp() throws Exception {
@@ -156,12 +146,6 @@
}
private void setUpArgumentCaptors() {
- // Setup testRunStarted
- mRunNameCaptor = ArgumentCaptor.forClass(String.class);
- mCountCaptor = ArgumentCaptor.forClass(Integer.class);
- Mockito.doNothing()
- .when(mMockListener)
- .testRunStarted(mRunNameCaptor.capture(), mCountCaptor.capture());
// Setup testStarted
mStartedDescCaptor = ArgumentCaptor.forClass(TestDescription.class);
mBeginTimeCaptor = ArgumentCaptor.forClass(Long.class);
@@ -180,17 +164,11 @@
Mockito.doNothing()
.when(mMockListener)
.testEnded(mEndDescCaptor.capture(), mEndTimeCaptor.capture(), any(Map.class));
- // Setup testRunEnded
- mElapseTimeCaptor = ArgumentCaptor.forClass(Long.class);
- Mockito.doNothing()
- .when(mMockListener)
- .testRunEnded(mElapseTimeCaptor.capture(), any(Map.class));
}
@Test
public void testReportToListenersPassRecord() {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
IMoblyYamlResultHandler.ITestResult passRecord =
new Record.Builder()
.setTestName(DEFAULT_TEST_NAME)
@@ -202,8 +180,6 @@
List<IMoblyYamlResultHandler.ITestResult> resultCache = ImmutableList.of(passRecord);
mParser.reportToListeners(mListeners, resultCache);
- assertEquals(mRunName, mRunNameCaptor.getValue());
- assertEquals(0, (int) mCountCaptor.getValue());
assertEquals(DEFAULT_TEST_CLASS, mStartedDescCaptor.getValue().getClassName());
assertEquals(DEFAULT_TEST_NAME, mStartedDescCaptor.getValue().getTestName());
assertEquals(Long.parseLong(DEFAULT_BEGIN_TIME), (long) mBeginTimeCaptor.getValue());
@@ -211,15 +187,11 @@
assertEquals(DEFAULT_TEST_CLASS, mEndDescCaptor.getValue().getClassName());
assertEquals(DEFAULT_TEST_NAME, mEndDescCaptor.getValue().getTestName());
assertEquals(Long.parseLong(DEFAULT_END_TIME), (long) mEndTimeCaptor.getValue());
- assertEquals(
- Long.parseLong(DEFAULT_END_TIME) - Long.parseLong(DEFAULT_BEGIN_TIME),
- (long) mElapseTimeCaptor.getValue());
}
@Test
public void testReportToListenersFailRecord() {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
IMoblyYamlResultHandler.ITestResult failRecord =
new Record.Builder()
.setTestName(DEFAULT_TEST_NAME)
@@ -232,8 +204,6 @@
List<IMoblyYamlResultHandler.ITestResult> resultCache = ImmutableList.of(failRecord);
mParser.reportToListeners(mListeners, resultCache);
- assertEquals(mRunName, mRunNameCaptor.getValue());
- assertEquals(0, (int) mCountCaptor.getValue());
assertEquals(DEFAULT_TEST_CLASS, mStartedDescCaptor.getValue().getClassName());
assertEquals(DEFAULT_TEST_NAME, mStartedDescCaptor.getValue().getTestName());
assertEquals(Long.parseLong(DEFAULT_BEGIN_TIME), (long) mBeginTimeCaptor.getValue());
@@ -252,46 +222,34 @@
assertEquals(DEFAULT_TEST_CLASS, mEndDescCaptor.getValue().getClassName());
assertEquals(DEFAULT_TEST_NAME, mEndDescCaptor.getValue().getTestName());
assertEquals(Long.parseLong(DEFAULT_END_TIME), (long) mEndTimeCaptor.getValue());
- assertEquals(
- Long.parseLong(DEFAULT_END_TIME) - Long.parseLong(DEFAULT_BEGIN_TIME),
- (long) mElapseTimeCaptor.getValue());
}
@Test
public void testReportToListenersUserData() {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
List<IMoblyYamlResultHandler.ITestResult> resultCache =
ImmutableList.of(new UserData.Builder().setTimestamp(DEFAULT_BEGIN_TIME).build());
mParser.reportToListeners(mListeners, resultCache);
- assertEquals(mRunName, mRunNameCaptor.getValue());
- assertEquals(0, (int) mCountCaptor.getValue());
verify(mMockListener, never()).testStarted(any(), anyLong());
verify(mMockListener, never()).testFailed(any(), anyString());
- assertEquals(0L - Long.parseLong(DEFAULT_BEGIN_TIME), (long) mElapseTimeCaptor.getValue());
}
@Test
public void testReportToListenersControllerInfo() {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
List<IMoblyYamlResultHandler.ITestResult> resultCache =
ImmutableList.of(
new ControllerInfo.Builder().setTimestamp("1571681322.791003").build());
mParser.reportToListeners(mListeners, resultCache);
- assertEquals(mRunName, mRunNameCaptor.getValue());
- assertEquals(0, (int) mCountCaptor.getValue());
verify(mMockListener, never()).testStarted(any(), anyLong());
verify(mMockListener, never()).testFailed(any(), anyString());
- assertEquals(1571681322791L, (long) mElapseTimeCaptor.getValue());
}
@Test
public void testParseDocumentMapRecordPass() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
Map<String, Object> detailMap = new HashMap<>();
detailMap.put("Result", "PASS");
detailMap.put("Stacktrace", "null");
@@ -307,8 +265,7 @@
@Test
public void testParseDocumentMapRecordFail() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
Map<String, Object> detailMap = new HashMap<>();
detailMap.put("Stacktrace", SAMPLE_STACK_TRACE);
detailMap.put("Result", "FAIL");
@@ -325,8 +282,7 @@
@Test
public void testParseDocumentMapSummary() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
Map<String, Object> docMap = new HashMap<>();
docMap.put("Type", "Summary");
docMap.put("Executed", "10");
@@ -339,8 +295,7 @@
@Test
public void testParseDocumentMapControllerInfo() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
Map<String, Object> docMap = new HashMap<>();
docMap.put("Type", "ControllerInfo");
docMap.put("Timestamp", "1571681322.791003");
@@ -352,8 +307,7 @@
@Test
public void testParseDocumentMapUserData() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
Map<String, Object> docMap = new HashMap<>();
docMap.put("Type", "UserData");
docMap.put("timestamp", DEFAULT_BEGIN_TIME);
@@ -364,8 +318,7 @@
@Test
public void testParseDocumentMapTestNameList() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
Map<String, Object> docMap = new HashMap<>();
docMap.put("Type", "TestNameList");
IMoblyYamlResultHandler.ITestResult result = mParser.parseDocumentMap(docMap);
@@ -374,8 +327,7 @@
@Test
public void testParse() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
+ mParser = new MoblyYamlResultParser(mMockListener);
MoblyYamlResultParser spyParser = Mockito.spy(mParser);
String passRecord = buildTestRecordString(new HashMap<>());
@@ -387,41 +339,22 @@
StringBuilder strBuilder = new StringBuilder();
strBuilder.append("---\n");
strBuilder.append(TESTNAME_LIST);
- strBuilder.append("\n---\n");
+ strBuilder.append("\n...\n---\n");
strBuilder.append(USER_DATA);
- strBuilder.append("\n---\n");
+ strBuilder.append("\n...\n---\n");
strBuilder.append(passRecord);
- strBuilder.append("\n---\n");
+ strBuilder.append("\n...\n---\n");
strBuilder.append(failRecord);
- strBuilder.append("\n---\n");
+ strBuilder.append("\n...\n---\n");
strBuilder.append(CONTROLLER_INFO);
- strBuilder.append("\n--- ");
+ strBuilder.append("\n...\n---\n");
strBuilder.append(SUMMARY);
+ strBuilder.append("\n...\n");
InputStream inputStream = new ByteArrayInputStream(strBuilder.toString().getBytes());
spyParser.parse(inputStream);
verify(spyParser, times(6)).parseDocumentMap(any(Map.class));
- verify(spyParser, times(1)).reportToListeners(any(), any());
- }
-
- @Test
- public void testParseError() throws Exception {
- mRunName = new Object() {}.getClass().getEnclosingMethod().getName();
- mParser = new MoblyYamlResultParser(mMockListener, mRunName);
- File testErrorYaml = FileUtil.createTempFile("test_summary", "yaml");
- ResourceUtil.extractResourceAsFile(TEST_ERROR_YAML, testErrorYaml);
- try (FileInputStream inputStream = new FileInputStream(testErrorYaml)) {
- mParser.parse(inputStream);
- } finally {
- FileUtil.deleteFile(testErrorYaml);
- }
- InOrder inOrder = Mockito.inOrder(mMockListener);
- inOrder.verify(mMockListener).testRunStarted(mRunName, 1);
- inOrder.verify(mMockListener).testRunFailed((FailureDescription) any());
- inOrder.verify(mMockListener).testRunEnded(anyLong(), any(Map.class));
-
- inOrder.verifyNoMoreInteractions();
- verifyNoMoreInteractions(mMockListener);
+ verify(spyParser, times(6)).reportToListeners(any(), any());
}
private ImmutableMap<String, Object> buildTestRecordDocMap(Map<String, Object> propertyMap) {
diff --git a/test_framework/com/android/tradefed/testtype/mobly/MoblyBinaryHostTest.java b/test_framework/com/android/tradefed/testtype/mobly/MoblyBinaryHostTest.java
index abeb2b4..eb1dbd7 100644
--- a/test_framework/com/android/tradefed/testtype/mobly/MoblyBinaryHostTest.java
+++ b/test_framework/com/android/tradefed/testtype/mobly/MoblyBinaryHostTest.java
@@ -56,12 +56,19 @@
import java.io.InputStream;
import java.io.Writer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
/** Host test meant to run a mobly python binary file from the Android Build system (Soong) */
@OptionClass(alias = "mobly-host")
@@ -217,8 +224,7 @@
}
parFile.setExecutable(true);
try {
- runSingleParFile(parFile.getAbsolutePath(), listener);
- processTestResults(listener, parFile.getName());
+ runSingleParFile(parFile.getAbsolutePath(), parFile.getName(), listener);
} finally {
reportLogs(getLogDir(), listener);
}
@@ -247,7 +253,8 @@
return files;
}
- private void runSingleParFile(String parFilePath, ITestInvocationListener listener) {
+ private void runSingleParFile(
+ String parFilePath, String runName, ITestInvocationListener listener) {
if (mInjectAndroidSerialVar) {
getRunUtil().setEnvVariable(ANDROID_SERIAL_VAR, getDevice().getSerialNumber());
}
@@ -263,60 +270,145 @@
configPath = updateTemplateConfigFile(configFile, mWildcardConfig);
} catch (FileNotFoundException e) {
reportFailure(
- listener,
- mConfigFileName,
- "Couldn't find Mobly config file " + mConfigFileName);
+ listener, runName, "Couldn't find Mobly config file " + mConfigFileName);
+ return;
}
}
- CommandResult result;
- if (isStdLogging()) {
- result =
- getRunUtil()
- .runTimedCmd(
- getTestTimeout(),
- System.out,
- System.err,
- buildCommandLineArray(parFilePath, configPath));
- } else {
- result =
- getRunUtil()
- .runTimedCmd(
- getTestTimeout(),
- buildCommandLineArray(parFilePath, configPath));
+ CommandResult list_result =
+ getRunUtil().runTimedCmd(6000, parFilePath, "--", "--list_tests");
+ if (!CommandStatus.SUCCESS.equals(list_result.getStatus())) {
+ String message;
+ if (CommandStatus.TIMED_OUT.equals(list_result.getStatus())) {
+ message = "Unable to list tests from the python binary: Timed out";
+ } else {
+ message =
+ "Unable to list tests from the python binary\nstdout: "
+ + list_result.getStdout()
+ + "\nstderr: "
+ + list_result.getStderr();
+ }
+ reportFailure(listener, runName, message);
+ return;
}
- if (!CommandStatus.SUCCESS.equals(result.getStatus())) {
- CLog.e(
- "Something went wrong when running the python binary:\nstdout: "
- + "%s\nstderr:%s\nStatus:%s",
- result.getStdout(), result.getStderr(), result.getStatus());
+ // Compute all tests.
+ final String[] all_tests =
+ Arrays.stream(list_result.getStdout().split(System.lineSeparator()))
+ .filter(line -> !line.startsWith("==========>"))
+ .toArray(String[]::new);
+ Stream<String> includedTests = Arrays.stream(all_tests);
+ // Process include filters.
+ String[] includeFilters =
+ getIncludeFilters().stream()
+ .map(filter -> filter.replace("#", "."))
+ .toArray(String[]::new);
+ if (includeFilters.length > 0) {
+ String invalidIncludeFilters =
+ Arrays.stream(includeFilters)
+ .filter(
+ filter ->
+ !Arrays.stream(all_tests)
+ .anyMatch(test -> test.startsWith(filter)))
+ .collect(Collectors.joining(", "));
+ if (!invalidIncludeFilters.isEmpty()) {
+ reportFailure(
+ listener,
+ runName,
+ "Invalid include filters: [" + invalidIncludeFilters + "]");
+ return;
+ }
+ includedTests =
+ includedTests.filter(
+ test ->
+ Arrays.stream(includeFilters)
+ .anyMatch(filter -> test.startsWith(filter)));
}
- }
-
- private void processTestResults(ITestInvocationListener listener, String runName)
- throws HarnessRuntimeException {
- // Convert yaml test summary to xml.
- File yamlSummaryFile = FileUtil.findFile(getLogDir(), MOBLY_TEST_SUMMARY);
- if (yamlSummaryFile == null) {
- throw new HarnessRuntimeException(
- String.format(
- "Fail to find test summary file %s under directory %s",
- MOBLY_TEST_SUMMARY, getLogDir()),
- TestErrorIdentifier.UNEXPECTED_MOBLY_BEHAVIOR);
+ // Process exclude filters.
+ String[] excludeFilters =
+ getExcludeFilters().stream()
+ .map(filter -> filter.replace("#", "."))
+ .toArray(String[]::new);
+ if (excludeFilters.length > 0) {
+ String invalidExcludeFilters =
+ Arrays.stream(excludeFilters)
+ .filter(
+ filter ->
+ !Arrays.stream(all_tests)
+ .anyMatch(test -> test.equals(filter)))
+ .collect(Collectors.joining(", "));
+ if (!invalidExcludeFilters.isEmpty()) {
+ reportFailure(
+ listener,
+ runName,
+ "Invalid exclude filters: [" + invalidExcludeFilters + "]");
+ return;
+ }
+ includedTests =
+ includedTests.filter(
+ test ->
+ !Arrays.stream(excludeFilters)
+ .anyMatch(filter -> test.equals(filter)));
}
-
- MoblyYamlResultParser parser = new MoblyYamlResultParser(listener, runName);
+ // Collect final filtered tests list.
+ Set<String> tests = includedTests.collect(Collectors.toSet());
+ // Start run.
+ long startTime = System.currentTimeMillis();
+ listener.testRunStarted(runName, tests.size());
+ // No test to run, abort early.
+ if (tests.isEmpty()) {
+ listener.testRunEnded(0, new HashMap<String, String>());
+ return;
+ }
+ // Do not pass tests to command line if all included.
+ if (tests.size() == all_tests.length) {
+ tests.clear();
+ }
+ String[] command = buildCommandLineArray(parFilePath, configPath, tests);
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ CompletableFuture<CommandResult> future =
+ CompletableFuture.supplyAsync(
+ () -> {
+ if (isStdLogging()) {
+ return getRunUtil()
+ .runTimedCmd(
+ getTestTimeout(), System.out, System.err, command);
+ }
+ return getRunUtil().runTimedCmd(getTestTimeout(), command);
+ },
+ executor);
+ MoblyYamlResultParser parser = new MoblyYamlResultParser(listener);
+ File yamlSummaryFile = null;
InputStream inputStream = null;
- try {
- inputStream = new FileInputStream(yamlSummaryFile);
- processYamlTestResults(inputStream, parser, listener, runName);
- } catch (FileNotFoundException ex) {
- reportFailure(
- listener,
- runName,
- "Fail processing test results, result file not found.\n" + ex);
- } finally {
+ boolean runFailed = false;
+ while (!future.isDone() && yamlSummaryFile == null) {
+ yamlSummaryFile = FileUtil.findFile(getLogDir(), MOBLY_TEST_SUMMARY);
+ if (yamlSummaryFile != null) {
+ try {
+ inputStream = new FileInputStream(yamlSummaryFile);
+ } catch (FileNotFoundException ex) {
+ listener.testRunFailed(ex.toString());
+ runFailed = true;
+ }
+ }
+ }
+ if (inputStream != null) {
+ while (!future.isDone()) processYamlTestResults(inputStream, parser, listener, runName);
+ if (!processYamlTestResults(inputStream, parser, listener, runName))
+ CLog.e("Did not get a complete summary file from python binary.");
+ runFailed = parser.getRunFailed();
StreamUtil.close(inputStream);
}
+ try {
+ CommandResult result = future.get();
+ if (!CommandStatus.SUCCESS.equals(result.getStatus()) && !runFailed)
+ listener.testRunFailed(result.getStderr());
+ } catch (InterruptedException ex) {
+ listener.testRunFailed(ex.toString());
+ } catch (ExecutionException ex) {
+ listener.testRunFailed(ex.toString());
+ }
+ executor.shutdownNow();
+ listener.testRunEnded(
+ System.currentTimeMillis() - startTime, new HashMap<String, String>());
}
/**
@@ -328,17 +420,19 @@
* @param runName str, the name of the Mobly test binary run.
*/
@VisibleForTesting
- protected void processYamlTestResults(
+ protected boolean processYamlTestResults(
InputStream inputStream,
MoblyYamlResultParser parser,
ITestInvocationListener listener,
String runName) {
try {
- parser.parse(inputStream);
+ return parser.parse(inputStream);
} catch (MoblyYamlResultHandlerFactory.InvalidResultTypeException
+ | IOException
| IllegalAccessException
| InstantiationException ex) {
- reportFailure(listener, runName, "Failed to parse the result file.\n" + ex);
+ CLog.e("Failed to parse the result file.\n" + ex);
+ return false;
}
}
@@ -423,6 +517,8 @@
androidDeviceList.add(deviceMap);
deviceMap.put("serial", devices.get(index).getSerialNumber());
}
+ } else if (androidDeviceValue == null) {
+ CLog.d("No Android device provided.");
} else {
throw new HarnessRuntimeException(
String.format("Unsupported value for AndroidDevice: %s", androidDeviceValue),
@@ -496,6 +592,11 @@
@VisibleForTesting
protected String[] buildCommandLineArray(String filePath, String configPath) {
+ return buildCommandLineArray(filePath, configPath, getIncludeFilters());
+ }
+
+ protected String[] buildCommandLineArray(
+ String filePath, String configPath, Set<String> tests) {
List<String> commandLine = new ArrayList<>();
commandLine.add(filePath);
// TODO(b/166468397): some test binaries are actually a wrapper of Mobly runner and need --
@@ -511,9 +612,9 @@
commandLine.add("--device_serial=" + device.getSerialNumber());
}
commandLine.add("--log_path=" + getLogDirAbsolutePath());
- if (!mIncludeFilters.isEmpty()) {
+ if (!tests.isEmpty()) {
commandLine.add("--tests");
- commandLine.addAll(cleanFilters(mIncludeFilters));
+ commandLine.addAll(cleanFilters(tests));
}
// Add all the other options
commandLine.addAll(getTestOptions());
diff --git a/test_framework/com/android/tradefed/testtype/mobly/MoblyYamlResultParser.java b/test_framework/com/android/tradefed/testtype/mobly/MoblyYamlResultParser.java
index 0d3d4af..c83580b 100644
--- a/test_framework/com/android/tradefed/testtype/mobly/MoblyYamlResultParser.java
+++ b/test_framework/com/android/tradefed/testtype/mobly/MoblyYamlResultParser.java
@@ -23,7 +23,6 @@
import com.android.tradefed.result.proto.TestRecordProto;
import com.android.tradefed.testtype.mobly.IMoblyYamlResultHandler.ITestResult;
import com.android.tradefed.testtype.mobly.MoblyYamlResultHandlerFactory.InvalidResultTypeException;
-import com.android.tradefed.testtype.mobly.MoblyYamlResultSummaryHandler.Summary;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
@@ -31,7 +30,11 @@
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
+import java.io.BufferedReader;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -41,122 +44,122 @@
private static final String TYPE = "Type";
private ImmutableList.Builder<ITestInvocationListener> mListenersBuilder =
new ImmutableList.Builder<>();
- private final String mRunName;
private ImmutableList.Builder<ITestResult> mResultCacheBuilder = new ImmutableList.Builder<>();
- private int mTestCount;
private long mRunStartTime;
private long mRunEndTime;
+ private boolean mEnded;
+ private boolean mRunFailed;
- public MoblyYamlResultParser(ITestInvocationListener listener, String runName) {
+ public MoblyYamlResultParser(ITestInvocationListener listener) {
mListenersBuilder.add(listener);
- mRunName = runName;
}
- public void parse(InputStream inputStream)
- throws InvalidResultTypeException, IllegalAccessException, InstantiationException {
- Yaml yaml = new Yaml(new SafeConstructor());
- for (Object doc : yaml.loadAll(inputStream)) {
- Map<String, Object> docMap = (Map<String, Object>) doc;
- mResultCacheBuilder.add(parseDocumentMap(docMap));
+ public boolean parse(InputStream inputStream)
+ throws InvalidResultTypeException,
+ IllegalAccessException,
+ InstantiationException,
+ IOException {
+ InputStreamReader isr = new InputStreamReader(inputStream);
+ BufferedReader in = new BufferedReader(isr);
+ while (in.ready() == true) {
+ String line = null;
+ String yaml_string = "";
+ while (true) {
+ line = in.readLine();
+ if (line == null) continue;
+ if (line.equals("...")) break;
+ yaml_string = yaml_string + line + "\n";
+ }
+ Yaml yaml = new Yaml(new SafeConstructor());
+ ArrayList<ITestResult> resultCache = new ArrayList<ITestResult>();
+ for (Object doc : yaml.loadAll(yaml_string)) {
+ Map<String, Object> docMap = (Map<String, Object>) doc;
+ resultCache.add(parseDocumentMap(docMap));
+ }
+ reportToListeners(mListenersBuilder.build(), resultCache);
}
- reportToListeners(mListenersBuilder.build(), mResultCacheBuilder.build());
+ return mEnded;
+ }
+
+ public boolean getRunFailed() {
+ return mRunFailed;
}
@VisibleForTesting
protected ITestResult parseDocumentMap(Map<String, Object> docMap)
throws InvalidResultTypeException, IllegalAccessException, InstantiationException {
- LogUtil.CLog.i("Parsed object: %s", docMap.toString());
+ LogUtil.CLog.d("Parsed object: %s", docMap.toString());
String docType = String.valueOf(docMap.get(TYPE));
- LogUtil.CLog.d("Parsing result type: %s", docType);
+ LogUtil.CLog.v("Parsing result type: %s", docType);
IMoblyYamlResultHandler resultHandler =
new MoblyYamlResultHandlerFactory().getHandler(docType);
- ITestResult testResult = resultHandler.handle(docMap);
- if ("Summary".equals(docType)) {
- mTestCount = ((Summary) testResult).getExecuted() + ((Summary) testResult).getSkipped();
- }
- return testResult;
+ return resultHandler.handle(docMap);
}
@VisibleForTesting
protected void reportToListeners(
List<ITestInvocationListener> listeners,
List<IMoblyYamlResultHandler.ITestResult> resultCache) {
- for (ITestInvocationListener listener : listeners) {
- listener.testRunStarted(mRunName, mTestCount);
- }
- try {
- boolean abort = false;
- for (IMoblyYamlResultHandler.ITestResult result : resultCache) {
- if (abort) {
- break;
- }
- switch (result.getType()) {
- case RECORD:
- MoblyYamlResultRecordHandler.Record record =
- (MoblyYamlResultRecordHandler.Record) result;
- TestDescription testDescription =
- new TestDescription(record.getTestClass(), record.getTestName());
- FailureDescription failureDescription =
- FailureDescription.create(
- record.getStackTrace(),
- TestRecordProto.FailureStatus.TEST_FAILURE);
- if (MoblyYamlResultRecordHandler.RecordResult.ERROR.equals(
+ for (IMoblyYamlResultHandler.ITestResult result : resultCache) {
+ switch (result.getType()) {
+ case RECORD:
+ MoblyYamlResultRecordHandler.Record record =
+ (MoblyYamlResultRecordHandler.Record) result;
+ TestDescription testDescription =
+ new TestDescription(record.getTestClass(), record.getTestName());
+ FailureDescription failureDescription =
+ FailureDescription.create(
+ record.getStackTrace(),
+ TestRecordProto.FailureStatus.TEST_FAILURE);
+ if (MoblyYamlResultRecordHandler.RecordResult.ERROR.equals(
+ record.getResult())) {
+ // Non-test failure reports indicates some early failure so we fail the run
+ if (!testDescription.getTestName().startsWith("test_")) {
+ for (ITestInvocationListener listener : listeners) {
+ listener.testRunFailed(failureDescription);
+ }
+ mRunFailed = true;
+ continue;
+ }
+ }
+ mRunStartTime =
+ mRunStartTime == 0L
+ ? record.getBeginTime()
+ : Math.min(mRunStartTime, record.getBeginTime());
+ mRunEndTime = Math.max(mRunEndTime, record.getEndTime());
+ for (ITestInvocationListener listener : listeners) {
+ listener.testStarted(testDescription, record.getBeginTime());
+ if (MoblyYamlResultRecordHandler.RecordResult.SKIP.equals(
record.getResult())) {
- // Setup_class indicates some early failure so we stop parsing
- if (testDescription.getTestName().equals("setup_class")) {
- for (ITestInvocationListener listener : listeners) {
- listener.testRunFailed(failureDescription);
- }
- abort = true;
- break;
- }
+ listener.testIgnored(testDescription);
+ } else if (!MoblyYamlResultRecordHandler.RecordResult.PASS.equals(
+ record.getResult())) {
+ listener.testFailed(testDescription, failureDescription);
}
- mRunStartTime =
- mRunStartTime == 0L
- ? record.getBeginTime()
- : Math.min(mRunStartTime, record.getBeginTime());
- mRunEndTime = Math.max(mRunEndTime, record.getEndTime());
- for (ITestInvocationListener listener : listeners) {
- listener.testStarted(testDescription, record.getBeginTime());
- if (MoblyYamlResultRecordHandler.RecordResult.SKIP.equals(
- record.getResult())) {
- listener.testIgnored(testDescription);
- } else if (!MoblyYamlResultRecordHandler.RecordResult.PASS.equals(
- record.getResult())) {
- listener.testFailed(testDescription, failureDescription);
- }
- listener.testEnded(
- testDescription,
- record.getEndTime(),
- new HashMap<String, String>());
- }
- break;
- case USER_DATA:
- long timestamp =
- ((MoblyYamlResultUserDataHandler.UserData) result).getTimeStamp();
- mRunStartTime =
- mRunStartTime == 0L
- ? timestamp
- : Math.min(mRunStartTime, timestamp);
- break;
- case CONTROLLER_INFO:
- mRunEndTime =
- Math.max(
- mRunEndTime,
- ((MoblyYamlResultControllerInfoHandler.ControllerInfo)
- result)
- .getTimeStamp());
- break;
- case TEST_NAME_LIST:
- // Do nothing
- break;
- default:
- // Do nothing
- }
- }
- } finally {
- for (ITestInvocationListener listener : listeners) {
- listener.testRunEnded(mRunEndTime - mRunStartTime, new HashMap<String, String>());
+ listener.testEnded(
+ testDescription,
+ record.getEndTime(),
+ new HashMap<String, String>());
+ }
+ break;
+ case USER_DATA:
+ long timestamp =
+ ((MoblyYamlResultUserDataHandler.UserData) result).getTimeStamp();
+ mRunStartTime =
+ mRunStartTime == 0L ? timestamp : Math.min(mRunStartTime, timestamp);
+ break;
+ case CONTROLLER_INFO:
+ mRunEndTime =
+ Math.max(
+ mRunEndTime,
+ ((MoblyYamlResultControllerInfoHandler.ControllerInfo) result)
+ .getTimeStamp());
+ break;
+ case SUMMARY:
+ mEnded = true;
+ break;
+ default:
+ // Do nothing
}
}
}