aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Eduardo Colaco <eduardocolaco@google.com>2016-11-03 15:33:47 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2016-11-03 16:12:39 +0000
commit8d8abe46bd7ab0c87beb31d97c9185760d762d79 (patch)
tree197a26794eddd4b59878b199c1914bc751f5a776
parent38e54ac14e69113e9790ce9a526784e0f18e4b6e (diff)
Writes a machine readable representation of BuildEvents to a file (varint delimited).
Adds --experimental_build_event_binary_file option that enables varint delimited proto loggging to the specified file path Adds varint delimited BuildEventStreamTransport and BuildEventStreamerModule Adds BuildEventStreamerModule for configuring and setting up BuildEventStreamer and its associated BuildEventTransports. Adds BuildEventTransportFactory which creates a Set of transports from command options. Moves BuildEventStreamer configuration from BlazeCommandDispatcher and BuildEventStreamerModule -- Change-Id: If71f2b58654879c2509206da47e6d1a846bf397f Reviewed-on: https://bazel-review.googlesource.com/#/c/7010/ MOS_MIGRATED_REVID=138073726
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/BazelMain.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD2
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java47
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java48
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java74
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandEventHandler.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModule.java79
-rw-r--r--src/test/java/com/google/devtools/build/lib/BUILD2
-rw-r--r--src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD24
-rw-r--r--src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransportTest.java90
-rw-r--r--src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactoryTest.java130
-rw-r--r--src/test/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransportTest.java91
-rw-r--r--src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModuleTest.java136
-rwxr-xr-xsrc/test/shell/integration/build_event_stream_test.sh10
16 files changed, 741 insertions, 23 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelMain.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelMain.java
index 29e598659d..924bffd339 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelMain.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelMain.java
@@ -48,6 +48,7 @@ public final class BazelMain {
com.google.devtools.build.lib.standalone.StandaloneModule.class,
com.google.devtools.build.lib.sandbox.SandboxModule.class,
com.google.devtools.build.lib.runtime.BuildSummaryStatsModule.class,
+ com.google.devtools.build.lib.runtime.BuildEventStreamerModule.class,
com.google.devtools.build.lib.bazel.rules.BazelRulesModule.class);
public static void main(String[] args) {
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
index 618abca496..11b6c22ccc 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
@@ -11,6 +11,8 @@ java_library(
deps = [
"//src/main/java/com/google/devtools/build/lib:buildeventstream",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
+ "//src/main/java/com/google/devtools/common/options",
+ "//third_party:guava",
"//third_party/protobuf",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java
new file mode 100644
index 0000000000..c0f341e2eb
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java
@@ -0,0 +1,47 @@
+// Copyright 2016 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.devtools.build.lib.buildeventstream.transports;
+
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * A simple {@link BuildEventTransport} that writes varint delimited binary representation of event
+ * {@link BuildEvent} protocol-buffers to a file. Files written by this Transport can be read by
+ * successive calls of {code BuildEvent.Builder#mergeDelimitedFrom(InputStream)} (or the static
+ * method {@code BuildEvent.parseDelimitedFrom(InputStream)}).
+ */
+public final class BinaryFormatFileTransport implements BuildEventTransport {
+ private final BufferedOutputStream out;
+
+ public BinaryFormatFileTransport(String path) throws IOException {
+ this.out = new BufferedOutputStream(new FileOutputStream(new File(path)));
+ }
+
+ @Override
+ public synchronized void sendBuildEvent(BuildEvent event) throws IOException {
+ event.asStreamProto().writeDelimitedTo(out);
+ out.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ out.close();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java
new file mode 100644
index 0000000000..c4cb96a36d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java
@@ -0,0 +1,48 @@
+// Copyright 2016 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.devtools.build.lib.buildeventstream.transports;
+
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionsBase;
+
+/** Options used to configure BuildEventStreamer and its BuildEventTransports. */
+public class BuildEventStreamOptions extends OptionsBase {
+
+ @Option(
+ name = "experimental_build_event_text_file",
+ defaultValue = "",
+ category = "hidden",
+ help = "If non-empty, write a textual representation of the build event protocol to that file"
+ )
+ public String buildEventTextFile;
+
+ @Option(
+ name = "experimental_build_event_binary_file",
+ defaultValue = "",
+ category = "hidden",
+ help =
+ "If non-empty, write a varint delimited binary representation of representation of the"
+ + " build event protocol to that file."
+ )
+ public String buildEventBinaryFile;
+
+ public String getBuildEventTextFile() {
+ return buildEventTextFile;
+ }
+
+ public String getBuildEventBinaryFile() {
+ return buildEventBinaryFile;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java
new file mode 100644
index 0000000000..f456b189d6
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java
@@ -0,0 +1,74 @@
+// Copyright 2016 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.devtools.build.lib.buildeventstream.transports;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
+import java.io.IOException;
+
+/** Factory used to create a Set of BuildEventTransports from BuildEventStreamOptions. */
+public enum BuildEventTransportFactory {
+ TEXT_TRANSPORT {
+ @Override
+ protected boolean enabled(BuildEventStreamOptions options) {
+ return !isNullOrEmpty(options.getBuildEventTextFile());
+ }
+
+ @Override
+ protected BuildEventTransport create(BuildEventStreamOptions options) throws IOException {
+ return new TextFormatFileTransport(options.getBuildEventTextFile());
+ }
+ },
+
+ BINARY_TRANSPORT {
+ @Override
+ protected boolean enabled(BuildEventStreamOptions options) {
+ return !isNullOrEmpty(options.getBuildEventBinaryFile());
+ }
+
+ @Override
+ protected BuildEventTransport create(BuildEventStreamOptions options) throws IOException {
+ return new BinaryFormatFileTransport(options.getBuildEventBinaryFile());
+ }
+ };
+
+ /**
+ * Creates a {@link ImmutableSet} of {@link BuildEventTransport} based on the specified {@link
+ * BuildEventStreamOptions}.
+ *
+ * @param options Options used configure and create the returned BuildEventTransports.
+ * @return A {@link ImmutableSet} of BuildEventTransports. This set may be empty.
+ * @throws IOException Exception propagated from a {@link BuildEventTransport} creation failure.
+ */
+ public static ImmutableSet<BuildEventTransport> createFromOptions(BuildEventStreamOptions options)
+ throws IOException {
+ Builder<BuildEventTransport> buildEventTransportsBuilder = ImmutableSet.builder();
+ for (BuildEventTransportFactory transportFactory : BuildEventTransportFactory.values()) {
+ if (transportFactory.enabled(options)) {
+ buildEventTransportsBuilder.add(transportFactory.create(options));
+ }
+ }
+ return buildEventTransportsBuilder.build();
+ }
+
+ /** Returns true if this factory BuildEventTransport is enabled by the specified options. */
+ protected abstract boolean enabled(BuildEventStreamOptions options);
+
+ /** Creates a BuildEventTransport from the specified options. */
+ protected abstract BuildEventTransport create(BuildEventStreamOptions options) throws IOException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
index 87adbd7374..c16994f0d4 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
@@ -27,8 +27,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.io.Flushables;
-import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
-import com.google.devtools.build.lib.buildeventstream.transports.TextFormatFileTransport;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Reporter;
@@ -455,18 +453,6 @@ public class BlazeCommandDispatcher {
Reporter reporter = env.getReporter();
reporter.addHandler(handler);
env.getEventBus().register(handler);
- if (eventHandlerOptions.buildEventTextFile.length() > 0) {
- try {
- BuildEventStreamer streamer =
- new BuildEventStreamer(
- ImmutableSet.<BuildEventTransport>of(
- new TextFormatFileTransport(eventHandlerOptions.buildEventTextFile)));
- reporter.addHandler(streamer);
- env.getEventBus().register(streamer);
- } catch (IOException e) {
- return ExitCode.LOCAL_ENVIRONMENTAL_ERROR.getNumericExitCode();
- }
- }
// We register an ANSI-allowing handler associated with {@code handler} so that ANSI control
// codes can be re-introduced later even if blaze is invoked with --color=no. This is useful
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandEventHandler.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandEventHandler.java
index 7ab613fc3f..601f37f5fd 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandEventHandler.java
@@ -168,15 +168,6 @@ public class BlazeCommandEventHandler implements EventHandler {
)
public int experimentalUiActionsShown;
-
- @Option(
- name = "experimental_build_event_text_file",
- defaultValue = "",
- category = "hidden",
- help = "If non-empty, write a textual representation of the build event protocol to that file"
- )
- public String buildEventTextFile;
-
public boolean useColor() {
return useColorEnum == UseColor.YES || (useColorEnum == UseColor.AUTO && isATty);
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java b/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java
index 819e2f3c32..812d223449 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.runtime;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.eventbus.Subscribe;
import com.google.devtools.build.lib.actions.ActionExecutedEvent;
@@ -156,4 +158,9 @@ public class BuildEventStreamer implements EventHandler {
post(event);
}
+
+ @VisibleForTesting
+ ImmutableSet<BuildEventTransport> getTransports() {
+ return ImmutableSet.copyOf(transports);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModule.java b/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModule.java
new file mode 100644
index 0000000000..b405c79b38
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModule.java
@@ -0,0 +1,79 @@
+// Copyright 2016 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.devtools.build.lib.runtime;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.devtools.build.lib.buildeventstream.transports.BuildEventTransportFactory.createFromOptions;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
+import com.google.devtools.build.lib.buildeventstream.transports.BuildEventStreamOptions;
+import com.google.devtools.build.lib.util.AbruptExitException;
+import com.google.devtools.build.lib.util.ExitCode;
+import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsProvider;
+import java.io.IOException;
+
+
+/** Module responsible for configuring BuildEventStreamer and transports. */
+public class BuildEventStreamerModule extends BlazeModule {
+
+ private CommandEnvironment commandEnvironment;
+
+ @Override
+ public Iterable<Class<? extends OptionsBase>> getCommandOptions(Command command) {
+ return ImmutableList.<Class<? extends OptionsBase>>of(BuildEventStreamOptions.class);
+ }
+
+ @Override
+ public void beforeCommand(Command command, CommandEnvironment commandEnvironment)
+ throws AbruptExitException {
+ this.commandEnvironment = commandEnvironment;
+ }
+
+ @Override
+ public void handleOptions(OptionsProvider optionsProvider) {
+ checkState(commandEnvironment != null, "Methods called out of order");
+ Optional<BuildEventStreamer> streamer =
+ tryCreateStreamer(optionsProvider, commandEnvironment.getBlazeModuleEnvironment());
+ if (streamer.isPresent()) {
+ commandEnvironment.getReporter().addHandler(streamer.get());
+ commandEnvironment.getEventBus().register(streamer.get());
+ }
+ }
+
+ @VisibleForTesting
+ Optional<BuildEventStreamer> tryCreateStreamer(
+ OptionsProvider optionsProvider, ModuleEnvironment moduleEnvironment) {
+ try {
+ BuildEventStreamOptions besOptions =
+ checkNotNull(
+ optionsProvider.getOptions(BuildEventStreamOptions.class),
+ "Could not get BuildEventStreamOptions");
+ ImmutableSet<BuildEventTransport> buildEventTransports = createFromOptions(besOptions);
+ if (!buildEventTransports.isEmpty()) {
+ BuildEventStreamer streamer = new BuildEventStreamer(buildEventTransports);
+ return Optional.of(streamer);
+ }
+ } catch (IOException e) {
+ moduleEnvironment.exit(new AbruptExitException(ExitCode.LOCAL_ENVIRONMENTAL_ERROR, e));
+ }
+ return Optional.absent();
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index f7ae7d599a..4c1f7b226d 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -27,6 +27,7 @@ filegroup(
"//src/test/java/com/google/devtools/build/lib/skyframe:srcs",
"//src/test/java/com/google/devtools/build/lib/rules/repository:srcs",
"//src/test/java/com/google/devtools/build/lib/bazel/repository:srcs",
+ "//src/test/java/com/google/devtools/build/lib/buildeventstream/transports:srcs",
"//src/test/java/com/google/devtools/build/lib/buildtool:srcs",
],
visibility = ["//src:__pkg__"],
@@ -1000,6 +1001,7 @@ java_test(
"//src/main/java/com/google/devtools/build/lib:vfs",
"//src/main/java/com/google/devtools/build/lib/actions",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
+ "//src/main/java/com/google/devtools/build/lib/buildeventstream/transports",
"//src/main/java/com/google/devtools/common/options",
"//src/main/protobuf:invocation_policy_java_proto",
"//src/main/protobuf:test_status_java_proto",
diff --git a/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
new file mode 100644
index 0000000000..6472d8aa21
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
@@ -0,0 +1,24 @@
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+ visibility = ["//src/test/java/com/google/devtools/build/lib:__pkg__"],
+)
+
+java_test(
+ name = "BuildEventTransportTest",
+ srcs = glob(["*.java"]),
+ test_class = "com.google.devtools.build.lib.AllTests",
+ runtime_deps = ["//src/test/java/com/google/devtools/build/lib:test_runner"],
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:buildeventstream",
+ "//src/main/java/com/google/devtools/build/lib:runtime",
+ "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
+ "//src/main/java/com/google/devtools/build/lib/buildeventstream/transports",
+ "//src/test/java/com/google/devtools/build/lib:packages_testutil",
+ "//third_party:guava",
+ "//third_party:junit4",
+ "//third_party:mockito",
+ "//third_party:truth",
+ "//third_party/protobuf",
+ ],
+)
diff --git a/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransportTest.java b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransportTest.java
new file mode 100644
index 0000000000..e241e8410c
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransportTest.java
@@ -0,0 +1,90 @@
+// Copyright 2016 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.devtools.build.lib.buildeventstream.transports;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildStarted;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.Progress;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TargetComplete;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/** Tests {@link BinaryFormatFileTransport}. **/
+@RunWith(JUnit4.class)
+public class BinaryFormatFileTransportTest {
+
+ @Rule public TemporaryFolder tmp = new TemporaryFolder();
+
+ @Mock public BuildEvent buildEvent;
+
+ @Before
+ public void initMocks() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @After
+ public void validateMocks() {
+ Mockito.validateMockitoUsage();
+ }
+
+ @Test
+ public void testCreatesFileAndWritesProtoTextFormat() throws IOException {
+ File output = tmp.newFile();
+
+ BuildEventStreamProtos.BuildEvent started =
+ BuildEventStreamProtos.BuildEvent.newBuilder()
+ .setStarted(BuildStarted.newBuilder().setCommand("build"))
+ .build();
+ when(buildEvent.asStreamProto()).thenReturn(started);
+ BinaryFormatFileTransport transport = new BinaryFormatFileTransport(output.getAbsolutePath());
+ transport.sendBuildEvent(buildEvent);
+
+ BuildEventStreamProtos.BuildEvent progress =
+ BuildEventStreamProtos.BuildEvent.newBuilder().setProgress(Progress.newBuilder()).build();
+ when(buildEvent.asStreamProto()).thenReturn(progress);
+ transport.sendBuildEvent(buildEvent);
+
+ BuildEventStreamProtos.BuildEvent completed =
+ BuildEventStreamProtos.BuildEvent.newBuilder()
+ .setCompleted(TargetComplete.newBuilder().setSuccess(true))
+ .build();
+ when(buildEvent.asStreamProto()).thenReturn(completed);
+ transport.sendBuildEvent(buildEvent);
+
+ transport.close();
+ try (InputStream in = new FileInputStream(output)) {
+ assertThat(BuildEventStreamProtos.BuildEvent.parseDelimitedFrom(in)).isEqualTo(started);
+ assertThat(BuildEventStreamProtos.BuildEvent.parseDelimitedFrom(in)).isEqualTo(progress);
+ assertThat(BuildEventStreamProtos.BuildEvent.parseDelimitedFrom(in)).isEqualTo(completed);
+ assertThat(in.available()).isEqualTo(0);
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactoryTest.java b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactoryTest.java
new file mode 100644
index 0000000000..8d4aa520db
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactoryTest.java
@@ -0,0 +1,130 @@
+// Copyright 2016 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.devtools.build.lib.buildeventstream.transports;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildStarted;
+import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
+import java.io.File;
+import java.io.IOException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/** Tests {@link BuildEventTransportFactory}. **/
+@RunWith(JUnit4.class)
+public class BuildEventTransportFactoryTest {
+
+ private static final Function<Object, Class<?>> GET_CLASS =
+ new Function<Object, Class<?>>() {
+ @Override
+ public Class<?> apply(Object o) {
+ return o.getClass();
+ }
+ };
+
+ private static final BuildEventStreamProtos.BuildEvent BUILD_EVENT_AS_PROTO =
+ BuildEventStreamProtos.BuildEvent.newBuilder()
+ .setStarted(BuildStarted.newBuilder().setCommand("build"))
+ .build();
+
+ @Rule public TemporaryFolder tmp = new TemporaryFolder();
+
+ @Mock public BuildEventStreamOptions options;
+
+ @Mock public BuildEvent buildEvent;
+
+ @Before
+ public void before() {
+ MockitoAnnotations.initMocks(this);
+ when(buildEvent.asStreamProto()).thenReturn(BUILD_EVENT_AS_PROTO);
+ }
+
+ @After
+ public void validateMocks() {
+ Mockito.validateMockitoUsage();
+ }
+
+ @Test
+ public void testCreatesTextFormatFileTransport() throws IOException {
+ File textFile = tmp.newFile();
+ when(options.getBuildEventTextFile()).thenReturn(textFile.getAbsolutePath());
+ when(options.getBuildEventBinaryFile()).thenReturn("");
+ ImmutableSet<BuildEventTransport> transports =
+ BuildEventTransportFactory.createFromOptions(options);
+ assertThat(FluentIterable.from(transports).transform(GET_CLASS))
+ .containsExactly(TextFormatFileTransport.class);
+ sendEventsAndClose(buildEvent, transports);
+ assertThat(textFile.exists()).isTrue();
+ }
+
+ @Test
+ public void testCreatesBinaryFormatFileTransport() throws IOException {
+ File binaryFile = tmp.newFile();
+ when(options.getBuildEventTextFile()).thenReturn("");
+ when(options.getBuildEventBinaryFile()).thenReturn(binaryFile.getAbsolutePath());
+ ImmutableSet<BuildEventTransport> transports =
+ BuildEventTransportFactory.createFromOptions(options);
+ assertThat(FluentIterable.from(transports).transform(GET_CLASS))
+ .containsExactly(BinaryFormatFileTransport.class);
+ sendEventsAndClose(buildEvent, transports);
+ assertThat(binaryFile.exists()).isTrue();
+ }
+
+ @Test
+ public void testCreatesAllTransports() throws IOException {
+ File textFile = tmp.newFile();
+ File binaryFile = tmp.newFile();
+ when(options.getBuildEventTextFile()).thenReturn(textFile.getAbsolutePath());
+ when(options.getBuildEventBinaryFile()).thenReturn(binaryFile.getAbsolutePath());
+ ImmutableSet<BuildEventTransport> transports =
+ BuildEventTransportFactory.createFromOptions(options);
+ assertThat(FluentIterable.from(transports).transform(GET_CLASS))
+ .containsExactly(TextFormatFileTransport.class, BinaryFormatFileTransport.class);
+ sendEventsAndClose(buildEvent, transports);
+ assertThat(textFile.exists()).isTrue();
+ assertThat(binaryFile.exists()).isTrue();
+ }
+
+ @Test
+ public void testCreatesNoTransports() throws IOException {
+ when(options.getBuildEventTextFile()).thenReturn("");
+ ImmutableSet<BuildEventTransport> transports =
+ BuildEventTransportFactory.createFromOptions(options);
+ assertThat(transports).isEmpty();
+ }
+
+ private void sendEventsAndClose(BuildEvent event, Iterable<BuildEventTransport> transports)
+ throws IOException{
+ for (BuildEventTransport transport : transports) {
+ transport.sendBuildEvent(event);
+ transport.close();
+ }
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransportTest.java b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransportTest.java
new file mode 100644
index 0000000000..798e8557c8
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransportTest.java
@@ -0,0 +1,91 @@
+// Copyright 2016 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.devtools.build.lib.buildeventstream.transports;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Joiner;
+import com.google.common.io.Files;
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildStarted;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.Progress;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.TargetComplete;
+import com.google.protobuf.TextFormat;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/** Tests {@link TextFormatFileTransport}. **/
+@RunWith(JUnit4.class)
+public class TextFormatFileTransportTest {
+
+ @Rule public TemporaryFolder tmp = new TemporaryFolder();
+
+ @Mock public BuildEvent buildEvent;
+
+ @Before
+ public void initMocks() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @After
+ public void validateMocks() {
+ Mockito.validateMockitoUsage();
+ }
+
+ @Test
+ public void testCreatesFileAndWritesProtoTextFormat() throws IOException {
+ File output = tmp.newFile();
+
+ BuildEventStreamProtos.BuildEvent started =
+ BuildEventStreamProtos.BuildEvent.newBuilder()
+ .setStarted(BuildStarted.newBuilder().setCommand("build"))
+ .build();
+ when(buildEvent.asStreamProto()).thenReturn(started);
+ TextFormatFileTransport transport = new TextFormatFileTransport(output.getAbsolutePath());
+ transport.sendBuildEvent(buildEvent);
+
+ BuildEventStreamProtos.BuildEvent progress =
+ BuildEventStreamProtos.BuildEvent.newBuilder().setProgress(Progress.newBuilder()).build();
+ when(buildEvent.asStreamProto()).thenReturn(progress);
+ transport.sendBuildEvent(buildEvent);
+
+ BuildEventStreamProtos.BuildEvent completed =
+ BuildEventStreamProtos.BuildEvent.newBuilder()
+ .setCompleted(TargetComplete.newBuilder().setSuccess(true))
+ .build();
+ when(buildEvent.asStreamProto()).thenReturn(completed);
+ transport.sendBuildEvent(buildEvent);
+
+ transport.close();
+ String contents =
+ Joiner.on(System.lineSeparator()).join(Files.readLines(output, StandardCharsets.UTF_8));
+ assertThat(contents).contains(TextFormat.printToString(started));
+ assertThat(contents).contains(TextFormat.printToString(progress));
+ assertThat(contents).contains(TextFormat.printToString(completed));
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModuleTest.java b/src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModuleTest.java
new file mode 100644
index 0000000000..ad5a87c745
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerModuleTest.java
@@ -0,0 +1,136 @@
+// Copyright 2016 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.devtools.build.lib.runtime;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
+import com.google.devtools.build.lib.buildeventstream.transports.BinaryFormatFileTransport;
+import com.google.devtools.build.lib.buildeventstream.transports.BuildEventStreamOptions;
+import com.google.devtools.build.lib.buildeventstream.transports.TextFormatFileTransport;
+import com.google.devtools.build.lib.runtime.BlazeModule.ModuleEnvironment;
+import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsParser;
+import com.google.devtools.common.options.OptionsProvider;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/** Tests {@link BuildEventStreamerModule}. **/
+@RunWith(JUnit4.class)
+public class BuildEventStreamerModuleTest {
+
+ private static final Function<Object, Class<?>> GET_CLASS =
+ new Function<Object, Class<?>>() {
+ @Override
+ public Class<?> apply(Object o) {
+ return o.getClass();
+ }
+ };
+
+ @Rule public TemporaryFolder tmp = new TemporaryFolder();
+
+ @Mock public BuildEventStreamOptions options;
+
+ @Mock public OptionsProvider optionsProvider;
+
+ @Mock public ModuleEnvironment moduleEnvironment;
+
+ @Mock public Command command;
+
+ @Before
+ public void initMocks() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @After
+ public void validateMocks() {
+ Mockito.validateMockitoUsage();
+ }
+
+ @Test
+ public void testReturnsBuildEventStreamerOptions() throws Exception {
+ BuildEventStreamerModule module = new BuildEventStreamerModule();
+ Iterable<Class<? extends OptionsBase>> commandOptions = module.getCommandOptions(command);
+ assertThat(commandOptions).isNotEmpty();
+ OptionsParser optionsParser = OptionsParser.newOptionsParser(commandOptions);
+ optionsParser.parse(
+ "--experimental_build_event_text_file", "/tmp/foo.txt",
+ "--experimental_build_event_binary_file", "/tmp/foo.bin");
+ BuildEventStreamOptions options = optionsParser.getOptions(BuildEventStreamOptions.class);
+ assertThat(options.getBuildEventTextFile()).isEqualTo("/tmp/foo.txt");
+ assertThat(options.getBuildEventBinaryFile()).isEqualTo("/tmp/foo.bin");
+ }
+
+ @Test
+ public void testCreatesStreamerForTextFormatFileTransport() throws Exception {
+ when(optionsProvider.getOptions(BuildEventStreamOptions.class)).thenReturn(options);
+ when(options.getBuildEventTextFile()).thenReturn(tmp.newFile().getAbsolutePath());
+
+ BuildEventStreamerModule module = new BuildEventStreamerModule();
+ Optional<BuildEventStreamer> buildEventStreamer =
+ module.tryCreateStreamer(optionsProvider, moduleEnvironment);
+ assertThat(buildEventStreamer.get()).isInstanceOf(BuildEventStreamer.class);
+ assertThat(FluentIterable.from(buildEventStreamer.get().getTransports()).transform(GET_CLASS))
+ .containsExactly(TextFormatFileTransport.class);
+ }
+
+ @Test
+ public void testCreatesStreamerForBinaryFormatFileTransport() throws Exception {
+ when(optionsProvider.getOptions(BuildEventStreamOptions.class)).thenReturn(options);
+ when(options.getBuildEventBinaryFile()).thenReturn(tmp.newFile().getAbsolutePath());
+
+ BuildEventStreamerModule module = new BuildEventStreamerModule();
+ Optional<BuildEventStreamer> buildEventStreamer =
+ module.tryCreateStreamer(optionsProvider, moduleEnvironment);
+ assertThat(buildEventStreamer.get()).isInstanceOf(BuildEventStreamer.class);
+ assertThat(FluentIterable.from(buildEventStreamer.get().getTransports()).transform(GET_CLASS))
+ .containsExactly(BinaryFormatFileTransport.class);
+ }
+
+ @Test
+ public void testCreatesStreamerForAllTransports() throws Exception {
+ when(optionsProvider.getOptions(BuildEventStreamOptions.class)).thenReturn(options);
+ when(options.getBuildEventTextFile()).thenReturn(tmp.newFile().getAbsolutePath());
+ when(options.getBuildEventBinaryFile()).thenReturn(tmp.newFile().getAbsolutePath());
+
+ BuildEventStreamerModule module = new BuildEventStreamerModule();
+ Optional<BuildEventStreamer> buildEventStreamer =
+ module.tryCreateStreamer(optionsProvider, moduleEnvironment);
+ assertThat(buildEventStreamer.get()).isInstanceOf(BuildEventStreamer.class);
+ assertThat(FluentIterable.from(buildEventStreamer.get().getTransports()).transform(GET_CLASS))
+ .containsExactly(TextFormatFileTransport.class, BinaryFormatFileTransport.class);
+ }
+
+ @Test
+ public void testDoesNotCreatesStreamerWithoutTransports() throws Exception {
+ when(optionsProvider.getOptions(BuildEventStreamOptions.class)).thenReturn(options);
+
+ BuildEventStreamerModule module = new BuildEventStreamerModule();
+ Optional<BuildEventStreamer> buildEventStreamer =
+ module.tryCreateStreamer(optionsProvider, moduleEnvironment);
+ assertThat(buildEventStreamer.isPresent()).isFalse();
+ }
+}
diff --git a/src/test/shell/integration/build_event_stream_test.sh b/src/test/shell/integration/build_event_stream_test.sh
index 2d8c246b9d..5cc89bb599 100755
--- a/src/test/shell/integration/build_event_stream_test.sh
+++ b/src/test/shell/integration/build_event_stream_test.sh
@@ -76,4 +76,14 @@ function test_test_summary() {
expect_not_log 'aborted'
}
+function test_multiple_transports() {
+ # Verifies usage of multiple build event transports at the same time
+ bazel test \
+ --experimental_build_event_text_file=test_multiple_transports.txt \
+ --experimental_build_event_binary_file=test_multiple_transports.bin \
+ pkg:suite || fail "bazel test failed"
+ [ -f test_multiple_transports.txt ] || fail "Missing expected file test_multiple_transports.txt"
+ [ -f test_multiple_transports.bin ] || fail "Missing expected file test_multiple_transports.bin"
+}
+
run_suite "Integration tests for the build event stream"