blob: 7026b1da8bef0891f8f2e0a38e0dff8cc035fd35 [file] [log] [blame]
/*
* Copyright 2017 The Bazel Authors. All rights reserved.
*
* 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.google.idea.blaze.base.command.buildresult;
import static com.google.common.truth.Truth.assertThat;
import static com.google.idea.common.guava.GuavaHelper.toImmutableList;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.idea.blaze.base.model.primitives.Kind;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.run.testlogs.BlazeTestResult;
import com.google.idea.blaze.base.run.testlogs.BlazeTestResult.TestStatus;
import com.google.idea.blaze.base.run.testlogs.BlazeTestResults;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEvent;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.TargetCompletedId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.TargetConfiguredId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.TestResultId;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.NamedSetOfFiles;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TargetComplete;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TargetConfigured;
import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TestResult;
import com.intellij.openapi.vfs.LocalFileSystem;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link BuildEventProtocolOutputReader}. */
@RunWith(JUnit4.class)
public class BuildEventProtocolOutputReaderTest {
@Rule public TemporaryFolder tmpFolder = new TemporaryFolder();
@Test
public void parseAllOutputFilenames_singleFileEvent_returnsAllFilenames() throws IOException {
ImmutableList<String> filePaths =
ImmutableList.of(
"/usr/local/lib/File.py", "/usr/bin/python2.7", "/usr/local/home/script.sh");
BuildEvent.Builder event = BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(filePaths));
ImmutableList<File> parsedFilenames =
BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(event), path -> true);
assertThat(parsedFilenames)
.containsExactly(filePaths.stream().map(File::new).toArray())
.inOrder();
}
@Test
public void parseAllOutputFilenamesWithFilter_singleFileEvent_returnsFilteredFilenames()
throws IOException {
Predicate<String> filter = path -> path.endsWith(".py");
ImmutableList<String> filePaths =
ImmutableList.of(
"/usr/local/lib/File.py", "/usr/bin/python2.7", "/usr/local/home/script.sh");
BuildEvent.Builder event = BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(filePaths));
ImmutableList<File> parsedFilenames =
BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(event), filter);
assertThat(parsedFilenames).containsExactly(new File("/usr/local/lib/File.py"));
}
@Test
public void parseAllOutputFilenames_nonFileEvent_returnsEmptyList() throws IOException {
BuildEvent.Builder targetFinishedEvent =
BuildEvent.newBuilder()
.setCompleted(BuildEventStreamProtos.TargetComplete.getDefaultInstance());
ImmutableList<File> parsedFilenames =
BuildEventProtocolOutputReader.parseAllOutputFilenames(
asInputStream(targetFinishedEvent), path -> true);
assertThat(parsedFilenames).isEmpty();
}
@Test
public void parseAllOutputFilenames_streamWithOneFileEvent_returnsAllFilenames()
throws IOException {
ImmutableList<String> filePaths =
ImmutableList.of(
"/usr/local/lib/Provider.java",
"/usr/local/home/Executor.java",
"/google/code/script.sh");
List<BuildEvent.Builder> events =
ImmutableList.of(
BuildEvent.newBuilder()
.setStarted(BuildEventStreamProtos.BuildStarted.getDefaultInstance()),
BuildEvent.newBuilder()
.setProgress(BuildEventStreamProtos.Progress.getDefaultInstance()),
BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(filePaths)));
ImmutableList<File> parsedFilenames =
BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(events), path -> true);
assertThat(parsedFilenames)
.containsExactly(filePaths.stream().map(File::new).toArray())
.inOrder();
}
@Test
public void parseAllOutputFilenames_streamWithMultipleFileEvents_returnsAllFilenames()
throws IOException {
ImmutableList<String> fileSet1 =
ImmutableList.of(
"/usr/local/lib/Provider.java",
"/usr/local/home/Executor.java",
"/google/code/script.sh");
ImmutableList<String> fileSet2 =
ImmutableList.of(
"/usr/local/code/ParserTest.java",
"/usr/local/code/action_output.bzl",
"/usr/genfiles/BUILD.bazel");
List<BuildEvent.Builder> events =
ImmutableList.of(
BuildEvent.newBuilder()
.setStarted(BuildEventStreamProtos.BuildStarted.getDefaultInstance()),
BuildEvent.newBuilder()
.setProgress(BuildEventStreamProtos.Progress.getDefaultInstance()),
BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(fileSet1)),
BuildEvent.newBuilder()
.setProgress(BuildEventStreamProtos.Progress.getDefaultInstance()),
BuildEvent.newBuilder().setNamedSetOfFiles(setOfFiles(fileSet2)),
BuildEvent.newBuilder()
.setCompleted(BuildEventStreamProtos.TargetComplete.getDefaultInstance()));
ImmutableList<File> allFiles =
ImmutableList.<String>builder()
.addAll(fileSet1)
.addAll(fileSet2)
.build()
.stream()
.map(File::new)
.collect(toImmutableList());
ImmutableList<File> parsedFilenames =
BuildEventProtocolOutputReader.parseAllOutputFilenames(asInputStream(events), path -> true);
assertThat(parsedFilenames).containsExactlyElementsIn(allFiles).inOrder();
}
@Test
public void testStatusEnum_handlesAllProtoEnumValues() {
Set<String> protoValues =
EnumSet.allOf(BuildEventStreamProtos.TestStatus.class)
.stream()
.map(Enum::name)
.collect(Collectors.toSet());
protoValues.remove(BuildEventStreamProtos.TestStatus.UNRECOGNIZED.name());
Set<String> handledValues =
EnumSet.allOf(TestStatus.class).stream().map(Enum::name).collect(Collectors.toSet());
assertThat(protoValues).containsExactlyElementsIn(handledValues);
}
@Test
public void parseTestResults_singleEvent_returnsTestResults() throws IOException {
Label label = Label.create("//java/com/google:unit_tests");
BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
BuildEvent.Builder event = testResultEvent(label.toString(), status, filePaths);
BlazeTestResults results =
BuildEventProtocolOutputReader.parseTestResults(asInputStream(event));
assertThat(results.perTargetResults.keySet()).containsExactly(label);
assertThat(results.perTargetResults.get(label)).hasSize(1);
BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
assertThat(result.getOutputXmlFiles())
.containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
}
@Test
public void parseTestResults_singleTestEventWithTargetConfigured_resultsIncludeTargetKind()
throws IOException {
Label label = Label.create("//java/com/google:unit_tests");
BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
InputStream events =
asInputStream(
targetConfiguredEvent(label.toString(), "java_test rule"),
testResultEvent(label.toString(), status, filePaths));
BlazeTestResults results = BuildEventProtocolOutputReader.parseTestResults(events);
assertThat(results.perTargetResults.keySet()).containsExactly(label);
assertThat(results.perTargetResults.get(label)).hasSize(1);
BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
assertThat(result.getTargetKind()).isEqualTo(Kind.JAVA_TEST);
assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
assertThat(result.getOutputXmlFiles())
.containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
}
@Test
public void parseTestResults_singleTestEventWithTargetCompleted_resultsIncludeTargetKind()
throws IOException {
Label label = Label.create("//java/com/google:unit_tests");
BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
InputStream events =
asInputStream(
targetCompletedEvent(label.toString(), "java_test rule"),
testResultEvent(label.toString(), status, filePaths));
BlazeTestResults results = BuildEventProtocolOutputReader.parseTestResults(events);
assertThat(results.perTargetResults.keySet()).containsExactly(label);
assertThat(results.perTargetResults.get(label)).hasSize(1);
BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
assertThat(result.getTargetKind()).isEqualTo(Kind.JAVA_TEST);
assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
assertThat(result.getOutputXmlFiles())
.containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
}
@Test
public void parseTestResults_multipleTargetKindSources_resultsIncludeCorrectTargetKind()
throws IOException {
Label label = Label.create("//java/com/google:unit_tests");
BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
ImmutableList<String> filePaths = ImmutableList.of("/usr/local/tmp/_cache/test_result.xml");
InputStream events =
asInputStream(
targetConfiguredEvent(label.toString(), "java_test rule"),
targetCompletedEvent(label.toString(), "java_test rule"),
testResultEvent(label.toString(), status, filePaths));
BlazeTestResults results = BuildEventProtocolOutputReader.parseTestResults(events);
assertThat(results.perTargetResults.keySet()).containsExactly(label);
assertThat(results.perTargetResults.get(label)).hasSize(1);
BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
assertThat(result.getTargetKind()).isEqualTo(Kind.JAVA_TEST);
assertThat(result.getTestStatus()).isEqualTo(TestStatus.FAILED);
assertThat(result.getOutputXmlFiles())
.containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
}
@Test
public void parseTestResults_singleEvent_ignoresNonXmlOutputFiles() throws IOException {
Label label = Label.create("//java/com/google:unit_tests");
BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.FAILED;
ImmutableList<String> filePaths =
ImmutableList.of(
"/usr/local/tmp/_cache/test_result.xml",
"/usr/local/tmp/_cache/test_result.log",
"/usr/local/tmp/other_output_file");
BuildEvent.Builder event = testResultEvent(label.toString(), status, filePaths);
BlazeTestResults results =
BuildEventProtocolOutputReader.parseTestResults(asInputStream(event));
BlazeTestResult result = results.perTargetResults.get(label).iterator().next();
assertThat(result.getOutputXmlFiles())
.containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
}
@Test
public void parseTestResults_singleTargetWithMultipleEvents_returnsTestResults()
throws IOException {
Label label = Label.create("//java/com/google:unit_tests");
BuildEventStreamProtos.TestStatus status = BuildEventStreamProtos.TestStatus.PASSED;
BuildEvent.Builder shard1 =
testResultEvent(
label.toString(), status, ImmutableList.of("/usr/local/tmp/_cache/shard1_of_2.xml"));
BuildEvent.Builder shard2 =
testResultEvent(
label.toString(), status, ImmutableList.of("/usr/local/tmp/_cache/shard2_of_2.xml"));
BlazeTestResults results =
BuildEventProtocolOutputReader.parseTestResults(asInputStream(shard1, shard2));
assertThat(results.perTargetResults).hasSize(2);
Collection<BlazeTestResult> targetResults = results.perTargetResults.get(label);
assertThat(targetResults)
.containsExactly(
BlazeTestResult.create(
label,
null,
TestStatus.PASSED,
ImmutableSet.of(new File("/usr/local/tmp/_cache/shard1_of_2.xml"))),
BlazeTestResult.create(
label,
null,
TestStatus.PASSED,
ImmutableSet.of(new File("/usr/local/tmp/_cache/shard2_of_2.xml"))));
}
@Test
public void parseTestResults_multipleEvents_returnsAllResults() throws IOException {
BuildEvent.Builder test1 =
testResultEvent(
"//java/com/google:Test1",
BuildEventStreamProtos.TestStatus.PASSED,
ImmutableList.of("/usr/local/tmp/_cache/test_result.xml"));
BuildEvent.Builder test2 =
testResultEvent(
"//java/com/google:Test2",
BuildEventStreamProtos.TestStatus.INCOMPLETE,
ImmutableList.of("/usr/local/tmp/_cache/second_result.xml"));
BlazeTestResults results =
BuildEventProtocolOutputReader.parseTestResults(asInputStream(test1, test2));
assertThat(results.perTargetResults).hasSize(2);
assertThat(results.perTargetResults.get(Label.create("//java/com/google:Test1"))).hasSize(1);
assertThat(results.perTargetResults.get(Label.create("//java/com/google:Test2"))).hasSize(1);
BlazeTestResult result1 =
results.perTargetResults.get(Label.create("//java/com/google:Test1")).iterator().next();
assertThat(result1.getTestStatus()).isEqualTo(TestStatus.PASSED);
assertThat(result1.getOutputXmlFiles())
.containsExactly(new File("/usr/local/tmp/_cache/test_result.xml"));
BlazeTestResult result2 =
results.perTargetResults.get(Label.create("//java/com/google:Test2")).iterator().next();
assertThat(result2.getTestStatus()).isEqualTo(TestStatus.INCOMPLETE);
assertThat(result2.getOutputXmlFiles())
.containsExactly(new File("/usr/local/tmp/_cache/second_result.xml"));
}
private static InputStream asInputStream(BuildEvent.Builder... events) throws IOException {
return asInputStream(Arrays.asList(events));
}
private static InputStream asInputStream(Iterable<BuildEvent.Builder> events) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
for (BuildEvent.Builder event : events) {
event.build().writeDelimitedTo(output);
}
return new ByteArrayInputStream(output.toByteArray());
}
private static BuildEvent.Builder targetConfiguredEvent(String label, String targetKind) {
return BuildEvent.newBuilder()
.setId(
BuildEventId.newBuilder()
.setTargetConfigured(TargetConfiguredId.newBuilder().setLabel(label)))
.setConfigured(TargetConfigured.newBuilder().setTargetKind(targetKind));
}
private static BuildEvent.Builder targetCompletedEvent(String label, String targetKind) {
return BuildEvent.newBuilder()
.setId(
BuildEventId.newBuilder()
.setTargetCompleted(TargetCompletedId.newBuilder().setLabel(label)))
.setCompleted(TargetComplete.newBuilder().setTargetKind(targetKind));
}
private static BuildEvent.Builder testResultEvent(
String label, BuildEventStreamProtos.TestStatus status, List<String> filePaths) {
return BuildEvent.newBuilder()
.setId(BuildEventId.newBuilder().setTestResult(TestResultId.newBuilder().setLabel(label)))
.setTestResult(
TestResult.newBuilder()
.setStatus(status)
.addAllTestActionOutput(
filePaths
.stream()
.map(BuildEventProtocolOutputReaderTest::toEventFile)
.collect(toImmutableList())));
}
private static NamedSetOfFiles setOfFiles(List<String> filePaths) {
return NamedSetOfFiles.newBuilder()
.addAllFiles(
filePaths
.stream()
.map(BuildEventProtocolOutputReaderTest::toEventFile)
.collect(toImmutableList()))
.build();
}
private static BuildEventStreamProtos.File toEventFile(String filePath) {
return BuildEventStreamProtos.File.newBuilder().setUri(fileUrl(filePath)).build();
}
private static String fileUrl(String filePath) {
return LocalFileSystem.PROTOCOL_PREFIX + filePath;
}
}