blob: 6da3ca7444ed7778d32ead82fe01da90fb167e57 [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;
gregcee495e6b2019-04-30 14:07:06 -070041import com.google.devtools.build.lib.analysis.config.CoreOptions;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -040042import com.google.devtools.build.lib.analysis.config.FragmentOptions;
buchgr9e0308e2017-04-25 16:38:45 +020043import com.google.devtools.build.lib.buildeventstream.AnnounceBuildEventTransportsEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000044import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
Klaus Aehlig17325a12016-09-30 15:45:27 +000045import com.google.devtools.build.lib.buildeventstream.BuildEvent;
felly75a422a2019-01-17 14:52:49 -080046import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
ulfjack26e586d2018-05-17 08:42:13 -070047import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
Klaus Aehlig17325a12016-09-30 15:45:27 +000048import com.google.devtools.build.lib.buildeventstream.BuildEventId;
ulfjackfbf27562018-05-18 12:46:54 -070049import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
Klaus Aehligf75878d2016-11-21 13:41:16 +000050import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
Googlerd990a0a2019-05-13 16:46:42 -070051import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.Aborted.AbortReason;
Klaus Aehligee3e1922017-04-07 14:25:27 +000052import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.NamedSetOfFilesId;
Klaus Aehlig17325a12016-09-30 15:45:27 +000053import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
lberkid2630092018-11-22 09:12:34 -080054import com.google.devtools.build.lib.buildeventstream.BuildEventTransportClosedEvent;
Klaus Aehliga708a022017-07-11 12:54:40 +020055import com.google.devtools.build.lib.buildeventstream.BuildEventWithConfiguration;
Klaus Aehligf75878d2016-11-21 13:41:16 +000056import com.google.devtools.build.lib.buildeventstream.BuildEventWithOrderConstraint;
Klaus Aehlig17325a12016-09-30 15:45:27 +000057import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000058import com.google.devtools.build.lib.buildeventstream.PathConverter;
Klaus Aehlig17325a12016-09-30 15:45:27 +000059import com.google.devtools.build.lib.buildeventstream.ProgressEvent;
ruperts76de73b2018-03-02 16:10:43 -080060import com.google.devtools.build.lib.buildeventstream.transports.BuildEventStreamOptions;
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +000061import com.google.devtools.build.lib.buildtool.BuildResult;
Klaus Aehlig17325a12016-09-30 15:45:27 +000062import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
Googlerd990a0a2019-05-13 16:46:42 -070063import com.google.devtools.build.lib.buildtool.buildevent.NoAnalyzeEvent;
Klaus Aehligee3e1922017-04-07 14:25:27 +000064import com.google.devtools.build.lib.collect.nestedset.NestedSet;
65import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
66import com.google.devtools.build.lib.collect.nestedset.NestedSetView;
67import com.google.devtools.build.lib.testutil.FoundationTestCase;
Googlerd990a0a2019-05-13 16:46:42 -070068import com.google.devtools.build.lib.util.ExitCode;
felly17594762019-02-07 15:24:32 -080069import com.google.devtools.build.lib.util.Pair;
Klaus Aehligee3e1922017-04-07 14:25:27 +000070import com.google.devtools.build.lib.vfs.Path;
71import com.google.devtools.build.lib.vfs.PathFragment;
tomluee6a6862018-01-17 14:36:26 -080072import com.google.devtools.build.lib.vfs.Root;
ulfjackfbf27562018-05-18 12:46:54 -070073import com.google.devtools.common.options.Options;
Klaus Aehlig17325a12016-09-30 15:45:27 +000074import java.util.ArrayList;
Klaus Aehligf75878d2016-11-21 13:41:16 +000075import java.util.Collection;
buchgr9e0308e2017-04-25 16:38:45 +020076import java.util.Collections;
77import java.util.HashSet;
Klaus Aehlig17325a12016-09-30 15:45:27 +000078import java.util.List;
buchgr9e0308e2017-04-25 16:38:45 +020079import java.util.Set;
fellya4488a22019-04-03 13:05:47 -070080import java.util.concurrent.LinkedBlockingQueue;
81import java.util.concurrent.ThreadPoolExecutor;
lberkid2630092018-11-22 09:12:34 -080082import java.util.concurrent.TimeUnit;
fellya4488a22019-04-03 13:05:47 -070083import java.util.concurrent.atomic.AtomicInteger;
lberkid2630092018-11-22 09:12:34 -080084import java.util.concurrent.locks.LockSupport;
Googlerd990a0a2019-05-13 16:46:42 -070085import javax.annotation.Nullable;
fellya4488a22019-04-03 13:05:47 -070086import org.apache.commons.lang.time.StopWatch;
lpino0361ff62019-02-12 22:52:59 -080087import org.junit.After;
buchgr9e0308e2017-04-25 16:38:45 +020088import org.junit.Before;
fellya4488a22019-04-03 13:05:47 -070089import org.junit.Ignore;
Klaus Aehlig17325a12016-09-30 15:45:27 +000090import org.junit.Test;
91import org.junit.runner.RunWith;
92import org.junit.runners.JUnit4;
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +020093import org.mockito.Mockito;
buchgr9e0308e2017-04-25 16:38:45 +020094import org.mockito.MockitoAnnotations;
Klaus Aehlig17325a12016-09-30 15:45:27 +000095
96/** Tests {@link BuildEventStreamer}. */
97@RunWith(JUnit4.class)
Klaus Aehligee3e1922017-04-07 14:25:27 +000098public class BuildEventStreamerTest extends FoundationTestCase {
lpino0361ff62019-02-12 22:52:59 -080099 private CountingArtifactGroupNamer artifactGroupNamer;
100 private RecordingBuildEventTransport transport;
101 private BuildEventStreamer streamer;
102
103 @Before
104 public void setUp() {
105 artifactGroupNamer = new CountingArtifactGroupNamer();
fellya4488a22019-04-03 13:05:47 -0700106 transport = new RecordingBuildEventTransport(artifactGroupNamer, true);
lpino0361ff62019-02-12 22:52:59 -0800107 streamer =
lpino5bec36c2019-03-21 09:50:52 -0700108 new BuildEventStreamer(ImmutableSet.<BuildEventTransport>of(transport), artifactGroupNamer);
lpino0361ff62019-02-12 22:52:59 -0800109 }
110
111 @After
112 public void tearDown() {
113 artifactGroupNamer = null;
114 transport = null;
115 streamer = null;
116 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000117
ruperts76de73b2018-03-02 16:10:43 -0800118 private static final ActionExecutedEvent SUCCESSFUL_ACTION_EXECUTED_EVENT =
119 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -0700120 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -0800121 new ActionsTestUtil.NullAction(),
122 /* exception= */ null,
tomlud56a8062018-08-01 13:20:41 -0700123 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -0800124 /* stdout= */ null,
125 /* stderr= */ null,
126 ErrorTiming.NO_ERROR);
127
Klaus Aehlig17325a12016-09-30 15:45:27 +0000128 private static class RecordingBuildEventTransport implements BuildEventTransport {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000129 private final List<BuildEvent> events = new ArrayList<>();
130 private final List<BuildEventStreamProtos.BuildEvent> eventsAsProtos = new ArrayList<>();
lpino0361ff62019-02-12 22:52:59 -0800131 private ArtifactGroupNamer artifactGroupNamer;
132
fellya4488a22019-04-03 13:05:47 -0700133 RecordingBuildEventTransport(ArtifactGroupNamer namer, boolean recordEvents) {
lpino0361ff62019-02-12 22:52:59 -0800134 this.artifactGroupNamer = namer;
135 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000136
137 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200138 public String name() {
139 return this.getClass().getSimpleName();
140 }
141
142 @Override
fellya4488a22019-04-03 13:05:47 -0700143 public synchronized void sendBuildEvent(BuildEvent event) {
Klaus Aehlig17325a12016-09-30 15:45:27 +0000144 events.add(event);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000145 eventsAsProtos.add(
146 event.asStreamProto(
ulfjack26e586d2018-05-17 08:42:13 -0700147 new BuildEventContext() {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000148 @Override
149 public ArtifactGroupNamer artifactGroupNamer() {
lpino0361ff62019-02-12 22:52:59 -0800150 return artifactGroupNamer;
Klaus Aehligee3e1922017-04-07 14:25:27 +0000151 }
152
153 @Override
154 public PathConverter pathConverter() {
155 return new PathConverter() {
156 @Override
157 public String apply(Path path) {
158 return path.toString();
159 }
160 };
161 }
ulfjackfbf27562018-05-18 12:46:54 -0700162
163 @Override
164 public BuildEventProtocolOptions getOptions() {
165 return Options.getDefaults(BuildEventProtocolOptions.class);
166 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000167 }));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000168 }
169
170 @Override
buchgr9e0308e2017-04-25 16:38:45 +0200171 public ListenableFuture<Void> close() {
buchgr0b937432017-04-06 18:54:22 +0000172 return Futures.immediateFuture(null);
173 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000174
felly75a422a2019-01-17 14:52:49 -0800175 @Override
176 public BuildEventArtifactUploader getUploader() {
177 throw new IllegalStateException();
178 }
179
Klaus Aehlig17325a12016-09-30 15:45:27 +0000180 List<BuildEvent> getEvents() {
181 return events;
182 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000183
184 List<BuildEventStreamProtos.BuildEvent> getEventProtos() {
185 return eventsAsProtos;
186 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000187 }
188
Klaus Aehligf75878d2016-11-21 13:41:16 +0000189 private static class GenericOrderEvent implements BuildEventWithOrderConstraint {
190 private final BuildEventId id;
191 private final Collection<BuildEventId> children;
192 private final Collection<BuildEventId> after;
193
194 GenericOrderEvent(
195 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEventId> after) {
196 this.id = id;
197 this.children = children;
198 this.after = after;
199 }
200
201 GenericOrderEvent(BuildEventId id, Collection<BuildEventId> children) {
202 this(id, children, children);
203 }
204
205 @Override
206 public BuildEventId getEventId() {
207 return id;
208 }
209
210 @Override
211 public Collection<BuildEventId> getChildrenEvents() {
212 return children;
213 }
214
215 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700216 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000217 return GenericBuildEvent.protoChaining(this).build();
218 }
219
220 @Override
221 public Collection<BuildEventId> postedAfter() {
222 return after;
223 }
224 }
225
Klaus Aehligee3e1922017-04-07 14:25:27 +0000226 private static class GenericArtifactReportingEvent implements EventReportingArtifacts {
227 private final BuildEventId id;
228 private final Collection<BuildEventId> children;
229 private final Collection<NestedSet<Artifact>> artifacts;
230
231 GenericArtifactReportingEvent(
232 BuildEventId id,
233 Collection<BuildEventId> children,
234 Collection<NestedSet<Artifact>> artifacts) {
235 this.id = id;
236 this.children = children;
237 this.artifacts = artifacts;
238 }
239
240 GenericArtifactReportingEvent(BuildEventId id, Collection<NestedSet<Artifact>> artifacts) {
241 this(id, ImmutableSet.<BuildEventId>of(), artifacts);
242 }
243
244 @Override
245 public BuildEventId getEventId() {
246 return id;
247 }
248
249 @Override
250 public Collection<BuildEventId> getChildrenEvents() {
251 return children;
252 }
253
254 @Override
tomlu04e92812018-08-02 11:49:08 -0700255 public ReportedArtifacts reportedArtifacts() {
256 return new ReportedArtifacts(artifacts, ArtifactPathResolver.IDENTITY);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000257 }
258
259 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700260 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehligee3e1922017-04-07 14:25:27 +0000261 BuildEventStreamProtos.NamedSetOfFiles.Builder builder =
262 BuildEventStreamProtos.NamedSetOfFiles.newBuilder();
263 for (NestedSet<Artifact> artifactset : artifacts) {
264 builder.addFileSets(
265 converters
266 .artifactGroupNamer()
267 .apply((new NestedSetView<Artifact>(artifactset)).identifier()));
268 }
269 return GenericBuildEvent.protoChaining(this).setNamedSetOfFiles(builder.build()).build();
270 }
271 }
272
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400273 private static class GenericConfigurationEvent implements BuildEventWithConfiguration {
274 private final BuildEventId id;
275 private final Collection<BuildEventId> children;
Klaus Aehliga708a022017-07-11 12:54:40 +0200276 private final Collection<BuildEvent> configurations;
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400277
278 GenericConfigurationEvent(
Klaus Aehliga708a022017-07-11 12:54:40 +0200279 BuildEventId id, Collection<BuildEventId> children, Collection<BuildEvent> configurations) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400280 this.id = id;
281 this.children = children;
282 this.configurations = configurations;
283 }
284
Klaus Aehliga708a022017-07-11 12:54:40 +0200285 GenericConfigurationEvent(BuildEventId id, BuildEvent configuration) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400286 this(id, ImmutableSet.<BuildEventId>of(), ImmutableSet.of(configuration));
287 }
288
289 @Override
290 public BuildEventId getEventId() {
291 return id;
292 }
293
294 @Override
295 public Collection<BuildEventId> getChildrenEvents() {
296 return children;
297 }
298
299 @Override
Klaus Aehliga708a022017-07-11 12:54:40 +0200300 public Collection<BuildEvent> getConfigurations() {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400301 return configurations;
302 }
303
304 @Override
ulfjack26e586d2018-05-17 08:42:13 -0700305 public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400306 return GenericBuildEvent.protoChaining(this).build();
307 }
308 }
309
Klaus Aehlig17325a12016-09-30 15:45:27 +0000310 private static BuildEventId testId(String opaque) {
311 return BuildEventId.unknownBuildEventId(opaque);
312 }
313
buchgr9e0308e2017-04-25 16:38:45 +0200314 private static class EventBusHandler {
315
316 Set<BuildEventTransport> transportSet;
317
318 @Subscribe
319 void transportsAnnounced(AnnounceBuildEventTransportsEvent evt) {
320 transportSet = Collections.synchronizedSet(new HashSet<>(evt.transports()));
321 }
lberkid2630092018-11-22 09:12:34 -0800322
323 @Subscribe
324 void transportClosed(BuildEventTransportClosedEvent evt) {
325 transportSet.remove(evt.transport());
326 }
buchgr9e0308e2017-04-25 16:38:45 +0200327 }
328
329 @Before
330 public void setup() {
331 MockitoAnnotations.initMocks(this);
332 }
333
334 @Test(timeout = 5000)
Klaus Aehlig17325a12016-09-30 15:45:27 +0000335 public void testSimpleStream() {
336 // Verify that a well-formed event is passed through and that completion of the
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200337 // build clears the pending progress-update event. However, there is no guarantee
338 // on the order of the flushed events.
339 // Additionally, assert that the actual last event has the last_message flag set.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000340
buchgr9e0308e2017-04-25 16:38:45 +0200341 EventBusHandler handler = new EventBusHandler();
342 eventBus.register(handler);
lberkiaea56b32017-05-30 12:35:33 +0200343 assertThat(handler.transportSet).isNull();
buchgr9e0308e2017-04-25 16:38:45 +0200344
lpino5bec36c2019-03-21 09:50:52 -0700345 eventBus.post(new AnnounceBuildEventTransportsEvent(ImmutableSet.of(transport)));
346
Klaus Aehlig17325a12016-09-30 15:45:27 +0000347 BuildEvent startEvent =
348 new GenericBuildEvent(
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000349 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE,
350 BuildEventId.buildFinished()));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000351
352 streamer.buildEvent(startEvent);
353
aehlig03d55f32017-10-26 11:45:35 +0200354 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000355 List<BuildEvent> afterFirstEvent = transport.getEvents();
356 assertThat(afterFirstEvent).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200357 assertThat(afterFirstEvent.get(0).getEventId()).isEqualTo(startEvent.getEventId());
358 assertThat(handler.transportSet).hasSize(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000359
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000360 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000361
aehlig03d55f32017-10-26 11:45:35 +0200362 assertThat(streamer.isClosed()).isTrue();
lpino5bec36c2019-03-21 09:50:52 -0700363 eventBus.post(new BuildEventTransportClosedEvent(transport));
364
Klaus Aehlig17325a12016-09-30 15:45:27 +0000365 List<BuildEvent> finalStream = transport.getEvents();
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000366 assertThat(finalStream).hasSize(3);
Klaus Aehligfb3c5722017-07-10 13:08:19 +0200367 assertThat(ImmutableSet.of(finalStream.get(1).getEventId(), finalStream.get(2).getEventId()))
368 .isEqualTo(
369 ImmutableSet.of(BuildEventId.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
370
371 // verify the "last_message" flag.
372 assertThat(transport.getEventProtos().get(0).getLastMessage()).isFalse();
373 assertThat(transport.getEventProtos().get(1).getLastMessage()).isFalse();
374 assertThat(transport.getEventProtos().get(2).getLastMessage()).isTrue();
lberkid2630092018-11-22 09:12:34 -0800375
376 while (!handler.transportSet.isEmpty()) {
377 LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100));
378 }
Klaus Aehlig17325a12016-09-30 15:45:27 +0000379 }
380
381 @Test
382 public void testChaining() {
383 // Verify that unannounced events are linked in with progress update events, assuming
384 // a correctly formed initial event.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000385 BuildEvent startEvent =
386 new GenericBuildEvent(
387 testId("Initial"), ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000388 BuildEvent unexpectedEvent =
389 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000390
391 streamer.buildEvent(startEvent);
392 streamer.buildEvent(unexpectedEvent);
393
aehlig03d55f32017-10-26 11:45:35 +0200394 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000395 List<BuildEvent> eventsSeen = transport.getEvents();
396 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200397 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
398 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000399 BuildEvent linkEvent = eventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200400 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
401 assertWithMessage("Unexpected events should be linked")
402 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
403 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000404 }
405
406 @Test
407 public void testBadInitialEvent() {
408 // Verify that, if the initial event does not announce the initial progress update event,
409 // the initial progress event is used instead to chain that event; in this way, new
410 // progress updates can always be chained in.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000411 BuildEvent unexpectedStartEvent =
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000412 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000413
414 streamer.buildEvent(unexpectedStartEvent);
415
416 List<BuildEvent> eventsSeen = transport.getEvents();
417 assertThat(eventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200418 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000419 BuildEvent initial = eventsSeen.get(0);
lberkiaea56b32017-05-30 12:35:33 +0200420 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
421 assertWithMessage("Event should be linked")
422 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
423 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000424
425 // The initial event should also announce a new progress event; we test this
426 // by streaming another unannounced event.
427
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000428 BuildEvent unexpectedEvent =
429 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000430
431 streamer.buildEvent(unexpectedEvent);
aehlig03d55f32017-10-26 11:45:35 +0200432
433 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000434 List<BuildEvent> allEventsSeen = transport.getEvents();
435 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200436 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000437 BuildEvent secondLinkEvent = allEventsSeen.get(2);
lberkiaea56b32017-05-30 12:35:33 +0200438 assertWithMessage("Progress should have been announced")
439 .that(initial.getChildrenEvents().contains(secondLinkEvent.getEventId()))
440 .isTrue();
441 assertWithMessage("Second event should be linked")
442 .that(secondLinkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
443 .isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000444 }
445
446 @Test
447 public void testReferPastEvent() {
448 // Verify that, if an event is refers to a previously done event, that duplicated
449 // late-referenced event is not expected again.
Klaus Aehlig17325a12016-09-30 15:45:27 +0000450 BuildEvent startEvent =
451 new GenericBuildEvent(
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000452 testId("Initial"),
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000453 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE,
454 BuildEventId.buildFinished()));
Klaus Aehlig2b1eec32016-10-05 09:21:45 +0000455 BuildEvent earlyEvent =
456 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
Klaus Aehlig17325a12016-09-30 15:45:27 +0000457 BuildEvent lateReference =
458 new GenericBuildEvent(testId("late reference"), ImmutableSet.of(earlyEvent.getEventId()));
459
460 streamer.buildEvent(startEvent);
461 streamer.buildEvent(earlyEvent);
462 streamer.buildEvent(lateReference);
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000463 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehlig17325a12016-09-30 15:45:27 +0000464
aehlig03d55f32017-10-26 11:45:35 +0200465 assertThat(streamer.isClosed()).isTrue();
Klaus Aehlig17325a12016-09-30 15:45:27 +0000466 List<BuildEvent> eventsSeen = transport.getEvents();
467 int earlyEventCount = 0;
468 for (BuildEvent event : eventsSeen) {
469 if (event.getEventId().equals(earlyEvent.getEventId())) {
470 earlyEventCount++;
471 }
472 }
473 // The early event should be reported precisely once.
lberkiaea56b32017-05-30 12:35:33 +0200474 assertThat(earlyEventCount).isEqualTo(1);
Klaus Aehlig17325a12016-09-30 15:45:27 +0000475 }
Klaus Aehligf75878d2016-11-21 13:41:16 +0000476
477 @Test
felly17594762019-02-07 15:24:32 -0800478 public void testReordering() {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000479 // Verify that an event requiring to be posted after another one is indeed.
Klaus Aehligf75878d2016-11-21 13:41:16 +0000480 BuildEventId expectedId = testId("the target");
481 BuildEvent startEvent =
482 new GenericBuildEvent(
483 testId("Initial"),
484 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, expectedId));
485 BuildEvent rootCause =
486 new GenericBuildEvent(testId("failure event"), ImmutableSet.<BuildEventId>of());
487 BuildEvent failedTarget =
488 new GenericOrderEvent(expectedId, ImmutableSet.<BuildEventId>of(rootCause.getEventId()));
489
490 streamer.buildEvent(startEvent);
491 streamer.buildEvent(failedTarget);
492 streamer.buildEvent(rootCause);
493
aehlig03d55f32017-10-26 11:45:35 +0200494 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligf75878d2016-11-21 13:41:16 +0000495 List<BuildEvent> allEventsSeen = transport.getEvents();
496 assertThat(allEventsSeen).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200497 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000498 BuildEvent linkEvent = allEventsSeen.get(1);
lberkiaea56b32017-05-30 12:35:33 +0200499 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
500 assertThat(allEventsSeen.get(2).getEventId()).isEqualTo(rootCause.getEventId());
501 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(failedTarget.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000502 }
503
fellya4488a22019-04-03 13:05:47 -0700504 private static BuildEvent indexOrderedBuildEvent(int index, int afterIndex) {
505 return new GenericOrderEvent(
506 testId("Concurrent-" + index),
507 ImmutableList.of(),
508 afterIndex == -1
509 ? ImmutableList.of()
510 : ImmutableList.of(testId("Concurrent-" + afterIndex)));
511 }
512
513 @Test
514 public void testConcurrency() throws Exception {
515 // Verify that we can blast the BuildEventStreamer with many build events in parallel without
516 // violating internal consistency. The thread-safety under test is primarily sensitive to the
517 // pendingEvents field constructed when there are ordering constraints, so we make sure to
518 // include such ordering constraints in this test.
519 BuildEvent startEvent =
520 new GenericBuildEvent(
521 testId("Initial"),
522 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
523 streamer.buildEvent(startEvent);
524
525 int numThreads = 12;
526 int numEventsPerThread = 10_000;
527 int totalEvents = numThreads * numEventsPerThread;
528 AtomicInteger idIndex = new AtomicInteger();
529 ThreadPoolExecutor pool =
530 new ThreadPoolExecutor(
531 numThreads,
532 numThreads,
533 /* keepAliveTime= */ 0,
534 TimeUnit.SECONDS,
535 /* workQueue= */ new LinkedBlockingQueue<>());
536
537 for (int i = 0; i < numThreads; i++) {
538 pool.execute(
539 () -> {
540 for (int j = 0; j < numEventsPerThread; j++) {
541 int index = idIndex.getAndIncrement();
542 // Arrange for half of the events to have an ordering constraint on the subsequent
543 // event. The ordering graph must avoid cycles.
544 int afterIndex = (index % 2 == 0) ? (index + 1) % totalEvents : -1;
545 streamer.buildEvent(indexOrderedBuildEvent(index, afterIndex));
546 }
547 });
548 }
549
550 pool.shutdown();
551 pool.awaitTermination(1, TimeUnit.DAYS);
552
553 BuildEventId lateId = testId("late event");
554 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId)));
555 assertThat(streamer.isClosed()).isFalse();
556 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
557 assertThat(streamer.isClosed()).isTrue();
558
559 List<BuildEvent> eventsSeen = transport.getEvents();
560 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
561 assertThat(eventsSeen).hasSize(4 + totalEvents * 2);
562 }
563
564 // Re-enable this "test" for ad-hoc benchmarking of many concurrent build events.
565 @Ignore
566 public void concurrencyBenchmark() throws Exception {
567 long time = 0;
568 for (int iteration = 0; iteration < 3; iteration++) {
569 StopWatch watch = new StopWatch();
570 watch.start();
571
572 transport = new RecordingBuildEventTransport(artifactGroupNamer, /*recordEvents=*/ false);
573 streamer =
574 new BuildEventStreamer(
575 ImmutableSet.<BuildEventTransport>of(transport), artifactGroupNamer);
576 BuildEvent startEvent =
577 new GenericBuildEvent(
578 testId("Initial"),
579 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
580 streamer.buildEvent(startEvent);
581
582 int numThreads = 12;
583 int numEventsPerThread = 100_000;
584 int totalEvents = numThreads * numEventsPerThread;
585 AtomicInteger idIndex = new AtomicInteger();
586 ThreadPoolExecutor pool =
587 new ThreadPoolExecutor(
588 numThreads, numThreads, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
589
590 for (int i = 0; i < numThreads; i++) {
591 pool.execute(
592 () -> {
593 for (int j = 0; j < numEventsPerThread; j++) {
594 int index = idIndex.getAndIncrement();
595 // Arrange for half of the events to have an ordering constraint on the subsequent
596 // event. The ordering graph must avoid cycles.
597 int afterIndex = (index % 2 == 0) ? (index + 1) % totalEvents : -1;
598 streamer.buildEvent(indexOrderedBuildEvent(index, afterIndex));
599 }
600 });
601 }
602
603 pool.shutdown();
604 pool.awaitTermination(1, TimeUnit.DAYS);
605 watch.stop();
606
607 time += watch.getTime();
608
609 BuildEventId lateId = testId("late event");
610 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId)));
611 assertThat(streamer.isClosed()).isFalse();
612 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
613 assertThat(streamer.isClosed()).isTrue();
614 }
615
616 System.err.println();
617 System.err.println("=============================================================");
618 System.err.println("Concurrent performance of BEP build event processing: " + time + "ms");
619 System.err.println("=============================================================");
620 }
621
Klaus Aehligf75878d2016-11-21 13:41:16 +0000622 @Test
felly21c25822018-12-28 13:29:52 -0800623 public void testMissingPrerequisites() {
Klaus Aehligf75878d2016-11-21 13:41:16 +0000624 // Verify that an event where the prerequisite is never coming till the end of
625 // the build still gets posted, with the prerequisite aborted.
Klaus Aehligf75878d2016-11-21 13:41:16 +0000626 BuildEventId expectedId = testId("the target");
627 BuildEvent startEvent =
628 new GenericBuildEvent(
629 testId("Initial"),
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000630 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, expectedId,
631 BuildEventId.buildFinished()));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000632 BuildEventId rootCauseId = testId("failure event");
633 BuildEvent failedTarget =
634 new GenericOrderEvent(expectedId, ImmutableSet.<BuildEventId>of(rootCauseId));
635
636 streamer.buildEvent(startEvent);
637 streamer.buildEvent(failedTarget);
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000638 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
Klaus Aehligf75878d2016-11-21 13:41:16 +0000639
aehlig03d55f32017-10-26 11:45:35 +0200640 assertThat(streamer.isClosed()).isTrue();
Klaus Aehligf75878d2016-11-21 13:41:16 +0000641 List<BuildEvent> allEventsSeen = transport.getEvents();
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000642 assertThat(allEventsSeen).hasSize(6);
lberkiaea56b32017-05-30 12:35:33 +0200643 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
644 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
Jakob Buchgraber8c3a4ef2017-02-28 18:49:50 +0000645 BuildEvent linkEvent = allEventsSeen.get(2);
lberkiaea56b32017-05-30 12:35:33 +0200646 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
647 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(rootCauseId);
648 assertThat(allEventsSeen.get(4).getEventId()).isEqualTo(failedTarget.getEventId());
Klaus Aehligf75878d2016-11-21 13:41:16 +0000649 }
Klaus Aehligceb0f622017-03-20 13:52:06 +0000650
651 @Test
652 public void testVeryFirstEventNeedsToWait() {
653 // Verify that we can handle an first event waiting for another event.
Klaus Aehligceb0f622017-03-20 13:52:06 +0000654 BuildEventId initialId = testId("Initial");
655 BuildEventId waitId = testId("Waiting for initial event");
656 BuildEvent startEvent =
657 new GenericBuildEvent(
658 initialId,
659 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE, waitId));
660 BuildEvent waitingForStart =
661 new GenericOrderEvent(waitId, ImmutableSet.<BuildEventId>of(), ImmutableSet.of(initialId));
662
663 streamer.buildEvent(waitingForStart);
664 streamer.buildEvent(startEvent);
665
aehlig03d55f32017-10-26 11:45:35 +0200666 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligceb0f622017-03-20 13:52:06 +0000667 List<BuildEvent> allEventsSeen = transport.getEvents();
668 assertThat(allEventsSeen).hasSize(2);
lberkiaea56b32017-05-30 12:35:33 +0200669 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
670 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(waitingForStart.getEventId());
Klaus Aehligceb0f622017-03-20 13:52:06 +0000671 }
Klaus Aehligee3e1922017-04-07 14:25:27 +0000672
673 private Artifact makeArtifact(String pathString) {
674 Path path = outputBase.getRelative(PathFragment.create(pathString));
tomluee6a6862018-01-17 14:36:26 -0800675 return new Artifact(path, ArtifactRoot.asSourceRoot(Root.fromPath(outputBase)));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000676 }
677
678 @Test
679 public void testReportedArtifacts() {
680 // Verify that reported artifacts are correctly unfolded into the stream
Klaus Aehligee3e1922017-04-07 14:25:27 +0000681 BuildEvent startEvent =
682 new GenericBuildEvent(
683 testId("Initial"),
684 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
685
686 Artifact a = makeArtifact("path/a");
687 Artifact b = makeArtifact("path/b");
688 Artifact c = makeArtifact("path/c");
689 NestedSet<Artifact> innerGroup = NestedSetBuilder.<Artifact>stableOrder().add(a).add(b).build();
690 NestedSet<Artifact> group =
691 NestedSetBuilder.<Artifact>stableOrder().addTransitive(innerGroup).add(c).build();
692 BuildEvent reportingArtifacts =
693 new GenericArtifactReportingEvent(testId("reporting"), ImmutableSet.of(group));
694
695 streamer.buildEvent(startEvent);
696 streamer.buildEvent(reportingArtifacts);
697
aehlig03d55f32017-10-26 11:45:35 +0200698 assertThat(streamer.isClosed()).isFalse();
Klaus Aehligee3e1922017-04-07 14:25:27 +0000699 List<BuildEvent> allEventsSeen = transport.getEvents();
700 List<BuildEventStreamProtos.BuildEvent> eventProtos = transport.getEventProtos();
lberkiaea56b32017-05-30 12:35:33 +0200701 assertThat(allEventsSeen).hasSize(7);
702 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
703 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
Klaus Aehligee3e1922017-04-07 14:25:27 +0000704 List<BuildEventStreamProtos.File> firstSetDirects =
705 eventProtos.get(2).getNamedSetOfFiles().getFilesList();
lberkiaea56b32017-05-30 12:35:33 +0200706 assertThat(firstSetDirects).hasSize(2);
707 assertThat(ImmutableSet.of(firstSetDirects.get(0).getUri(), firstSetDirects.get(1).getUri()))
708 .isEqualTo(ImmutableSet.of(a.getPath().toString(), b.getPath().toString()));
Klaus Aehligee3e1922017-04-07 14:25:27 +0000709 List<NamedSetOfFilesId> secondSetTransitives =
710 eventProtos.get(4).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200711 assertThat(secondSetTransitives).hasSize(1);
712 assertThat(secondSetTransitives.get(0)).isEqualTo(eventProtos.get(2).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000713 List<NamedSetOfFilesId> reportedArtifactSets =
714 eventProtos.get(6).getNamedSetOfFiles().getFileSetsList();
lberkiaea56b32017-05-30 12:35:33 +0200715 assertThat(reportedArtifactSets).hasSize(1);
716 assertThat(reportedArtifactSets.get(0)).isEqualTo(eventProtos.get(4).getId().getNamedSet());
Klaus Aehligee3e1922017-04-07 14:25:27 +0000717 }
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200718
719 @Test
720 public void testStdoutReported() {
721 // Verify that stdout and stderr are reported in the build-event stream on progress
722 // events.
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200723 BuildEventStreamer.OutErrProvider outErr =
724 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
725 String stdoutMsg = "Some text that was written to stdout.";
726 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -0800727 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
728 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200729 BuildEvent startEvent =
730 new GenericBuildEvent(
731 testId("Initial"),
732 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
733 BuildEvent unexpectedEvent =
734 new GenericBuildEvent(testId("unexpected"), ImmutableSet.<BuildEventId>of());
735
736 streamer.registerOutErrProvider(outErr);
737 streamer.buildEvent(startEvent);
738 streamer.buildEvent(unexpectedEvent);
739
aehlig03d55f32017-10-26 11:45:35 +0200740 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200741 List<BuildEvent> eventsSeen = transport.getEvents();
742 assertThat(eventsSeen).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200743 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
744 assertThat(eventsSeen.get(2).getEventId()).isEqualTo(unexpectedEvent.getEventId());
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200745 BuildEvent linkEvent = eventsSeen.get(1);
746 BuildEventStreamProtos.BuildEvent linkEventProto = transport.getEventProtos().get(1);
lberkiaea56b32017-05-30 12:35:33 +0200747 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
748 assertWithMessage("Unexpected events should be linked")
749 .that(linkEvent.getChildrenEvents().contains(unexpectedEvent.getEventId()))
750 .isTrue();
751 assertThat(linkEventProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
752 assertThat(linkEventProto.getProgress().getStderr()).isEqualTo(stderrMsg);
Klaus Aehlig9b3b2e92017-05-02 11:18:42 +0200753
754 // As there is only one progress event, the OutErrProvider should be queried
755 // only once for stdout and stderr.
756 verify(outErr, times(1)).getOut();
757 verify(outErr, times(1)).getErr();
758 }
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400759
760 @Test
felly21c25822018-12-28 13:29:52 -0800761 public void testStdoutReportedAfterCrash() {
762 // Verify that stdout and stderr are reported in the build-event stream on progress
763 // events.
felly21c25822018-12-28 13:29:52 -0800764 BuildEventStreamer.OutErrProvider outErr =
765 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
766 String stdoutMsg = "Some text that was written to stdout.";
767 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -0800768 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
769 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
felly21c25822018-12-28 13:29:52 -0800770 BuildEvent startEvent =
771 new GenericBuildEvent(
772 testId("Initial"),
773 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
774
775 streamer.registerOutErrProvider(outErr);
776 streamer.buildEvent(startEvent);
777 // Simulate a crash with an abrupt call to #close().
778 streamer.close();
779 assertThat(streamer.isClosed()).isTrue();
780
781 List<BuildEvent> eventsSeen = transport.getEvents();
782 assertThat(eventsSeen).hasSize(2);
783 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
784 BuildEvent linkEvent = eventsSeen.get(1);
785 BuildEventStreamProtos.BuildEvent linkEventProto = transport.getEventProtos().get(1);
786 assertThat(linkEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
787 assertThat(linkEventProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
788 assertThat(linkEventProto.getProgress().getStderr()).isEqualTo(stderrMsg);
789
790 // As there is only one progress event, the OutErrProvider should be queried
791 // only once for stdout and stderr.
792 verify(outErr, times(1)).getOut();
793 verify(outErr, times(1)).getErr();
794 }
795
felly17594762019-02-07 15:24:32 -0800796 private static <T> ImmutableList<ImmutableList<Pair<T, T>>> consumeToLists(
797 Iterable<T> left, Iterable<T> right) {
798 ImmutableList.Builder<Pair<T, T>> consumerBuilder = ImmutableList.builder();
799 ImmutableList.Builder<Pair<T, T>> lastConsumerBuilder = ImmutableList.builder();
800
801 BuildEventStreamer.consumeAsPairs(
802 left,
803 right,
804 (t1, t2) -> consumerBuilder.add(Pair.of(t1, t2)),
805 (t1, t2) -> lastConsumerBuilder.add(Pair.of(t1, t2)));
806
807 return ImmutableList.of(consumerBuilder.build(), lastConsumerBuilder.build());
808 }
809
810 @Test
811 public void testConsumeAsPairs() {
812 assertThat(consumeToLists(ImmutableList.of(1, 2, 3), ImmutableList.of(4, 5, 6)))
813 .containsExactly(
814 ImmutableList.of(Pair.of(1, null), Pair.of(2, null), Pair.of(3, 4), Pair.of(null, 5)),
815 ImmutableList.of(Pair.of(null, 6)))
816 .inOrder();
817
818 assertThat(consumeToLists(ImmutableList.of(), ImmutableList.of()))
819 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(null, null)))
820 .inOrder();
821
822 assertThat(consumeToLists(ImmutableList.of(1), ImmutableList.of(2)))
823 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(1, 2)))
824 .inOrder();
825
826 assertThat(consumeToLists(ImmutableList.of(1), ImmutableList.of(2, 3)))
827 .containsExactly(ImmutableList.of(Pair.of(1, 2)), ImmutableList.of(Pair.of(null, 3)))
828 .inOrder();
829
830 assertThat(consumeToLists(ImmutableList.of(1, 2), ImmutableList.of()))
831 .containsExactly(ImmutableList.of(Pair.of(1, null)), ImmutableList.of(Pair.of(2, null)))
832 .inOrder();
833
834 assertThat(consumeToLists(ImmutableList.of(), ImmutableList.of(1)))
835 .containsExactly(ImmutableList.of(), ImmutableList.of(Pair.of(null, 1)))
836 .inOrder();
837 }
838
felly21c25822018-12-28 13:29:52 -0800839 @Test
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400840 public void testReportedConfigurations() throws Exception {
841 // Verify that configuration events are posted, but only once.
mjhalupka5d7fa7b2018-03-22 13:37:38 -0700842 BuildOptions defaultBuildOptions =
gregcee495e6b2019-04-30 14:07:06 -0700843 BuildOptions.of(ImmutableList.<Class<? extends FragmentOptions>>of(CoreOptions.class));
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400844 BuildEvent startEvent =
845 new GenericBuildEvent(
846 testId("Initial"),
847 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
848 BuildConfiguration configuration =
849 new BuildConfiguration(
janakr3b63a4e2017-09-14 09:55:40 +0200850 new BlazeDirectories(
Klaus Aehligc2499c42018-02-27 05:47:21 -0800851 new ServerDirectories(outputBase, outputBase, outputBase),
852 rootDirectory,
cushon849df362018-05-14 01:51:45 -0700853 /* defaultSystemJavabase= */ null,
Klaus Aehligc2499c42018-02-27 05:47:21 -0800854 "productName"),
lberki406199f2018-04-09 03:16:19 -0700855 /* fragmentsMap= */ ImmutableMap
janakr3b63a4e2017-09-14 09:55:40 +0200856 .<Class<? extends BuildConfiguration.Fragment>, BuildConfiguration.Fragment>of(),
mjhalupka5d7fa7b2018-03-22 13:37:38 -0700857 defaultBuildOptions,
858 BuildOptions.diffForReconstruction(defaultBuildOptions, defaultBuildOptions),
lberki406199f2018-04-09 03:16:19 -0700859 /* reservedActionMnemonics= */ ImmutableSet.of(),
lberki86266232018-04-11 00:33:42 -0700860 ActionEnvironment.EMPTY,
gregce85297462017-08-18 21:20:29 +0200861 "workspace");
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400862 BuildEvent firstWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800863 new GenericConfigurationEvent(testId("first"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400864 BuildEvent secondWithConfiguration =
shahan50f99d52018-03-10 05:14:09 -0800865 new GenericConfigurationEvent(testId("second"), configuration.toBuildEvent());
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400866
867 streamer.buildEvent(startEvent);
868 streamer.buildEvent(firstWithConfiguration);
869 streamer.buildEvent(secondWithConfiguration);
870
aehlig03d55f32017-10-26 11:45:35 +0200871 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400872 List<BuildEvent> allEventsSeen = transport.getEvents();
lberkiaea56b32017-05-30 12:35:33 +0200873 assertThat(allEventsSeen).hasSize(7);
874 assertThat(allEventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
875 assertThat(allEventsSeen.get(1).getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
shahan50f99d52018-03-10 05:14:09 -0800876 assertThat(allEventsSeen.get(2)).isEqualTo(configuration.toBuildEvent());
lberkiaea56b32017-05-30 12:35:33 +0200877 assertThat(allEventsSeen.get(3).getEventId()).isEqualTo(BuildEventId.progressId(1));
878 assertThat(allEventsSeen.get(4)).isEqualTo(firstWithConfiguration);
879 assertThat(allEventsSeen.get(5).getEventId()).isEqualTo(BuildEventId.progressId(2));
880 assertThat(allEventsSeen.get(6)).isEqualTo(secondWithConfiguration);
Klaus Aehlig0cce00c2017-05-08 08:26:03 -0400881 }
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200882
883 @Test
884 public void testEarlyFlush() throws Exception {
885 // Verify that the streamer can handle early calls to flush() and still correctly
886 // reports stdout and stderr in the build-event stream.
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200887 BuildEventStreamer.OutErrProvider outErr =
888 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
889 String firstStdoutMsg = "Some text that was written to stdout.";
890 String firstStderrMsg = "The UI text that bazel wrote to stderr.";
891 String secondStdoutMsg = "More text that was written to stdout, still before the start event.";
892 String secondStderrMsg = "More text written to stderr, still before the start event.";
felly17594762019-02-07 15:24:32 -0800893 when(outErr.getOut())
894 .thenReturn(ImmutableList.of(firstStdoutMsg))
895 .thenReturn(ImmutableList.of(secondStdoutMsg));
896 when(outErr.getErr())
897 .thenReturn(ImmutableList.of(firstStderrMsg))
898 .thenReturn(ImmutableList.of(secondStderrMsg));
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200899 BuildEvent startEvent =
900 new GenericBuildEvent(
901 testId("Initial"),
902 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
903
904 streamer.registerOutErrProvider(outErr);
905 streamer.flush();
906 streamer.flush();
907 streamer.buildEvent(startEvent);
908
aehlig03d55f32017-10-26 11:45:35 +0200909 assertThat(streamer.isClosed()).isFalse();
Klaus Aehlig8f6549f2017-06-26 15:30:55 +0200910 List<BuildEvent> eventsSeen = transport.getEvents();
911 assertThat(eventsSeen).hasSize(3);
912 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
913 BuildEvent progressEvent = eventsSeen.get(1);
914 assertThat(progressEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
915 BuildEventStreamProtos.BuildEvent progressEventProto = transport.getEventProtos().get(1);
916 assertThat(progressEventProto.getProgress().getStdout()).isEqualTo(firstStdoutMsg);
917 assertThat(progressEventProto.getProgress().getStderr()).isEqualTo(firstStderrMsg);
918 BuildEventStreamProtos.BuildEvent secondProgressEventProto = transport.getEventProtos().get(2);
919 assertThat(secondProgressEventProto.getProgress().getStdout()).isEqualTo(secondStdoutMsg);
920 assertThat(secondProgressEventProto.getProgress().getStderr()).isEqualTo(secondStderrMsg);
921
922 // As there is only one progress event, the OutErrProvider should be queried
923 // only once per flush() for stdout and stderr.
924 verify(outErr, times(2)).getOut();
925 verify(outErr, times(2)).getErr();
926 }
927
928 @Test
felly17594762019-02-07 15:24:32 -0800929 public void testChunkedFlush() throws Exception {
930 // Verify that the streamer calls to flush() that return multiple chunked buffers.
felly17594762019-02-07 15:24:32 -0800931 BuildEventStreamer.OutErrProvider outErr =
932 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
933 String firstStdoutMsg = "Some text that was written to stdout.";
934 String firstStderrMsg = "The UI text that bazel wrote to stderr.";
935 String secondStdoutMsg = "More text that was written to stdout, still before the start event.";
936 String secondStderrMsg = "More text written to stderr, still before the start event.";
937 when(outErr.getOut()).thenReturn(ImmutableList.of(firstStdoutMsg, secondStdoutMsg));
938 when(outErr.getErr()).thenReturn(ImmutableList.of(firstStderrMsg, secondStderrMsg));
939 BuildEvent startEvent =
940 new GenericBuildEvent(
941 testId("Initial"),
942 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
943
944 streamer.registerOutErrProvider(outErr);
945 streamer.buildEvent(startEvent);
946 streamer.flush();
947
948 assertThat(streamer.isClosed()).isFalse();
949 List<BuildEvent> eventsSeen = transport.getEvents();
950 assertThat(eventsSeen).hasSize(4);
951 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
952
953 // Expect to find 3 progress messages: (firstStdout, ""), (secondStdout, firstStderr),
954 // ("", secondStdErr). Assuming UIs display stdout first, this maintains ordering.
955 BuildEvent progressEvent = eventsSeen.get(1);
956 assertThat(progressEvent.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
957 BuildEventStreamProtos.BuildEvent progressEventProto = transport.getEventProtos().get(1);
958 assertThat(progressEventProto.getProgress().getStdout()).isEqualTo(firstStdoutMsg);
959 assertThat(progressEventProto.getProgress().getStderr()).isEmpty();
960
961 BuildEventStreamProtos.BuildEvent secondProgressEventProto = transport.getEventProtos().get(2);
962 assertThat(secondProgressEventProto.getProgress().getStdout()).isEqualTo(secondStdoutMsg);
963 assertThat(secondProgressEventProto.getProgress().getStderr()).isEqualTo(firstStderrMsg);
964
965 BuildEventStreamProtos.BuildEvent thirdProgressEventProto = transport.getEventProtos().get(3);
966 assertThat(thirdProgressEventProto.getProgress().getStdout()).isEmpty();
967 assertThat(thirdProgressEventProto.getProgress().getStderr()).isEqualTo(secondStderrMsg);
968
969 // The OutErrProvider should be queried only once per flush().
970 verify(outErr, times(1)).getOut();
971 verify(outErr, times(1)).getErr();
972 }
973
974 @Test
Klaus Aehlig28221ff2018-01-11 04:28:00 -0800975 public void testNoopFlush() throws Exception {
976 // Verify that the streamer ignores a flush, if neither stream produces any output.
Klaus Aehlig28221ff2018-01-11 04:28:00 -0800977 BuildEventStreamer.OutErrProvider outErr =
978 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
979 String stdoutMsg = "Some text that was written to stdout.";
980 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -0800981 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg)).thenReturn(ImmutableList.of());
982 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg)).thenReturn(ImmutableList.of());
Klaus Aehlig28221ff2018-01-11 04:28:00 -0800983 BuildEvent startEvent =
984 new GenericBuildEvent(
985 testId("Initial"),
986 ImmutableSet.<BuildEventId>of(ProgressEvent.INITIAL_PROGRESS_UPDATE));
987
988 streamer.registerOutErrProvider(outErr);
989 streamer.buildEvent(startEvent);
990 assertThat(transport.getEvents()).hasSize(1);
991 streamer.flush(); // Output, so a new progress event has to be added
992 assertThat(transport.getEvents()).hasSize(2);
993 streamer.flush(); // No further output, so no additional event should be generated.
994 assertThat(transport.getEvents()).hasSize(2);
995
996 assertThat(transport.getEvents().get(0)).isEqualTo(startEvent);
997 assertThat(transport.getEventProtos().get(1).getProgress().getStdout()).isEqualTo(stdoutMsg);
998 assertThat(transport.getEventProtos().get(1).getProgress().getStderr()).isEqualTo(stderrMsg);
999 }
1000
1001 @Test
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001002 public void testEarlyFlushBadInitialEvent() throws Exception {
1003 // Verify that an early flush works correctly with an unusual start event.
1004 // In this case, we expect 3 events in the stream, in that order:
jingwen68c57f02018-11-21 16:17:17 -08001005 // - an artificial progress event as initial event, to properly link in
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001006 // all events
1007 // - the unusal first event we have seen, and
1008 // - a progress event reporting the flushed messages.
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001009 BuildEventStreamer.OutErrProvider outErr =
1010 Mockito.mock(BuildEventStreamer.OutErrProvider.class);
1011 String stdoutMsg = "Some text that was written to stdout.";
1012 String stderrMsg = "The UI text that bazel wrote to stderr.";
felly17594762019-02-07 15:24:32 -08001013 when(outErr.getOut()).thenReturn(ImmutableList.of(stdoutMsg));
1014 when(outErr.getErr()).thenReturn(ImmutableList.of(stderrMsg));
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001015
1016 BuildEvent unexpectedStartEvent =
1017 new GenericBuildEvent(testId("unexpected start"), ImmutableSet.<BuildEventId>of());
1018
1019 streamer.registerOutErrProvider(outErr);
1020 streamer.flush();
1021 streamer.buildEvent(unexpectedStartEvent);
1022
aehlig03d55f32017-10-26 11:45:35 +02001023 assertThat(streamer.isClosed()).isFalse();
1024
Klaus Aehlig8f6549f2017-06-26 15:30:55 +02001025 List<BuildEvent> eventsSeen = transport.getEvents();
1026 assertThat(eventsSeen).hasSize(3);
1027
1028 BuildEvent initial = eventsSeen.get(0);
1029 assertThat(initial.getEventId()).isEqualTo(ProgressEvent.INITIAL_PROGRESS_UPDATE);
1030 BuildEventStreamProtos.BuildEvent initialProto = transport.getEventProtos().get(0);
1031 assertThat(initialProto.getProgress().getStdout()).isEmpty();
1032 assertThat(initialProto.getProgress().getStderr()).isEmpty();
1033
1034 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(unexpectedStartEvent.getEventId());
1035 assertWithMessage("Unexpected event should be linked")
1036 .that(initial.getChildrenEvents().contains(unexpectedStartEvent.getEventId()))
1037 .isTrue();
1038
1039 BuildEventStreamProtos.BuildEvent progressProto = transport.getEventProtos().get(2);
1040 assertThat(progressProto.getProgress().getStdout()).isEqualTo(stdoutMsg);
1041 assertThat(progressProto.getProgress().getStderr()).isEqualTo(stderrMsg);
1042 assertWithMessage("flushed progress should be linked")
1043 .that(initial.getChildrenEvents().contains(eventsSeen.get(2).getEventId()))
1044 .isTrue();
1045
1046 verify(outErr, times(1)).getOut();
1047 verify(outErr, times(1)).getErr();
1048 }
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001049
1050 @Test
1051 public void testEarlyAbort() throws Exception {
1052 // For a build that is aborted before a build-started event is generated,
1053 // we still expect that, if a build-started event is forced by some order
1054 // constraint (e.g., CommandLine wants to come after build started), then
1055 // that gets sorted to the beginning.
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001056 BuildEvent orderEvent =
1057 new GenericOrderEvent(
1058 testId("event depending on start"),
1059 ImmutableList.of(),
1060 ImmutableList.of(BuildEventId.buildStartedId()));
1061
1062 streamer.buildEvent(orderEvent);
1063 streamer.buildEvent(new BuildCompleteEvent(new BuildResult(0)));
1064
aehlig03d55f32017-10-26 11:45:35 +02001065 assertThat(streamer.isClosed()).isTrue();
Klaus Aehligdeea6b02017-10-16 12:32:20 +02001066 List<BuildEvent> eventsSeen = transport.getEvents();
1067 assertThat(eventsSeen).hasSize(4);
1068 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(BuildEventId.buildStartedId());
1069 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(orderEvent.getEventId());
1070 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1071 .isEqualTo(
1072 ImmutableSet.of(BuildEventId.buildFinished(), ProgressEvent.INITIAL_PROGRESS_UPDATE));
1073 assertThat(transport.getEventProtos().get(3).getLastMessage()).isTrue();
1074 }
aehlig03d55f32017-10-26 11:45:35 +02001075
1076 @Test
1077 public void testFinalEventsLate() throws Exception {
1078 // Verify that we correctly handle late events (i.e., events coming only after the
1079 // BuildCompleteEvent) that are sent to the streamer after the BuildCompleteEvent.
aehlig03d55f32017-10-26 11:45:35 +02001080 BuildEvent startEvent =
1081 new GenericBuildEvent(
1082 testId("Initial"),
1083 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1084 BuildEventId lateId = testId("late event");
1085 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
1086
1087 streamer.buildEvent(startEvent);
1088 streamer.buildEvent(finishedEvent);
1089 assertThat(streamer.isClosed()).isFalse();
1090 streamer.buildEvent(new GenericBuildEvent(lateId, ImmutableSet.of()));
1091 assertThat(streamer.isClosed()).isTrue();
1092
1093 List<BuildEvent> eventsSeen = transport.getEvents();
1094 assertThat(eventsSeen).hasSize(4);
1095 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
1096 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
1097 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1098 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
1099 }
1100
1101 @Test
1102 public void testFinalEventsEarly() throws Exception {
1103 // Verify that we correctly handle late events (i.e., events coming only after the
1104 // BuildCompleteEvent) that are sent to the streamer before the BuildCompleteEvent,
1105 // but with an order constraint to come afterwards.
aehlig03d55f32017-10-26 11:45:35 +02001106 BuildEvent startEvent =
1107 new GenericBuildEvent(
1108 testId("Initial"),
1109 ImmutableSet.of(ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1110 BuildEventId lateId = testId("late event");
1111 BuildEvent finishedEvent = new BuildCompleteEvent(new BuildResult(0), ImmutableList.of(lateId));
1112
1113 streamer.buildEvent(startEvent);
1114 streamer.buildEvent(
1115 new GenericOrderEvent(
1116 lateId, ImmutableSet.of(), ImmutableList.of(BuildEventId.buildFinished())));
1117 streamer.buildEvent(finishedEvent);
1118 assertThat(streamer.isClosed()).isTrue();
1119
1120 List<BuildEvent> eventsSeen = transport.getEvents();
1121 assertThat(eventsSeen).hasSize(4);
1122 assertThat(eventsSeen.get(0).getEventId()).isEqualTo(startEvent.getEventId());
1123 assertThat(eventsSeen.get(1).getEventId()).isEqualTo(BuildEventId.buildFinished());
1124 assertThat(ImmutableSet.of(eventsSeen.get(2).getEventId(), eventsSeen.get(3).getEventId()))
1125 .isEqualTo(ImmutableSet.of(lateId, ProgressEvent.INITIAL_PROGRESS_UPDATE));
1126 }
ruperts76de73b2018-03-02 16:10:43 -08001127
1128 @Test
1129 public void testSuccessfulActionsAreNotPublishedByDefault() {
1130 EventBusHandler handler = new EventBusHandler();
1131 eventBus.register(handler);
1132
ruperts76de73b2018-03-02 16:10:43 -08001133 ActionExecutedEvent failedActionExecutedEvent =
1134 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -07001135 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -08001136 new ActionsTestUtil.NullAction(),
1137 new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
tomlud56a8062018-08-01 13:20:41 -07001138 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -08001139 /* stdout= */ null,
1140 /* stderr= */ null,
1141 ErrorTiming.BEFORE_EXECUTION);
1142
1143 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1144 streamer.buildEvent(failedActionExecutedEvent);
1145
1146 List<BuildEvent> transportedEvents = transport.getEvents();
1147
1148 assertThat(transportedEvents).doesNotContain(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1149 assertThat(transportedEvents).contains(failedActionExecutedEvent);
1150 }
1151
1152 @Test
1153 public void testSuccessfulActionsCanBePublished() {
1154 EventBusHandler handler = new EventBusHandler();
1155 eventBus.register(handler);
1156
1157 BuildEventStreamOptions options = new BuildEventStreamOptions();
1158 options.publishAllActions = true;
1159
ruperts76de73b2018-03-02 16:10:43 -08001160 BuildEventStreamer streamer =
lpino2bf89062019-02-21 03:24:49 -08001161 new BuildEventStreamer.Builder()
1162 .artifactGroupNamer(artifactGroupNamer)
1163 .besStreamOptions(options)
lpino2bf89062019-02-21 03:24:49 -08001164 .buildEventTransports(ImmutableSet.of(transport))
1165 .build();
ruperts76de73b2018-03-02 16:10:43 -08001166
1167 ActionExecutedEvent failedActionExecutedEvent =
1168 new ActionExecutedEvent(
ulfjack5f312dd2018-10-02 04:58:53 -07001169 ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
ruperts76de73b2018-03-02 16:10:43 -08001170 new ActionsTestUtil.NullAction(),
1171 new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
tomlud56a8062018-08-01 13:20:41 -07001172 ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
ruperts76de73b2018-03-02 16:10:43 -08001173 /* stdout= */ null,
1174 /* stderr= */ null,
1175 ErrorTiming.BEFORE_EXECUTION);
1176
1177 streamer.buildEvent(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1178 streamer.buildEvent(failedActionExecutedEvent);
1179
1180 List<BuildEvent> transportedEvents = transport.getEvents();
1181
1182 assertThat(transportedEvents).contains(SUCCESSFUL_ACTION_EXECUTED_EVENT);
1183 assertThat(transportedEvents).contains(failedActionExecutedEvent);
1184 }
Googlerd990a0a2019-05-13 16:46:42 -07001185
1186 @Test
1187 public void testBuildIncomplete() {
1188 BuildEventId buildEventId = testId("abort_expected");
1189 BuildEvent startEvent =
1190 new GenericBuildEvent(
1191 BuildEventId.buildStartedId(),
1192 ImmutableSet.of(
1193 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1194 BuildCompleteEvent buildCompleteEvent =
1195 buildCompleteEvent(ExitCode.BUILD_FAILURE, true, null, false);
1196
1197 streamer.buildEvent(startEvent);
1198 streamer.buildEvent(buildCompleteEvent);
1199 streamer.close();
1200
1201 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1202 assertThat(aborted).isNotNull();
1203 assertThat(aborted.hasAborted()).isNotNull();
1204 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INCOMPLETE);
1205 assertThat(aborted.getAborted().getDescription()).isEmpty();
1206 }
1207
1208 @Test
1209 public void testBuildCrash() {
1210 BuildEventId buildEventId = testId("abort_expected");
1211 BuildEvent startEvent =
1212 new GenericBuildEvent(
1213 BuildEventId.buildStartedId(),
1214 ImmutableSet.of(
1215 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1216 BuildCompleteEvent buildCompleteEvent =
1217 buildCompleteEvent(ExitCode.BUILD_FAILURE, true, new RuntimeException(), false);
1218
1219 streamer.buildEvent(startEvent);
1220 streamer.buildEvent(buildCompleteEvent);
1221 streamer.close();
1222
1223 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1224 assertThat(aborted).isNotNull();
1225 assertThat(aborted.hasAborted()).isNotNull();
1226 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1227 assertThat(aborted.getAborted().getDescription()).isEmpty();
1228 }
1229
1230 @Test
1231 public void testBuildCatastrophe() {
1232 BuildEventId buildEventId = testId("abort_expected");
1233 BuildEvent startEvent =
1234 new GenericBuildEvent(
1235 BuildEventId.buildStartedId(),
1236 ImmutableSet.of(
1237 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1238 BuildCompleteEvent buildCompleteEvent =
1239 buildCompleteEvent(ExitCode.BUILD_FAILURE, true, null, true);
1240
1241 streamer.buildEvent(startEvent);
1242 streamer.buildEvent(buildCompleteEvent);
1243 streamer.close();
1244
1245 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1246 assertThat(aborted).isNotNull();
1247 assertThat(aborted.hasAborted()).isNotNull();
1248 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1249 assertThat(aborted.getAborted().getDescription()).isEmpty();
1250 }
1251
1252 @Test
1253 public void testStreamAbortedWithTimeout() {
1254 BuildEventId buildEventId = testId("abort_expected");
1255 BuildEvent startEvent =
1256 new GenericBuildEvent(
1257 BuildEventId.buildStartedId(),
1258 ImmutableSet.of(
1259 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1260
1261 streamer.buildEvent(startEvent);
1262 streamer.close(AbortReason.TIME_OUT);
1263
1264 BuildEventStreamProtos.BuildEvent aborted0 = getBepEvent(buildEventId);
1265 assertThat(aborted0).isNotNull();
1266 assertThat(aborted0.hasAborted()).isNotNull();
1267 assertThat(aborted0.getAborted().getReason()).isEqualTo(AbortReason.TIME_OUT);
1268 assertThat(aborted0.getAborted().getDescription()).isEmpty();
1269
1270 BuildEventStreamProtos.BuildEvent aborted1 = getBepEvent(BuildEventId.buildFinished());
1271 assertThat(aborted1).isNotNull();
1272 assertThat(aborted1.hasAborted()).isNotNull();
1273 assertThat(aborted1.getAborted().getReason()).isEqualTo(AbortReason.TIME_OUT);
1274 assertThat(aborted1.getAborted().getDescription()).isEmpty();
1275 }
1276
1277 @Test
1278 public void testBuildFailureMultipleReasons() {
1279 BuildEventId buildEventId = testId("abort_expected");
1280 BuildEvent startEvent =
1281 new GenericBuildEvent(
1282 BuildEventId.buildStartedId(),
1283 ImmutableSet.of(
1284 buildEventId, ProgressEvent.INITIAL_PROGRESS_UPDATE, BuildEventId.buildFinished()));
1285 BuildCompleteEvent buildCompleteEvent =
1286 buildCompleteEvent(ExitCode.BUILD_FAILURE, false, new RuntimeException(), false);
1287
1288 streamer.buildEvent(startEvent);
1289 streamer.noAnalyze(new NoAnalyzeEvent());
1290 streamer.buildEvent(buildCompleteEvent);
1291 streamer.close();
1292
1293 BuildEventStreamProtos.BuildEvent aborted = getBepEvent(buildEventId);
1294 assertThat(aborted).isNotNull();
1295 assertThat(aborted.hasAborted()).isNotNull();
1296 assertThat(aborted.getAborted().getReason()).isEqualTo(AbortReason.INTERNAL);
1297 assertThat(aborted.getAborted().getDescription())
1298 .isEqualTo("Multiple abort reasons reported: [NO_ANALYZE, INTERNAL]");
1299 }
1300
1301 @Nullable
1302 private BuildEventStreamProtos.BuildEvent getBepEvent(BuildEventId buildEventId) {
1303 return transport.getEventProtos().stream()
1304 .filter(e -> e.getId().equals(buildEventId.asStreamProto()))
1305 .findFirst()
1306 .orElse(null);
1307 }
1308
1309 private BuildCompleteEvent buildCompleteEvent(
1310 ExitCode exitCode, boolean stopOnFailure, Throwable crash, boolean catastrophe) {
1311 BuildResult result = new BuildResult(0);
1312 result.setExitCondition(exitCode);
1313 result.setStopOnFirstFailure(stopOnFailure);
1314 if (catastrophe) {
1315 result.setCatastrophe();
1316 }
1317 if (crash != null) {
1318 result.setUnhandledThrowable(crash);
1319 }
1320 return new BuildCompleteEvent(result);
1321 }
Klaus Aehlig17325a12016-09-30 15:45:27 +00001322}