blob: 53d4a74d9cf23639baf9e7c0c6e8783d89f0e4d5 [file] [log] [blame]
Klaus Aehlig17325a12016-09-30 15:45:27 +00001// Copyright 2016 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.runtime;
15
16import static com.google.common.truth.Truth.assertThat;
lberkiaea56b32017-05-30 12:35:33 +020017import static com.google.common.truth.Truth.assertWithMessage;
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +020018import static org.mockito.Mockito.times;
19import static org.mockito.Mockito.verify;
20import static org.mockito.Mockito.when;
Klaus Aehlig17325a12016-09-30 15:45:27 +000021
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040022import com.google.common.collect.ImmutableList;
23import com.google.common.collect.ImmutableMap;
Klaus Aehlig17325a12016-09-30 15:45:27 +000024import com.google.common.collect.ImmutableSet;
buchgr9e0308e2017-04-25 16:38:45 +020025import com.google.common.eventbus.Subscribe;
buchgr0b937432017-04-06 18:54:22 +000026import com.google.common.util.concurrent.Futures;
buchgr9e0308e2017-04-25 16:38:45 +020027import com.google.common.util.concurrent.ListenableFuture;
lberki86266232018-04-11 00:33:42 -070028import com.google.devtools.build.lib.actions.ActionEnvironment;
ruperts76de73b2018-03-02 16:10:43 -080029import com.google.devtools.build.lib.actions.ActionExecutedEvent;
30import com.google.devtools.build.lib.actions.ActionExecutedEvent.ErrorTiming;
31import com.google.devtools.build.lib.actions.ActionExecutionException;
Klaus Aehligee3e1922017-04-07 14:25:27 +000032import com.google.devtools.build.lib.actions.Artifact;
tomlu04e92812018-08-02 11:49:08 -070033import com.google.devtools.build.lib.actions.ArtifactPathResolver;
tomlu1cdcdf92018-01-16 11:07:51 -080034import com.google.devtools.build.lib.actions.ArtifactRoot;
Klaus Aehligee3e1922017-04-07 14:25:27 +000035import com.google.devtools.build.lib.actions.EventReportingArtifacts;
ruperts76de73b2018-03-02 16:10:43 -080036import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040037import com.google.devtools.build.lib.analysis.BlazeDirectories;
janakr3b63a4e2017-09-14 09:55:40 +020038import com.google.devtools.build.lib.analysis.ServerDirectories;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040039import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040040import com.google.devtools.build.lib.analysis.config.BuildOptions;
41import com.google.devtools.build.lib.analysis.config.FragmentOptions;
buchgr9e0308e2017-04-25 16:38:45 +020042import com.google.devtools.build.lib.buildeventstream.AnnounceBuildEventTransportsEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000043import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
Klaus Aehlig17325a12016-09-30 15:45:27 +000044import com.google.devtools.build.lib.buildeventstream.BuildEvent;
ulfjack26e586d2018-05-17 08:42:13 -070045import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
Klaus Aehlig17325a12016-09-30 15:45:27 +000046import com.google.devtools.build.lib.buildeventstream.BuildEventId;
ulfjackfbf27562018-05-18 12:46:54 -070047import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
Klaus Aehligf75878d2016-11-21 13:41:16 +000048import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
Klaus Aehligee3e1922017-04-07 14:25:27 +000049import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.NamedSetOfFilesId;
Klaus Aehlig17325a12016-09-30 15:45:27 +000050import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
buchgr9e0308e2017-04-25 16:38:45 +020051import com.google.devtools.build.lib.buildeventstream.BuildEventTransportClosedEvent;
Klaus Aehliga708a022017-07-11 12:54:40 +020052import com.google.devtools.build.lib.buildeventstream.BuildEventWithConfiguration;
Klaus Aehligf75878d2016-11-21 13:41:16 +000053import com.google.devtools.build.lib.buildeventstream.BuildEventWithOrderConstraint;
Klaus Aehlig17325a12016-09-30 15:45:27 +000054import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000055import com.google.devtools.build.lib.buildeventstream.PathConverter;
Klaus Aehlig17325a12016-09-30 15:45:27 +000056import com.google.devtools.build.lib.buildeventstream.ProgressEvent;
ruperts76de73b2018-03-02 16:10:43 -080057import com.google.devtools.build.lib.buildeventstream.transports.BuildEventStreamOptions;
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +000058import com.google.devtools.build.lib.buildtool.BuildResult;
Klaus Aehlig17325a12016-09-30 15:45:27 +000059import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000060import com.google.devtools.build.lib.collect.nestedset.NestedSet;
61import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
62import com.google.devtools.build.lib.collect.nestedset.NestedSetView;
63import com.google.devtools.build.lib.testutil.FoundationTestCase;
64import com.google.devtools.build.lib.vfs.Path;
65import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080066import com.google.devtools.build.lib.vfs.Root;
ulfjackfbf27562018-05-18 12:46:54 -070067import com.google.devtools.common.options.Options;
Klaus Aehlig17325a12016-09-30 15:45:27 +000068import java.util.ArrayList;
Klaus Aehligf75878d2016-11-21 13:41:16 +000069import java.util.Collection;
buchgr9e0308e2017-04-25 16:38:45 +020070import java.util.Collections;
71import java.util.HashSet;
Klaus Aehlig17325a12016-09-30 15:45:27 +000072import java.util.List;
buchgr9e0308e2017-04-25 16:38:45 +020073import java.util.Set;
74import java.util.concurrent.TimeUnit;
75import java.util.concurrent.locks.LockSupport;
76import org.junit.Before;
Klaus Aehlig17325a12016-09-30 15:45:27 +000077import org.junit.Test;
78import org.junit.runner.RunWith;
79import org.junit.runners.JUnit4;
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +020080import org.mockito.Mockito;
buchgr9e0308e2017-04-25 16:38:45 +020081import org.mockito.MockitoAnnotations;
Klaus Aehlig17325a12016-09-30 15:45:27 +000082
83/** Tests {@link BuildEventStreamer}. */
84@RunWith(JUnit4.class)
Klaus Aehligee3e1922017-04-07 14:25:27 +000085public class BuildEventStreamerTest extends FoundationTestCase {
Klaus Aehlig17325a12016-09-30 15:45:27 +000086
ruperts76de73b2018-03-02 16:10:43 -080087 private static final ActionExecutedEvent SUCCESSFUL_ACTION_EXECUTED_EVENT =
88 new ActionExecutedEvent(
89 new ActionsTestUtil.NullAction(),
90 /* exception= */ null,
tomlud56a8062018-08-01 13:20:41 -070091 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -080092 /* stdout= */ null,
93 /* stderr= */ null,
94 ErrorTiming.NO_ERROR);
95
Klaus Aehlig17325a12016-09-30 15:45:27 +000096 private static class RecordingBuildEventTransport implements BuildEventTransport {
Klaus Aehligee3e1922017-04-07 14:25:27 +000097 private final List<BuildEvent> events = new ArrayList<>();
98 private final List<BuildEventStreamProtos.BuildEvent> eventsAsProtos = new ArrayList<>();
Klaus Aehlig17325a12016-09-30 15:45:27 +000099
100 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200101 public String name() {
102 return this.getClass().getSimpleName();
103 }
104
105 @Override
Klaus Aehligee3e1922017-04-07 14:25:27 +0000106 public void sendBuildEvent(BuildEvent event, final ArtifactGroupNamer namer) {
Klaus Aehlig17325a12016-09-30 15:45:27 +0000107 events.add(event);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000108 eventsAsProtos.add(
109 event.asStreamProto(
ulfjack26e586d2018-05-17 08:42:13 -0700110 new BuildEventContext() {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000111 @Override
112 public ArtifactGroupNamer artifactGroupNamer() {
113 return namer;
114 }
115
116 @Override
117 public PathConverter pathConverter() {
118 return new PathConverter() {
119 @Override
120 public String apply(Path path) {
121 return path.toString();
122 }
123 };
124 }
ulfjackfbf27562018-05-18 12:46:54 -0700125
126 @Override
127 public BuildEventProtocolOptions getOptions() {
128 return Options.getDefaults(BuildEventProtocolOptions.class);
129 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000130 }));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000131 }
132
133 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200134 public ListenableFuture<Void> close() {
buchgr0b937432017-04-06 18:54:22 +0000135 return Futures.immediateFuture(null);
136 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000137
buchgr0ca8f4b2017-09-12 13:49:21 +0200138 @Override
139 public void closeNow() {
140 }
141
Klaus Aehlig17325a12016-09-30 15:45:27 +0000142 List<BuildEvent> getEvents() {
143 return events;
144 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000145
146 List<BuildEventStreamProtos.BuildEvent> getEventProtos() {
147 return eventsAsProtos;
148 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000149 }
150
Klaus Aehligf75878d2016-11-21 13:41:16 +0000151 private static class GenericOrderEvent implements BuildEventWithOrderConstraint {
152 private final BuildEventId id;
153 private final Collection<BuildEventId> children;
154 private final Collection<BuildEventId> after;
155
156 GenericOrderEvent(
157 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEventId> after) {
158 this.id = id;
159 this.children = children;
160 this.after = after;
161 }
162
163 GenericOrderEvent(BuildEventId id, Collection<BuildEventId> children) {
164 this(id, children, children);
165 }
166
167 @Override
168 public BuildEventId getEventId() {
169 return id;
170 }
171
172 @Override
173 public Collection<BuildEventId> getChildrenEvents() {
174 return children;
175 }
176
177 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700178 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000179 return GenericBuildEvent.protoChaining(this).build();
180 }
181
182 @Override
183 public Collection<BuildEventId> postedAfter() {
184 return after;
185 }
186 }
187
Klaus Aehligee3e1922017-04-07 14:25:27 +0000188 private static class GenericArtifactReportingEvent implements EventReportingArtifacts {
189 private final BuildEventId id;
190 private final Collection<BuildEventId> children;
191 private final Collection<NestedSet<Artifact>> artifacts;
192
193 GenericArtifactReportingEvent(
194 BuildEventId id,
195 Collection<BuildEventId> children,
196 Collection<NestedSet<Artifact>> artifacts) {
197 this.id = id;
198 this.children = children;
199 this.artifacts = artifacts;
200 }
201
202 GenericArtifactReportingEvent(BuildEventId id, Collection<NestedSet<Artifact>> artifacts) {
203 this(id, ImmutableSet.<BuildEventId>of(), artifacts);
204 }
205
206 @Override
207 public BuildEventId getEventId() {
208 return id;
209 }
210
211 @Override
212 public Collection<BuildEventId> getChildrenEvents() {
213 return children;
214 }
215
216 @Override
tomlu04e92812018-08-02 11:49:08 -0700217 public ReportedArtifacts reportedArtifacts() {
218 return new ReportedArtifacts(artifacts, ArtifactPathResolver.IDENTITY);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000219 }
220
221 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700222 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000223 BuildEventStreamProtos.NamedSetOfFiles.Builder builder =
224 BuildEventStreamProtos.NamedSetOfFiles.newBuilder();
225 for (NestedSet<Artifact> artifactset : artifacts) {
226 builder.addFileSets(
227 converters
228 .artifactGroupNamer()
229 .apply((new NestedSetView<Artifact>(artifactset)).identifier()));
230 }
231 return GenericBuildEvent.protoChaining(this).setNamedSetOfFiles(builder.build()).build();
232 }
233 }
234
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400235 private static class GenericConfigurationEvent implements BuildEventWithConfiguration {
236 private final BuildEventId id;
237 private final Collection<BuildEventId> children;
Klaus Aehliga708a022017-07-11 12:54:40 +0200238 private final Collection<BuildEvent> configurations;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400239
240 GenericConfigurationEvent(
Klaus Aehliga708a022017-07-11 12:54:40 +0200241 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEvent> configurations) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400242 this.id = id;
243 this.children = children;
244 this.configurations = configurations;
245 }
246
Klaus Aehliga708a022017-07-11 12:54:40 +0200247 GenericConfigurationEvent(BuildEventId id, BuildEvent configuration) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400248 this(id, ImmutableSet.<BuildEventId>of(), ImmutableSet.of(configuration));
249 }
250
251 @Override
252 public BuildEventId getEventId() {
253 return id;
254 }
255
256 @Override
257 public Collection<BuildEventId> getChildrenEvents() {
258 return children;
259 }
260
261 @Override
Klaus Aehliga708a022017-07-11 12:54:40 +0200262 public Collection<BuildEvent> getConfigurations() {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400263 return configurations;
264 }
265
266 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700267 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400268 return GenericBuildEvent.protoChaining(this).build();
269 }
270 }
271
Klaus Aehlig17325a12016-09-30 15:45:27 +0000272 private static BuildEventId testId(String opaque) {
273 return BuildEventId.unknownBuildEventId(opaque);
274 }
275
buchgr9e0308e2017-04-25 16:38:45 +0200276 private static class EventBusHandler {
277
278 Set<BuildEventTransport> transportSet;
279
280 @Subscribe
281 void transportsAnnounced(AnnounceBuildEventTransportsEvent evt) {
282 transportSet = Collections.synchronizedSet(new HashSet<>(evt.transports()));
283 }
284
285 @Subscribe
286 void transportClosed(BuildEventTransportClosedEvent evt) {
287 transportSet.remove(evt.transport());
288 }
289 }
290
291 @Before
292 public void setup() {
293 MockitoAnnotations.initMocks(this);
294 }
295
296 @Test(timeout = 5000)
Klaus Aehlig17325a12016-09-30 15:45:27 +0000297 public void testSimpleStream() {
298 // Verify that a well-formed event is passed through and that completion of the
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200299 // build clears the pending progress-update event. However, there is no guarantee
300 // on the order of the flushed events.
301 // Additionally, assert that the actual last event has the last_message flag set.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000302
buchgr9e0308e2017-04-25 16:38:45 +0200303 EventBusHandler handler = new EventBusHandler();
304 eventBus.register(handler);
lberkiaea56b32017-05-30 12:35:33 +0200305 assertThat(handler.transportSet).isNull();
buchgr9e0308e2017-04-25 16:38:45 +0200306
Klaus Aehlig17325a12016-09-30 15:45:27 +0000307 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000308 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200309 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000310
311 BuildEvent startEvent =
312 new GenericBuildEvent(
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000313 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE,
314 BuildEventId.buildFinished()));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000315
316 streamer.buildEvent(startEvent);
317
aehlig03d55f32017-10-26 11:45:35 +0200318 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000319 List<BuildEvent> afterFirstEvent = transport.getEvents();
320 assertThat(afterFirstEvent).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200321 assertThat(afterFirstEvent.get(0).getEventId()).isEqualTo(startEvent.getEventId());
322 assertThat(handler.transportSet).hasSize(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000323
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000324 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000325
aehlig03d55f32017-10-26 11:45:35 +0200326 assertThat(streamer.isClosed()).isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000327 List<BuildEvent> finalStream = transport.getEvents();
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000328 assertThat(finalStream).hasSize(3);
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200329 assertThat(ImmutableSet.of(finalStream.get(1).getEventId(), finalStream.get(2).getEventId()))
330 .isEqualTo(
331 ImmutableSet.of(BuildEventId.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
332
333 // verify the "last_message" flag.
334 assertThat(transport.getEventProtos().get(0).getLastMessage()).isFalse();
335 assertThat(transport.getEventProtos().get(1).getLastMessage()).isFalse();
336 assertThat(transport.getEventProtos().get(2).getLastMessage()).isTrue();
buchgr9e0308e2017-04-25 16:38:45 +0200337
338 while (!handler.transportSet.isEmpty()) {
339 LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
340 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000341 }
342
343 @Test
344 public void testChaining() {
345 // Verify that unannounced events are linked in with progress update events, assuming
346 // a correctly formed initial event.
347
348 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000349 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200350 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000351
352 BuildEvent startEvent =
353 new GenericBuildEvent(
354 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000355 BuildEvent unexpectedEvent =
356 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000357
358 streamer.buildEvent(startEvent);
359 streamer.buildEvent(unexpectedEvent);
360
aehlig03d55f32017-10-26 11:45:35 +0200361 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000362 List<BuildEvent> eventsSeen = transport.getEvents();
363 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200364 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
365 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000366 BuildEvent linkEvent = eventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200367 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
368 assertWithMessage("Unexpected events should be linked")
369 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
370 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000371 }
372
373 @Test
374 public void testBadInitialEvent() {
375 // Verify that, if the initial event does not announce the initial progress update event,
376 // the initial progress event is used instead to chain that event; in this way, new
377 // progress updates can always be chained in.
378
379 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000380 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200381 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000382
383 BuildEvent unexpectedStartEvent =
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000384 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000385
386 streamer.buildEvent(unexpectedStartEvent);
387
388 List<BuildEvent> eventsSeen = transport.getEvents();
389 assertThat(eventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200390 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000391 BuildEvent initial = eventsSeen.get(0);
lberkiaea56b32017-05-30 12:35:33 +0200392 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
393 assertWithMessage("Event should be linked")
394 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
395 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000396
397 // The initial event should also announce a new progress event; we test this
398 // by streaming another unannounced event.
399
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000400 BuildEvent unexpectedEvent =
401 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000402
403 streamer.buildEvent(unexpectedEvent);
aehlig03d55f32017-10-26 11:45:35 +0200404
405 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000406 List<BuildEvent> allEventsSeen = transport.getEvents();
407 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200408 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000409 BuildEvent secondLinkEvent = allEventsSeen.get(2);
lberkiaea56b32017-05-30 12:35:33 +0200410 assertWithMessage("Progress should have been announced")
411 .that(initial.getChildrenEvents().contains(secondLinkEvent.getEventId()))
412 .isTrue();
413 assertWithMessage("Second event should be linked")
414 .that(secondLinkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
415 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000416 }
417
418 @Test
419 public void testReferPastEvent() {
420 // Verify that, if an event is refers to a previously done event, that duplicated
421 // late-referenced event is not expected again.
422 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000423 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200424 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000425
426 BuildEvent startEvent =
427 new GenericBuildEvent(
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000428 testId("Initial"),
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000429 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE,
430 BuildEventId.buildFinished()));
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000431 BuildEvent earlyEvent =
432 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000433 BuildEvent lateReference =
434 new GenericBuildEvent(testId("late reference"), ImmutableSet.of(earlyEvent.getEventId()));
435
436 streamer.buildEvent(startEvent);
437 streamer.buildEvent(earlyEvent);
438 streamer.buildEvent(lateReference);
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000439 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000440
aehlig03d55f32017-10-26 11:45:35 +0200441 assertThat(streamer.isClosed()).isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000442 List<BuildEvent> eventsSeen = transport.getEvents();
443 int earlyEventCount = 0;
444 for (BuildEvent event : eventsSeen) {
445 if (event.getEventId().equals(earlyEvent.getEventId())) {
446 earlyEventCount++;
447 }
448 }
449 // The early event should be reported precisely once.
lberkiaea56b32017-05-30 12:35:33 +0200450 assertThat(earlyEventCount).isEqualTo(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000451 }
Klaus Aehligf75878d2016-11-21 13:41:16 +0000452
453 @Test
454 public void testReodering() {
455 // Verify that an event requiring to be posted after another one is indeed.
456
457 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
458 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200459 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehligf75878d2016-11-21 13:41:16 +0000460
461 BuildEventId expectedId = testId("the target");
462 BuildEvent startEvent =
463 new GenericBuildEvent(
464 testId("Initial"),
465 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, expectedId));
466 BuildEvent rootCause =
467 new GenericBuildEvent(testId("failure event"), ImmutableSet.<BuildEventId>of());
468 BuildEvent failedTarget =
469 new GenericOrderEvent(expectedId, ImmutableSet.<BuildEventId>of(rootCause.getEventId()));
470
471 streamer.buildEvent(startEvent);
472 streamer.buildEvent(failedTarget);
473 streamer.buildEvent(rootCause);
474
aehlig03d55f32017-10-26 11:45:35 +0200475 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligf75878d2016-11-21 13:41:16 +0000476 List<BuildEvent> allEventsSeen = transport.getEvents();
477 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200478 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000479 BuildEvent linkEvent = allEventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200480 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
481 assertThat(allEventsSeen.get(2).getEventId()).isEqualTo(rootCause.getEventId());
482 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(failedTarget.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000483 }
484
485 @Test
486 public void testMissingPrerequisits() {
487 // Verify that an event where the prerequisite is never coming till the end of
488 // the build still gets posted, with the prerequisite aborted.
489
490 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
491 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200492 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehligf75878d2016-11-21 13:41:16 +0000493
494 BuildEventId expectedId = testId("the target");
495 BuildEvent startEvent =
496 new GenericBuildEvent(
497 testId("Initial"),
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000498 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, expectedId,
499 BuildEventId.buildFinished()));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000500 BuildEventId rootCauseId = testId("failure event");
501 BuildEvent failedTarget =
502 new GenericOrderEvent(expectedId, ImmutableSet.<BuildEventId>of(rootCauseId));
503
504 streamer.buildEvent(startEvent);
505 streamer.buildEvent(failedTarget);
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000506 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000507
aehlig03d55f32017-10-26 11:45:35 +0200508 assertThat(streamer.isClosed()).isTrue();
Klaus Aehligf75878d2016-11-21 13:41:16 +0000509 List<BuildEvent> allEventsSeen = transport.getEvents();
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000510 assertThat(allEventsSeen).hasSize(6);
lberkiaea56b32017-05-30 12:35:33 +0200511 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
512 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000513 BuildEvent linkEvent = allEventsSeen.get(2);
lberkiaea56b32017-05-30 12:35:33 +0200514 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
515 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(rootCauseId);
516 assertThat(allEventsSeen.get(4).getEventId()).isEqualTo(failedTarget.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000517 }
Klaus Aehligceb0f622017-03-20 13:52:06 +0000518
519 @Test
520 public void testVeryFirstEventNeedsToWait() {
521 // Verify that we can handle an first event waiting for another event.
522 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
523 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200524 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehligceb0f622017-03-20 13:52:06 +0000525
526 BuildEventId initialId = testId("Initial");
527 BuildEventId waitId = testId("Waiting for initial event");
528 BuildEvent startEvent =
529 new GenericBuildEvent(
530 initialId,
531 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, waitId));
532 BuildEvent waitingForStart =
533 new GenericOrderEvent(waitId, ImmutableSet.<BuildEventId>of(), ImmutableSet.of(initialId));
534
535 streamer.buildEvent(waitingForStart);
536 streamer.buildEvent(startEvent);
537
aehlig03d55f32017-10-26 11:45:35 +0200538 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligceb0f622017-03-20 13:52:06 +0000539 List<BuildEvent> allEventsSeen = transport.getEvents();
540 assertThat(allEventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200541 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
542 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(waitingForStart.getEventId());
Klaus Aehligceb0f622017-03-20 13:52:06 +0000543 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000544
545 private Artifact makeArtifact(String pathString) {
546 Path path = outputBase.getRelative(PathFragment.create(pathString));
tomluee6a6862018-01-17 14:36:26 -0800547 return new Artifact(path, ArtifactRoot.asSourceRoot(Root.fromPath(outputBase)));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000548 }
549
550 @Test
551 public void testReportedArtifacts() {
552 // Verify that reported artifacts are correctly unfolded into the stream
553 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
554 BuildEventStreamer streamer =
buchgr9e0308e2017-04-25 16:38:45 +0200555 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000556
557 BuildEvent startEvent =
558 new GenericBuildEvent(
559 testId("Initial"),
560 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
561
562 Artifact a = makeArtifact("path/a");
563 Artifact b = makeArtifact("path/b");
564 Artifact c = makeArtifact("path/c");
565 NestedSet<Artifact> innerGroup = NestedSetBuilder.<Artifact>stableOrder().add(a).add(b).build();
566 NestedSet<Artifact> group =
567 NestedSetBuilder.<Artifact>stableOrder().addTransitive(innerGroup).add(c).build();
568 BuildEvent reportingArtifacts =
569 new GenericArtifactReportingEvent(testId("reporting"), ImmutableSet.of(group));
570
571 streamer.buildEvent(startEvent);
572 streamer.buildEvent(reportingArtifacts);
573
aehlig03d55f32017-10-26 11:45:35 +0200574 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligee3e1922017-04-07 14:25:27 +0000575 List<BuildEvent> allEventsSeen = transport.getEvents();
576 List<BuildEventStreamProtos.BuildEvent> eventProtos = transport.getEventProtos();
lberkiaea56b32017-05-30 12:35:33 +0200577 assertThat(allEventsSeen).hasSize(7);
578 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
579 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000580 List<BuildEventStreamProtos.File> firstSetDirects =
581 eventProtos.get(2).getNamedSetOfFiles().getFilesList();
lberkiaea56b32017-05-30 12:35:33 +0200582 assertThat(firstSetDirects).hasSize(2);
583 assertThat(ImmutableSet.of(firstSetDirects.get(0).getUri(), firstSetDirects.get(1).getUri()))
584 .isEqualTo(ImmutableSet.of(a.getPath().toString(), b.getPath().toString()));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000585 List<NamedSetOfFilesId> secondSetTransitives =
586 eventProtos.get(4).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200587 assertThat(secondSetTransitives).hasSize(1);
588 assertThat(secondSetTransitives.get(0)).isEqualTo(eventProtos.get(2).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000589 List<NamedSetOfFilesId> reportedArtifactSets =
590 eventProtos.get(6).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200591 assertThat(reportedArtifactSets).hasSize(1);
592 assertThat(reportedArtifactSets.get(0)).isEqualTo(eventProtos.get(4).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000593 }
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200594
595 @Test
596 public void testStdoutReported() {
597 // Verify that stdout and stderr are reported in the build-event stream on progress
598 // events.
599 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
600 BuildEventStreamer streamer =
601 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
602 BuildEventStreamer.OutErrProvider outErr =
603 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
604 String stdoutMsg = "Some text that was written to stdout.";
605 String stderrMsg = "The UI text that bazel wrote to stderr.";
606 when(outErr.getOut()).thenReturn(stdoutMsg);
607 when(outErr.getErr()).thenReturn(stderrMsg);
608 BuildEvent startEvent =
609 new GenericBuildEvent(
610 testId("Initial"),
611 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
612 BuildEvent unexpectedEvent =
613 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
614
615 streamer.registerOutErrProvider(outErr);
616 streamer.buildEvent(startEvent);
617 streamer.buildEvent(unexpectedEvent);
618
aehlig03d55f32017-10-26 11:45:35 +0200619 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200620 List<BuildEvent> eventsSeen = transport.getEvents();
621 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200622 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
623 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200624 BuildEvent linkEvent = eventsSeen.get(1);
625 BuildEventStreamProtos.BuildEvent linkEventProto = transport.getEventProtos().get(1);
lberkiaea56b32017-05-30 12:35:33 +0200626 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
627 assertWithMessage("Unexpected events should be linked")
628 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
629 .isTrue();
630 assertThat(linkEventProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
631 assertThat(linkEventProto.getProgress().getStderr()).isEqualTo(stderrMsg);
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200632
633 // As there is only one progress event, the OutErrProvider should be queried
634 // only once for stdout and stderr.
635 verify(outErr, times(1)).getOut();
636 verify(outErr, times(1)).getErr();
637 }
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400638
639 @Test
640 public void testReportedConfigurations() throws Exception {
641 // Verify that configuration events are posted, but only once.
642 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
643 BuildEventStreamer streamer =
644 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
645
mjhalupka5d7fa7b2018-03-22 13:37:38 -0700646 BuildOptions defaultBuildOptions =
647 BuildOptions.of(
648 ImmutableList.<Class<? extends FragmentOptions>>of(BuildConfiguration.Options.class));
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400649 BuildEvent startEvent =
650 new GenericBuildEvent(
651 testId("Initial"),
652 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
653 BuildConfiguration configuration =
654 new BuildConfiguration(
janakr3b63a4e2017-09-14 09:55:40 +0200655 new BlazeDirectories(
Klaus Aehligc2499c42018-02-27 05:47:21 -0800656 new ServerDirectories(outputBase, outputBase, outputBase),
657 rootDirectory,
cushon849df362018-05-14 01:51:45 -0700658 /* defaultSystemJavabase= */ null,
Klaus Aehligc2499c42018-02-27 05:47:21 -0800659 "productName"),
lberki406199f2018-04-09 03:16:19 -0700660 /* fragmentsMap= */ ImmutableMap
janakr3b63a4e2017-09-14 09:55:40 +0200661 .<Class<? extends BuildConfiguration.Fragment>, BuildConfiguration.Fragment>of(),
mjhalupka5d7fa7b2018-03-22 13:37:38 -0700662 defaultBuildOptions,
663 BuildOptions.diffForReconstruction(defaultBuildOptions, defaultBuildOptions),
lberki406199f2018-04-09 03:16:19 -0700664 /* reservedActionMnemonics= */ ImmutableSet.of(),
lberki86266232018-04-11 00:33:42 -0700665 ActionEnvironment.EMPTY,
gregce85297462017-08-18 21:20:29 +0200666 "workspace");
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400667 BuildEvent firstWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800668 new GenericConfigurationEvent(testId("first"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400669 BuildEvent secondWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800670 new GenericConfigurationEvent(testId("second"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400671
672 streamer.buildEvent(startEvent);
673 streamer.buildEvent(firstWithConfiguration);
674 streamer.buildEvent(secondWithConfiguration);
675
aehlig03d55f32017-10-26 11:45:35 +0200676 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400677 List<BuildEvent> allEventsSeen = transport.getEvents();
lberkiaea56b32017-05-30 12:35:33 +0200678 assertThat(allEventsSeen).hasSize(7);
679 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
680 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
shahan50f99d52018-03-10 05:14:09 -0800681 assertThat(allEventsSeen.get(2)).isEqualTo(configuration.toBuildEvent());
lberkiaea56b32017-05-30 12:35:33 +0200682 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(BuildEventId.progressId(1));
683 assertThat(allEventsSeen.get(4)).isEqualTo(firstWithConfiguration);
684 assertThat(allEventsSeen.get(5).getEventId()).isEqualTo(BuildEventId.progressId(2));
685 assertThat(allEventsSeen.get(6)).isEqualTo(secondWithConfiguration);
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400686 }
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200687
688 @Test
689 public void testEarlyFlush() throws Exception {
690 // Verify that the streamer can handle early calls to flush() and still correctly
691 // reports stdout and stderr in the build-event stream.
692 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
693 BuildEventStreamer streamer =
694 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
695 BuildEventStreamer.OutErrProvider outErr =
696 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
697 String firstStdoutMsg = "Some text that was written to stdout.";
698 String firstStderrMsg = "The UI text that bazel wrote to stderr.";
699 String secondStdoutMsg = "More text that was written to stdout, still before the start event.";
700 String secondStderrMsg = "More text written to stderr, still before the start event.";
701 when(outErr.getOut()).thenReturn(firstStdoutMsg).thenReturn(secondStdoutMsg);
702 when(outErr.getErr()).thenReturn(firstStderrMsg).thenReturn(secondStderrMsg);
703 BuildEvent startEvent =
704 new GenericBuildEvent(
705 testId("Initial"),
706 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
707
708 streamer.registerOutErrProvider(outErr);
709 streamer.flush();
710 streamer.flush();
711 streamer.buildEvent(startEvent);
712
aehlig03d55f32017-10-26 11:45:35 +0200713 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200714 List<BuildEvent> eventsSeen = transport.getEvents();
715 assertThat(eventsSeen).hasSize(3);
716 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
717 BuildEvent progressEvent = eventsSeen.get(1);
718 assertThat(progressEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
719 BuildEventStreamProtos.BuildEvent progressEventProto = transport.getEventProtos().get(1);
720 assertThat(progressEventProto.getProgress().getStdout()).isEqualTo(firstStdoutMsg);
721 assertThat(progressEventProto.getProgress().getStderr()).isEqualTo(firstStderrMsg);
722 BuildEventStreamProtos.BuildEvent secondProgressEventProto = transport.getEventProtos().get(2);
723 assertThat(secondProgressEventProto.getProgress().getStdout()).isEqualTo(secondStdoutMsg);
724 assertThat(secondProgressEventProto.getProgress().getStderr()).isEqualTo(secondStderrMsg);
725
726 // As there is only one progress event, the OutErrProvider should be queried
727 // only once per flush() for stdout and stderr.
728 verify(outErr, times(2)).getOut();
729 verify(outErr, times(2)).getErr();
730 }
731
732 @Test
Klaus Aehlig28221ff2018-01-11 04:28:00 -0800733 public void testNoopFlush() throws Exception {
734 // Verify that the streamer ignores a flush, if neither stream produces any output.
735 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
736 BuildEventStreamer streamer =
737 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
738 BuildEventStreamer.OutErrProvider outErr =
739 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
740 String stdoutMsg = "Some text that was written to stdout.";
741 String stderrMsg = "The UI text that bazel wrote to stderr.";
742 when(outErr.getOut()).thenReturn(stdoutMsg).thenReturn("");
743 when(outErr.getErr()).thenReturn(stderrMsg).thenReturn("");
744 BuildEvent startEvent =
745 new GenericBuildEvent(
746 testId("Initial"),
747 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
748
749 streamer.registerOutErrProvider(outErr);
750 streamer.buildEvent(startEvent);
751 assertThat(transport.getEvents()).hasSize(1);
752 streamer.flush(); // Output, so a new progress event has to be added
753 assertThat(transport.getEvents()).hasSize(2);
754 streamer.flush(); // No further output, so no additional event should be generated.
755 assertThat(transport.getEvents()).hasSize(2);
756
757 assertThat(transport.getEvents().get(0)).isEqualTo(startEvent);
758 assertThat(transport.getEventProtos().get(1).getProgress().getStdout()).isEqualTo(stdoutMsg);
759 assertThat(transport.getEventProtos().get(1).getProgress().getStderr()).isEqualTo(stderrMsg);
760 }
761
762 @Test
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200763 public void testEarlyFlushBadInitialEvent() throws Exception {
764 // Verify that an early flush works correctly with an unusual start event.
765 // In this case, we expect 3 events in the stream, in that order:
766 // - an artifical progress event as initial event, to properly link in
767 // all events
768 // - the unusal first event we have seen, and
769 // - a progress event reporting the flushed messages.
770 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
771 BuildEventStreamer streamer =
772 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
773 BuildEventStreamer.OutErrProvider outErr =
774 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
775 String stdoutMsg = "Some text that was written to stdout.";
776 String stderrMsg = "The UI text that bazel wrote to stderr.";
777 when(outErr.getOut()).thenReturn(stdoutMsg);
778 when(outErr.getErr()).thenReturn(stderrMsg);
779
780 BuildEvent unexpectedStartEvent =
781 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.<BuildEventId>of());
782
783 streamer.registerOutErrProvider(outErr);
784 streamer.flush();
785 streamer.buildEvent(unexpectedStartEvent);
786
aehlig03d55f32017-10-26 11:45:35 +0200787 assertThat(streamer.isClosed()).isFalse();
788
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200789 List<BuildEvent> eventsSeen = transport.getEvents();
790 assertThat(eventsSeen).hasSize(3);
791
792 BuildEvent initial = eventsSeen.get(0);
793 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
794 BuildEventStreamProtos.BuildEvent initialProto = transport.getEventProtos().get(0);
795 assertThat(initialProto.getProgress().getStdout()).isEmpty();
796 assertThat(initialProto.getProgress().getStderr()).isEmpty();
797
798 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
799 assertWithMessage("Unexpected event should be linked")
800 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
801 .isTrue();
802
803 BuildEventStreamProtos.BuildEvent progressProto = transport.getEventProtos().get(2);
804 assertThat(progressProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
805 assertThat(progressProto.getProgress().getStderr()).isEqualTo(stderrMsg);
806 assertWithMessage("flushed progress should be linked")
807 .that(initial.getChildrenEvents().contains(eventsSeen.get(2).getEventId()))
808 .isTrue();
809
810 verify(outErr, times(1)).getOut();
811 verify(outErr, times(1)).getErr();
812 }
Klaus Aehligdeea6b02017-10-16 12:32:20 +0200813
814 @Test
815 public void testEarlyAbort() throws Exception {
816 // For a build that is aborted before a build-started event is generated,
817 // we still expect that, if a build-started event is forced by some order
818 // constraint (e.g., CommandLine wants to come after build started), then
819 // that gets sorted to the beginning.
820 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
821 BuildEventStreamer streamer =
822 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
823
824 BuildEvent orderEvent =
825 new GenericOrderEvent(
826 testId("event depending on start"),
827 ImmutableList.of(),
828 ImmutableList.of(BuildEventId.buildStartedId()));
829
830 streamer.buildEvent(orderEvent);
831 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
832
aehlig03d55f32017-10-26 11:45:35 +0200833 assertThat(streamer.isClosed()).isTrue();
Klaus Aehligdeea6b02017-10-16 12:32:20 +0200834 List<BuildEvent> eventsSeen = transport.getEvents();
835 assertThat(eventsSeen).hasSize(4);
836 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(BuildEventId.buildStartedId());
837 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(orderEvent.getEventId());
838 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
839 .isEqualTo(
840 ImmutableSet.of(BuildEventId.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
841 assertThat(transport.getEventProtos().get(3).getLastMessage()).isTrue();
842 }
aehlig03d55f32017-10-26 11:45:35 +0200843
844 @Test
845 public void testFinalEventsLate() throws Exception {
846 // Verify that we correctly handle late events (i.e., events coming only after the
847 // BuildCompleteEvent) that are sent to the streamer after the BuildCompleteEvent.
848 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
849 BuildEventStreamer streamer =
850 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
851 BuildEvent startEvent =
852 new GenericBuildEvent(
853 testId("Initial"),
854 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
855 BuildEventId lateId = testId("late event");
856 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
857
858 streamer.buildEvent(startEvent);
859 streamer.buildEvent(finishedEvent);
860 assertThat(streamer.isClosed()).isFalse();
861 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
862 assertThat(streamer.isClosed()).isTrue();
863
864 List<BuildEvent> eventsSeen = transport.getEvents();
865 assertThat(eventsSeen).hasSize(4);
866 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
867 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
868 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
869 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
870 }
871
872 @Test
873 public void testFinalEventsEarly() throws Exception {
874 // Verify that we correctly handle late events (i.e., events coming only after the
875 // BuildCompleteEvent) that are sent to the streamer before the BuildCompleteEvent,
876 // but with an order constraint to come afterwards.
877 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
878 BuildEventStreamer streamer =
879 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter);
880 BuildEvent startEvent =
881 new GenericBuildEvent(
882 testId("Initial"),
883 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
884 BuildEventId lateId = testId("late event");
885 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
886
887 streamer.buildEvent(startEvent);
888 streamer.buildEvent(
889 new GenericOrderEvent(
890 lateId, ImmutableSet.of(), ImmutableList.of(BuildEventId.buildFinished())));
891 streamer.buildEvent(finishedEvent);
892 assertThat(streamer.isClosed()).isTrue();
893
894 List<BuildEvent> eventsSeen = transport.getEvents();
895 assertThat(eventsSeen).hasSize(4);
896 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
897 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
898 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
899 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
900 }
ruperts76de73b2018-03-02 16:10:43 -0800901
902 @Test
903 public void testSuccessfulActionsAreNotPublishedByDefault() {
904 EventBusHandler handler = new EventBusHandler();
905 eventBus.register(handler);
906
907 BuildEventStreamOptions options = new BuildEventStreamOptions();
908
909 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
910 BuildEventStreamer streamer =
911 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter, options);
912
913 ActionExecutedEvent failedActionExecutedEvent =
914 new ActionExecutedEvent(
915 new ActionsTestUtil.NullAction(),
916 new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
tomlud56a8062018-08-01 13:20:41 -0700917 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -0800918 /* stdout= */ null,
919 /* stderr= */ null,
920 ErrorTiming.BEFORE_EXECUTION);
921
922 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
923 streamer.buildEvent(failedActionExecutedEvent);
924
925 List<BuildEvent> transportedEvents = transport.getEvents();
926
927 assertThat(transportedEvents).doesNotContain(SUCCESSFUL_ACTION_EXECUTED_EVENT);
928 assertThat(transportedEvents).contains(failedActionExecutedEvent);
929 }
930
931 @Test
932 public void testSuccessfulActionsCanBePublished() {
933 EventBusHandler handler = new EventBusHandler();
934 eventBus.register(handler);
935
936 BuildEventStreamOptions options = new BuildEventStreamOptions();
937 options.publishAllActions = true;
938
939 RecordingBuildEventTransport transport = new RecordingBuildEventTransport();
940 BuildEventStreamer streamer =
941 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), reporter, options);
942
943 ActionExecutedEvent failedActionExecutedEvent =
944 new ActionExecutedEvent(
945 new ActionsTestUtil.NullAction(),
946 new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
tomlud56a8062018-08-01 13:20:41 -0700947 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -0800948 /* stdout= */ null,
949 /* stderr= */ null,
950 ErrorTiming.BEFORE_EXECUTION);
951
952 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
953 streamer.buildEvent(failedActionExecutedEvent);
954
955 List<BuildEvent> transportedEvents = transport.getEvents();
956
957 assertThat(transportedEvents).contains(SUCCESSFUL_ACTION_EXECUTED_EVENT);
958 assertThat(transportedEvents).contains(failedActionExecutedEvent);
959 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000960}